feat: استيراد كود سيرو إلى تريبز (سيرو @ecfe7568) — بلا تعديل

قرار المالك 2026-07-27: باك إند سيرو PHP هو المعتمد، وتطبيقاته المجرّبة
ميدانياً تحل محل إعادة البناء المؤرشفة. سيرو نفسه لم يُمسّ.

الخريطة:
  backend · payment_server · loction_server · ride_server ·
  passenger_server · docker · dashboard · stress_test  → الجذر
  siro_rider  → apps/rider          siro_driver  → apps/driver
  siro_admin  → dashboards/admin    siro_service → dashboards/service
  android_bot → apps/android_bot    socialBot    → apps/socialBot

نُسخ المتعقَّب في git سيرو فقط عبر `git archive` (3,198 ملفاً / ~169 م.ب)
لا `cp -r` — فاستُثنيت مخلفات البناء تلقائياً. بلا أي تعديل محتوى عمداً:
كل ما يلي يصير فرقاً مقروءاً مقابل المصدر.

لم يُستورد وسببه: siromove.com (الموقع التسويقي يبقى marketing/ في تريبز،
سيرو فيه 8 ملفات) · docs و planning (تريبز له docs/ الخاص) · deploy.sh
(ليس نشراً على سيرفر بل `git add . && git push origin --all` — فخّ في
مستودع آخر) · transit_dashboard (بانتظار قرار مصير backend-transit و
dashboards/transit-web).

⚠️ لا يبني بعد — ثلاثة نواقص متوقعة ومقصودة:
1. `.env` و `lib/env/env.g.dart` غير متعقَّبين في سيرو (أسرار لكل مستأجر):
   كل تطبيق فلاتر يحتاج .env خاصاً ثم توليد env.g.dart بـ build_runner.
2. إعدادات Firebase (9 ملفات google-services.json و GoogleService-Info.plist)
   يستبعدها .gitignore تريبز — ولكل مستأجر مشروع Firebase خاص أصلاً.
3. apps/driver في سيرو يشير إلى `../../Intaleq/packages/get` خارج المستودع →
   يجب ضمّ الحزم داخله أسوة بـ apps/rider.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Hamza-Ayed
