feat(apps): الدراور على نمط سيرو — المكافآت والدعوات والمساعدة
جُرد دراور سيرو: 14 مدخلاً للراكب (map_menu_widget) و23 للسائق (drawer_captain). بُني ما له نقطة فعلية على NestJS، والباقي مذكور صراحةً. ## مبنيّ - **المكافآت** (features/rewards): GET /rewards/referrals و /rewards/coupons — كلاهما مُتحقَّق حيّاً. كود الدعوة يُنسخ ويُشارك، وعدّادات دعوتَهم/قيد التأكيد/مدفوعة. يقابل Promos + Invite Driver في سيرو - **شارك التطبيق · قيّم التطبيق · سياسة الخصوصية · تطبيق الطرف الآخر** — أفعال محليّة بلا نقطة خادم (share_plus + url_launcher) - **المساعدة** وُسّعت: أسئلة شائعة قابلة للطيّ · واتساب الدعم · **فحص توافق الجهاز** (نمط سيرو) يفحص ما يُعطّل التطبيق فعلاً: خدمة الموقع وإذنها وإذن الإشعارات — أسباب حقيقية لشكوى «التطبيق لا يعمل» - روابط المتجر والخصوصية والدعم صارت قيم بناء لكل مستأجر في BuildConfig ## غير مبنيّ — ولا نقطة خادم له الشكاوى (R3 في الباكلوج) · الإحصاءات · التحدّيات ولوحة المتصدّرين · مركز الصيانة · جدولي · التأمين الصحي (مؤجَّل بقرار المالك) · الطعام والمواصلات (خارج النطاق، docs/39 §1). بناء واجهة بلا خادم يعني شاشة تكذب على المستخدم. ## سجلّ الإشعارات سيرو يعرض قائمة إشعارات؛ الخادم يوفّر POST /notifications/token فقط بلا نقطة سرد. لم تُبنَ شاشة قائمة على فراغ. flutter analyze نظيف في التطبيقين. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
6a33cc7241
commit
ca766a2d4e
@@ -0,0 +1,65 @@
|
||||
import '../../../core/api/api_client.dart';
|
||||
|
||||
/// ملخّص الدعوات — شكل مُتحقَّق حيّاً: `{code, total, pending, paid}`.
|
||||
class ReferralSummary {
|
||||
const ReferralSummary({
|
||||
required this.code,
|
||||
required this.total,
|
||||
required this.pending,
|
||||
required this.paid,
|
||||
});
|
||||
|
||||
/// كود دعوتي الذي أشاركه.
|
||||
final String code;
|
||||
|
||||
final int total;
|
||||
final int pending;
|
||||
final int paid;
|
||||
|
||||
factory ReferralSummary.fromJson(Map<String, dynamic> json) =>
|
||||
ReferralSummary(
|
||||
code: json['code'] as String? ?? '',
|
||||
total: (json['total'] as num?)?.toInt() ?? 0,
|
||||
pending: (json['pending'] as num?)?.toInt() ?? 0,
|
||||
paid: (json['paid'] as num?)?.toInt() ?? 0,
|
||||
);
|
||||
}
|
||||
|
||||
class Coupon {
|
||||
const Coupon({
|
||||
required this.code,
|
||||
this.description = '',
|
||||
this.expiresAt,
|
||||
});
|
||||
|
||||
final String code;
|
||||
final String description;
|
||||
final DateTime? expiresAt;
|
||||
|
||||
factory Coupon.fromJson(Map<String, dynamic> json) => Coupon(
|
||||
code: json['code'] as String? ?? '',
|
||||
description: json['description'] as String? ??
|
||||
json['title'] as String? ??
|
||||
'',
|
||||
expiresAt: DateTime.tryParse(json['expires_at']?.toString() ?? ''),
|
||||
);
|
||||
}
|
||||
|
||||
class RewardsRepository {
|
||||
RewardsRepository(this._api);
|
||||
|
||||
final ApiClient _api;
|
||||
|
||||
Future<ReferralSummary> referrals() async {
|
||||
final res = await _api.get<Map<String, dynamic>>('/rewards/referrals');
|
||||
return ReferralSummary.fromJson(res);
|
||||
}
|
||||
|
||||
Future<List<Coupon>> coupons() async {
|
||||
final res = await _api.get<List<dynamic>>('/rewards/coupons');
|
||||
return res
|
||||
.whereType<Map<String, dynamic>>()
|
||||
.map(Coupon.fromJson)
|
||||
.toList(growable: false);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user