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:
co-authored by
Claude Opus 5
parent
9909d9b4c1
commit
4d8414c96b
@@ -0,0 +1,189 @@
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:siro_driver/constant/box_name.dart';
|
||||
import 'package:siro_driver/constant/links.dart';
|
||||
import 'package:siro_driver/controller/functions/crud.dart';
|
||||
import '../../main.dart';
|
||||
|
||||
// ════════════════════════════════════════════
|
||||
// نموذج الإحالة
|
||||
// ════════════════════════════════════════════
|
||||
|
||||
class ReferralRecord {
|
||||
final String id;
|
||||
final String name;
|
||||
final String phone;
|
||||
final String status; // 'registered', 'active', 'inactive'
|
||||
final String type; // 'driver', 'passenger'
|
||||
final String joinDate;
|
||||
final int tripCount;
|
||||
|
||||
ReferralRecord({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.phone,
|
||||
required this.status,
|
||||
required this.type,
|
||||
required this.joinDate,
|
||||
required this.tripCount,
|
||||
});
|
||||
|
||||
factory ReferralRecord.fromJson(Map<String, dynamic> json) {
|
||||
return ReferralRecord(
|
||||
id: json['id']?.toString() ?? '',
|
||||
name: json['name']?.toString() ?? json['nameArabic']?.toString() ?? '',
|
||||
phone: json['phone']?.toString() ?? '',
|
||||
status: json['status']?.toString() ?? 'registered',
|
||||
type: json['type']?.toString() ?? 'driver',
|
||||
joinDate: json['created_at']?.toString() ?? '',
|
||||
tripCount: int.tryParse(json['trip_count']?.toString() ?? '0') ?? 0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════
|
||||
// Controller
|
||||
// ════════════════════════════════════════════
|
||||
|
||||
class ReferralController extends GetxController {
|
||||
bool isLoading = false;
|
||||
List<ReferralRecord> driverReferrals = [];
|
||||
List<ReferralRecord> passengerReferrals = [];
|
||||
String referralCode = '';
|
||||
int totalDriverReferrals = 0;
|
||||
int totalPassengerReferrals = 0;
|
||||
int activeReferrals = 0;
|
||||
double totalRewardsEarned = 0;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
_generateReferralCode();
|
||||
fetchReferralData();
|
||||
}
|
||||
|
||||
void _generateReferralCode() {
|
||||
final driverId = box.read(BoxName.driverID)?.toString() ?? '';
|
||||
final name = box.read(BoxName.nameDriver)?.toString() ?? '';
|
||||
if (driverId.isNotEmpty) {
|
||||
// كود فريد: أول 3 حروف من الاسم + ID
|
||||
final prefix = name.length >= 3 ? name.substring(0, 3).toUpperCase() : name.toUpperCase();
|
||||
referralCode = '$prefix$driverId';
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> fetchReferralData() async {
|
||||
isLoading = true;
|
||||
update();
|
||||
|
||||
try {
|
||||
// 1. جلب دعوات السائقين
|
||||
var driverRes = await CRUD().get(
|
||||
link: AppLink.getInviteDriver,
|
||||
payload: {'driver_id': box.read(BoxName.driverID).toString()},
|
||||
);
|
||||
if (driverRes != null && driverRes != 'failure') {
|
||||
var data = jsonDecode(driverRes);
|
||||
if (data['message'] is List) {
|
||||
driverReferrals = (data['message'] as List)
|
||||
.map((e) => ReferralRecord.fromJson(e))
|
||||
.toList();
|
||||
totalDriverReferrals = driverReferrals.length;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. جلب دعوات الركاب
|
||||
var passengerRes = await CRUD().get(
|
||||
link: AppLink.getDriverInvitationToPassengers,
|
||||
payload: {'driver_id': box.read(BoxName.driverID).toString()},
|
||||
);
|
||||
if (passengerRes != null && passengerRes != 'failure') {
|
||||
var data = jsonDecode(passengerRes);
|
||||
if (data['message'] is List) {
|
||||
passengerReferrals = (data['message'] as List)
|
||||
.map((e) => ReferralRecord.fromJson(e))
|
||||
.toList();
|
||||
totalPassengerReferrals = passengerReferrals.length;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. جلب الإحصائيات الدقيقة للمكافآت
|
||||
var statsRes = await CRUD().get(
|
||||
link: AppLink.getReferralStats,
|
||||
payload: {'driver_id': box.read(BoxName.driverID).toString()},
|
||||
);
|
||||
if (statsRes != null && statsRes != 'failure') {
|
||||
var data = jsonDecode(statsRes);
|
||||
if (data['message'] is List && data['message'].isNotEmpty) {
|
||||
var stats = data['message'][0];
|
||||
totalRewardsEarned = double.tryParse(stats['totalRewards']?.toString() ?? '0') ?? 0;
|
||||
activeReferrals = (int.tryParse(stats['driverInvites']?.toString() ?? '0') ?? 0) +
|
||||
(int.tryParse(stats['passengerInvites']?.toString() ?? '0') ?? 0);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('❌ [Referral] Error: $e');
|
||||
}
|
||||
|
||||
isLoading = false;
|
||||
update();
|
||||
}
|
||||
|
||||
void copyCode() {
|
||||
Clipboard.setData(ClipboardData(text: referralCode));
|
||||
}
|
||||
|
||||
String get shareMessage {
|
||||
final appName = 'Siro';
|
||||
return 'Join $appName as a driver! Use my code: $referralCode\nDownload: https://siro.app/driver?ref=$referralCode';
|
||||
}
|
||||
|
||||
String get shareMessagePassenger {
|
||||
final appName = 'Siro';
|
||||
return 'Get a ride with $appName! Use my code: $referralCode for a discount.\nDownload: https://siro.app?ref=$referralCode';
|
||||
}
|
||||
|
||||
int get totalReferrals => totalDriverReferrals + totalPassengerReferrals;
|
||||
|
||||
// ═══════ إرسال دعوة سائق ═══════
|
||||
Future<bool> inviteDriver(String phone) async {
|
||||
try {
|
||||
var res = await CRUD().post(
|
||||
link: AppLink.addInviteDriver,
|
||||
payload: {
|
||||
'driver_id': box.read(BoxName.driverID).toString(),
|
||||
'phone': phone,
|
||||
},
|
||||
);
|
||||
if (res != null && res != 'failure') {
|
||||
await fetchReferralData();
|
||||
return true;
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('❌ [Referral] Invite driver error: $e');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ═══════ إرسال دعوة راكب ═══════
|
||||
Future<bool> invitePassenger(String phone) async {
|
||||
try {
|
||||
var res = await CRUD().post(
|
||||
link: AppLink.addInvitationPassenger,
|
||||
payload: {
|
||||
'driver_id': box.read(BoxName.driverID).toString(),
|
||||
'phone': phone,
|
||||
},
|
||||
);
|
||||
if (res != null && res != 'failure') {
|
||||
await fetchReferralData();
|
||||
return true;
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('❌ [Referral] Invite passenger error: $e');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user