2026-07-27 05:14:13 +03:00
co-authored by Claude Opus 5
parent 9909d9b4c1
commit 4d8414c96b
3198 changed files with 766859 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
class MonthlyDataModel {
final int year;
final int month;
final int day;
final int ridesCount;
MonthlyDataModel({
required this.year,
required this.month,
required this.day,
required this.ridesCount,
});
factory MonthlyDataModel.fromJson(Map<String, dynamic> json) =>
MonthlyDataModel(
year: json['year'] as int,
month: json['month'] as int,
day: json['day'] as int,
ridesCount: json['rides_count'] as int,
);
}
+79
View File
@@ -0,0 +1,79 @@
class Passenger {
String id;
String phone;
String email;
String gender;
String status;
String birthdate;
String site;
String firstName;
String lastName;
String sosPhone;
String education;
String employmentType;
String maritalStatus;
String createdAt;
String updatedAt;
int countPassenger;
int countFeedback;
double ratingPassenger;
int countDriverRate;
int countPassengerCancel;
double passengerAverageRating;
int countPassengerRate;
int countPassengerRide;
Passenger({
required this.id,
required this.phone,
required this.email,
required this.gender,
required this.status,
required this.birthdate,
required this.site,
required this.firstName,
required this.lastName,
required this.sosPhone,
required this.education,
required this.employmentType,
required this.maritalStatus,
required this.createdAt,
required this.updatedAt,
required this.countPassenger,
required this.countFeedback,
required this.ratingPassenger,
required this.countDriverRate,
required this.countPassengerCancel,
required this.passengerAverageRating,
required this.countPassengerRate,
required this.countPassengerRide,
});
factory Passenger.fromJson(Map<String, dynamic> json) {
return Passenger(
id: json['id'],
phone: json['phone'],
email: json['email'],
gender: json['gender'],
status: json['status'],
birthdate: json['birthdate'],
site: json['site'],
firstName: json['first_name'],
lastName: json['last_name'],
sosPhone: json['sosPhone'],
education: json['education'],
employmentType: json['employmentType'],
maritalStatus: json['maritalStatus'],
createdAt: json['created_at'],
updatedAt: json['updated_at'],
countPassenger: json['countPassenger'],
countFeedback: json['countFeedback'],
ratingPassenger: json['ratingPassenger'].toDouble(),
countDriverRate: json['countDriverRate'],
countPassengerCancel: json['countPassengerCancel'],
passengerAverageRating: json['passengerAverageRating'].toDouble(),
countPassengerRate: json['countPassengerRate'],
countPassengerRide: json['countPassengerRide'],
);
}
}
@@ -0,0 +1,43 @@
class MonthlyDataModel {
int day;
int totalDuration;
MonthlyDataModel({required this.day, required this.totalDuration});
factory MonthlyDataModel.fromJson(Map<String, dynamic> json) =>
MonthlyDataModel(
day: int.parse(json['day'].toString().split('-')[2]),
totalDuration:
int.parse(json['total_duration'].toString().split(':')[0]));
}
class MonthlyRideModel {
int day;
int countRide;
int totalCount;
MonthlyRideModel(
{required this.day, required this.countRide, required this.totalCount});
factory MonthlyRideModel.fromJson(Map<String, dynamic> json) =>
MonthlyRideModel(
day: int.parse(json['day'].toString().split('-')[2]),
countRide: int.parse(json['countRide'].toString()),
totalCount: int.parse(json['totalCount'].toString()),
);
}
class MonthlyPriceDriverModel {
int day;
// int price;
double pricePerDay;
MonthlyPriceDriverModel({required this.day, required this.pricePerDay});
factory MonthlyPriceDriverModel.fromJson(Map<String, dynamic> json) =>
MonthlyPriceDriverModel(
day: int.parse(json['day'].toString().split('-')[2]),
// price: int.parse(json['price'].toString()),
pricePerDay: double.parse(json['pricePerDay'].toString()),
);
}
+34
View File
@@ -0,0 +1,34 @@
class CarLocationModel {
String id;
String driverId;
double latitude;
double heading;
double speed;
double longitude;
DateTime createdAt;
DateTime updatedAt;
CarLocationModel({
required this.id,
required this.driverId,
required this.latitude,
required this.longitude,
required this.heading,
required this.speed,
required this.createdAt,
required this.updatedAt,
});
factory CarLocationModel.fromJson(Map<String, dynamic> json) {
return CarLocationModel(
id: json['id'],
driverId: json['driver_id'],
latitude: double.parse(json['latitude'].toString()),
longitude: double.parse(json['longitude'].toString()),
heading: double.parse(json['heading'].toString()),
speed: double.parse(json['speed'].toString()),
createdAt: DateTime.parse(json['created_at']),
updatedAt: DateTime.parse(json['updated_at']),
);
}
}
+30
View File
@@ -0,0 +1,30 @@
import 'package:get/get.dart';
List<OnBoardingModel> onBoardingList = [
OnBoardingModel(
title: 'Welcome to Siro!'.tr,
image: 'assets/images/on1.png',
body:
'Siro is the ride-hailing app that is safe, reliable, and accessible.'
.tr,
),
OnBoardingModel(
title: 'Get to your destination quickly and easily.'.tr,
image: 'assets/images/on2.png',
body: 'With Siro, you can get a ride to your destination in minutes.'.tr,
),
OnBoardingModel(
title: 'Enjoy a safe and comfortable ride.'.tr,
image: 'assets/images/on3.png',
body:
'Siro is committed to safety, and all of our captains are carefully screened and background checked.'
.tr,
),
];
class OnBoardingModel {
final String? title;
final String? image;
final String? body;
OnBoardingModel({this.body, this.title, this.image});
}
+206
View File
@@ -0,0 +1,206 @@
// lib/models/model/order_data.dart
import 'package:get/get.dart';
class OrderData {
final String customerName;
final String customerToken;
final double tripDistanceKm; // The total trip distance in kilometers
final String price;
final String startLocationAddress;
final String endLocationAddress;
final double
distanceToPassengerKm; // The distance to the passenger in kilometers
final int tripDurationMinutes; // Total trip duration in minutes (rounded up)
final int
durationToPassengerMinutes; // Duration to reach the passenger in minutes (rounded up)
final String rideType;
final String orderId;
final String passengerId;
final String passengerRate;
final String? rawStartCoordinates;
final String? rawEndCoordinates;
// 🆕 "أرباحك أعلى" — الفرق الإيجابي بأجرة السائق مقارنة بالمنافس (إن وُجد)
final double? driverEarningsExtra;
final String? driverEarningsCurrency;
OrderData({
required this.customerName,
required this.customerToken,
required this.tripDistanceKm,
required this.price,
required this.startLocationAddress,
required this.endLocationAddress,
required this.distanceToPassengerKm,
required this.tripDurationMinutes,
required this.durationToPassengerMinutes,
required this.rideType,
required this.orderId,
required this.passengerId,
required this.passengerRate,
this.rawStartCoordinates,
this.rawEndCoordinates,
this.driverEarningsExtra,
this.driverEarningsCurrency,
});
// --- NEW: Factory constructor to create an instance from a Map ---
// This is the missing method that was causing the error.
factory OrderData.fromMap(Map<String, dynamic> map) {
return OrderData(
// For strings, provide a default value in case the map key is null
customerName: map['customerName']?.toString() ?? 'Unknown Customer',
customerToken: map['customerToken']?.toString() ?? 'Unknown token',
// For numbers, cast from 'num' to handle both int and double, with a default value
tripDistanceKm: (map['tripDistanceKm'] as num?)?.toDouble() ?? 0.0,
price: map['price']?.toString() ?? '0',
startLocationAddress:
map['startLocationAddress']?.toString() ?? 'Unknown Address',
endLocationAddress:
map['endLocationAddress']?.toString() ?? 'Unknown Address',
distanceToPassengerKm:
(map['distanceToPassengerKm'] as num?)?.toDouble() ?? 0.0,
tripDurationMinutes: (map['tripDurationMinutes'] as num?)?.toInt() ?? 0,
durationToPassengerMinutes:
(map['durationToPassengerMinutes'] as num?)?.toInt() ?? 0,
rideType: map['rideType']?.toString() ?? 'Unknown',
orderId: map['orderId']?.toString() ?? 'N/A',
passengerId: map['passengerId']?.toString() ?? 'N/A',
passengerRate: map['passengerRate']?.toString() ?? 'N/A',
// For nullable strings, direct access is fine as it returns null if the key doesn't exist
rawStartCoordinates: map['rawStartCoordinates'],
rawEndCoordinates: map['rawEndCoordinates'],
driverEarningsExtra: (map['driverEarningsExtra'] as num?)?.toDouble(),
driverEarningsCurrency: map['driverEarningsCurrency']?.toString(),
);
}
// A helper function to convert seconds to rounded-up minutes
static int _secondsToRoundedUpMinutes(String secondsString) {
final seconds = double.tryParse(secondsString) ?? 0.0;
if (seconds <= 0) return 0;
return (seconds / 60)
.ceil(); // .ceil() rounds up (e.g., 0.1 minutes becomes 1 minute)
}
// Your existing factory for creating an instance from a List
factory OrderData.fromList(List<dynamic> list) {
double distanceToPassengerMeters =
list.length > 12 ? (double.tryParse(list[12].toString()) ?? 0.0) : 0.0;
return OrderData(
customerName: list.length > 8 ? list[8].toString() : 'Unknown Customer',
customerToken: list.length > 9 ? list[9].toString() : 'Unknown token',
tripDistanceKm:
list.length > 5 ? (double.tryParse(list[5].toString()) ?? 0.0) : 0.0,
price: list.length > 2 ? list[2].toString().split('.')[0] : '0',
startLocationAddress:
list.length > 29 ? list[29].toString() : 'Unknown Address',
endLocationAddress:
list.length > 30 ? list[30].toString() : 'Unknown Address',
distanceToPassengerKm:
distanceToPassengerMeters / 1000.0, // Convert meters to kilometers
tripDurationMinutes:
list.length > 4 ? _secondsToRoundedUpMinutes(list[4].toString()) : 0,
durationToPassengerMinutes: list.length > 15
? _secondsToRoundedUpMinutes(list[15].toString())
: 0,
rideType:
list.length > 31 ? _getRideType(list[31].toString()) : 'Unknown',
orderId: list.length > 16 ? list[16].toString() : 'N/A',
passengerId: list.length > 7 ? list[7].toString() : 'N/A',
passengerRate: list.length > 33 ? list[33].toString() : 'N/A',
rawStartCoordinates: list.isNotEmpty ? list[0].toString() : null,
rawEndCoordinates: list.length > 1 ? list[1].toString() : null,
// 🆕 Index 35/36: "أرباحك أعلى"
driverEarningsExtra: list.length > 35 && list[35].toString().isNotEmpty
? double.tryParse(list[35].toString())
: null,
driverEarningsCurrency:
list.length > 36 && list[36].toString().isNotEmpty
? list[36].toString()
: null,
);
}
static String _getRideType(String type) {
switch (type) {
case 'Comfort':
return 'Comfort ❄️'.tr;
case 'Lady':
return 'Lady 👩'.tr;
case 'Speed':
return 'Speed 🔻'.tr;
case 'Mashwari':
return 'Mashwari'.tr;
case 'Rayeh Gai':
return 'Rayeh Gai'.tr;
default:
return type.tr;
}
}
// Getter to parse start coordinates
Map<String, double?>? get startCoordinates {
if (rawStartCoordinates == null) return null;
final parts = rawStartCoordinates!.split(',');
if (parts.length == 2) {
return {
'lat': double.tryParse(parts[0].trim()),
'lng': double.tryParse(parts[1].trim())
};
}
return null;
}
// Getter to parse end coordinates
Map<String, double?>? get endCoordinates {
if (rawEndCoordinates == null) return null;
final parts = rawEndCoordinates!.split(',');
if (parts.length == 2) {
return {
'lat': double.tryParse(parts[0].trim()),
'lng': double.tryParse(parts[1].trim())
};
}
return null;
}
// Your existing method to convert the object TO a Map.
// This is used to pass the data from the overlay to the main app.
Map<String, dynamic> toMap() {
return {
'customerName': customerName,
'tripDistanceKm': tripDistanceKm,
'price': price,
'startLocationAddress': startLocationAddress,
'endLocationAddress': endLocationAddress,
'distanceToPassengerKm': distanceToPassengerKm,
'tripDurationMinutes': tripDurationMinutes,
'durationToPassengerMinutes': durationToPassengerMinutes,
'rideType': rideType,
'orderId': orderId,
'passengerId': passengerId,
'passengerRate': passengerRate,
'rawStartCoordinates': rawStartCoordinates,
'rawEndCoordinates': rawEndCoordinates,
'driverEarningsExtra': driverEarningsExtra,
'driverEarningsCurrency': driverEarningsCurrency,
};
}
}