fix(apps): إصلاحات من أول تجربة حقيقية على الجهاز
## تعذّر حساب الأجرة — الخطأ في التطبيق لا في جدول الكازان الخادم يبذر التعرفة بـ city: 'default' (tenants.service.ts:156) ويستعمل dto.city ?? 'default' عند إنشاء الرحلة، وكنت أرسل city: '' فيرجّع 404 «No active tariff for /economy». تحقّق حيّ: city='default' → total 1.55 JOD ✅ city='' → 404 ❌ city='amman' → 404 ❌ لا تغيير مطلوب على السيرفر. أُضيف AppConfig.defaultCity موثّقاً بالسبب. ## التسعير مرة واحدة لكل الأنواع كان نداء شبكة عند كل ضغطة نوع. صار _priceAll يسعّر كل الأنواع بالتوازي بعد اكتمال المسار — المسافة والمدة ثابتتان والفرق في التعرفة وحدها. الراكب يرى سعر الاقتصادي والمريح معاً تحت كل خيار ويقارن بنظرة، وتبديل النوع بلا نداء. ## الكاميرا لا تتبع الموقع سببان: الموقع يصل قبل إنشاء الخريطة فيضيع التحريك، ولا فحص للإذن/الخدمة قبل getCurrentPosition فيُبتلع الخطأ صامتاً. - _onCreated يلحق بما فات عند جهوز الخريطة - LocationService.ensureReady يفحص الخدمة والإذن أولاً - didChangeAppLifecycleState يعيد المحاولة عند العودة من إعدادات النظام - حالة noLocation تُعرض للمستخدم مع زر إعادة بدل خريطة صامتة ## الخريطة والتنقّل - إطار المسار من حدوده الفعلية مع حشوة سفلية بمقدار ما تغطّيه الورقة - علامتا البداية والنهاية دائرتان ملوّنتان تطابقان ألوان الخط الزمني - زر رجوع في ورقة التأكيد + زر إعادة حساب عند فشل التسعيرة: كان المستخدم يعلق في الشاشة بلا مخرج ## المحفظة — على أي أساس يُشحن POST /wallet/topup شحنٌ تجريبي بلا مزوّد دفع خلفه (الخادم نفسه يصفه كذلك). أُضيف PaymentChannel مشتقّاً من countryPack المستأجر لا من لغة الجهاز: jo → CliQ · sy → سيرياتيل/MTN/شام كاش · eg → PayMob. ويُعرض تنبيه صريح بأن الشحن بلا تحصيل فعلي — إخفاؤه يجعل المستخدم يظنّ أنه دفع. وسحب السائق صار يستعمل القناة المختارة بدل 'cliq' المكتوبة في الكود. flutter analyze نظيف في التطبيقين. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
29f375b122
commit
8976821a93
@@ -4,6 +4,9 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import '../../../../core/config.dart';
|
||||
import '../../../../core/design/tokens.dart';
|
||||
import '../../../../core/design/tripz_colors.dart';
|
||||
import '../../../../core/payments/payment_channels.dart';
|
||||
import '../../../../core/tenant/tenant_cubit.dart';
|
||||
import '../../../../core/ui/channel_picker.dart';
|
||||
import '../../../../core/l10n/l10n.dart';
|
||||
import '../../../../core/ui/tripz_button.dart';
|
||||
import '../../../../core/ui/tripz_otp_field.dart';
|
||||
@@ -24,6 +27,7 @@ class PayoutSheet extends StatefulWidget {
|
||||
class _PayoutSheetState extends State<PayoutSheet> {
|
||||
final _amount = TextEditingController();
|
||||
final _code = TextEditingController();
|
||||
PaymentChannel? _channel;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
@@ -75,7 +79,7 @@ class _PayoutSheetState extends State<PayoutSheet> {
|
||||
hasError: state.failure == PayoutFailure.rejected,
|
||||
onCompleted: cubit.confirm,
|
||||
)
|
||||
else
|
||||
else ...[
|
||||
TripzTextField(
|
||||
controller: _amount,
|
||||
label: l10n.payoutAmount,
|
||||
@@ -85,6 +89,22 @@ class _PayoutSheetState extends State<PayoutSheet> {
|
||||
decimal: true,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: Space.md),
|
||||
Text(l10n.payoutChannel, style: context.texts.titleSmall),
|
||||
const SizedBox(height: Space.xs),
|
||||
Builder(builder: (context) {
|
||||
// قنوات السحب من حزمة دولة المستأجر — والنقد ليس قناة سحب.
|
||||
final channels = PaymentChannel.payoutFor(
|
||||
context.watch<TenantCubit>().state.countryPack,
|
||||
);
|
||||
_channel ??= channels.isEmpty ? null : channels.first;
|
||||
return ChannelPicker(
|
||||
channels: channels,
|
||||
selected: _channel,
|
||||
onSelect: (c) => setState(() => _channel = c),
|
||||
);
|
||||
}),
|
||||
],
|
||||
if (state.failure != PayoutFailure.none) ...[
|
||||
const SizedBox(height: Space.sm),
|
||||
Text(
|
||||
@@ -107,8 +127,9 @@ class _PayoutSheetState extends State<PayoutSheet> {
|
||||
cubit.confirm(_code.text.trim());
|
||||
} else {
|
||||
final amount = num.tryParse(_amount.text.trim());
|
||||
if (amount != null) {
|
||||
cubit.request(amount: amount, channel: 'cliq');
|
||||
final channel = _channel;
|
||||
if (amount != null && channel != null) {
|
||||
cubit.request(amount: amount, channel: channel.wire);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user