chore: أرشفة تطبيقات ولوحات تريبز التي سيحلّ محلها كود سيرو

استكمال قرار 2026-07-27 (كوميت fff76c9 أرشف الباك إند):
  apps/rider          → apps/rider-archive-cubit
  apps/driver         → apps/driver-archive-cubit
  dashboards/admin-web    → dashboards/admin-web-archive
  dashboards/service-web  → dashboards/service-web-archive

إعادة تسمية بلا تعديل محتوى. rider/driver كانا إعادة بناء Cubit مبنية على
عقد NestJS المؤرشف. admin-web و service-web نموذجان بملف HTML واحد (164 و
128 سطراً) — يحلّ محلهما siro_admin و siro_service المكتملان.

يُحمل من المؤرشف ولا يُعاد اكتشافه: عقد map-saas المثبَّت بالتجربة في
apps/rider-archive-cubit/lib/core/api/ (x-api-key ترويسة، reverse مصفوفة،
route في points) ودرس مسار FCM.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Hamza-Ayed
2026-07-27 05:12:04 +03:00
co-authored by Claude Opus 5
parent fff76c949f
commit 9909d9b4c1
809 changed files with 0 additions and 0 deletions
@@ -0,0 +1,74 @@
import 'package:flutter/material.dart';
import '../../../../core/design/tokens.dart';
import '../../data/models/place_model.dart';
/// عنصر نتائج البحث عن مكان.
class PlaceTile extends StatelessWidget {
final PlaceModel place;
final VoidCallback? onTap;
final IconData? icon;
const PlaceTile({
super.key,
required this.place,
this.onTap,
this.icon,
});
@override
Widget build(BuildContext context) {
final cs = Theme.of(context).colorScheme;
final displayIcon = icon ?? Icons.location_on_outlined;
return InkWell(
onTap: onTap,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: T.pagePadding,
vertical: T.s12,
),
child: Row(
children: [
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: cs.surfaceContainerHighest,
shape: BoxShape.circle,
),
child: Icon(displayIcon, size: 20, color: cs.onSurfaceVariant),
),
const SizedBox(width: T.s12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
place.name,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontWeight: FontWeight.w500,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
if (place.address != null && place.address!.isNotEmpty) ...[
const SizedBox(height: 2),
Text(
place.address!,
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: cs.onSurfaceVariant,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
],
),
),
Icon(Icons.chevron_right_rounded, color: cs.onSurfaceVariant),
],
),
),
);
}
}
@@ -0,0 +1,116 @@
import 'package:flutter/material.dart';
import '../../../../core/l10n/app_localizations.dart';
import '../../../../core/design/tokens.dart';
import '../../data/models/quote_model.dart';
/// بطاقة فئة رحلة واحدة في قائمة الاختيار.
class RideClassCard extends StatelessWidget {
final QuoteClassModel quoteClass;
final bool selected;
final VoidCallback? onTap;
const RideClassCard({
super.key,
required this.quoteClass,
this.selected = false,
this.onTap,
});
@override
Widget build(BuildContext context) {
final cs = Theme.of(context).colorScheme;
final l10n = AppLocalizations.of(context)!;
return InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(T.r16),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: T.s16, vertical: T.s12),
decoration: BoxDecoration(
color: selected ? cs.primaryContainer.withValues(alpha: 0.2) : Colors.transparent,
borderRadius: BorderRadius.circular(T.r16),
border: Border.all(
color: selected ? cs.primary : cs.outlineVariant.withValues(alpha: 0.3),
width: selected ? 2 : 1,
),
),
child: Row(
children: [
// أيقونة المركبة
Container(
width: 56,
height: 56,
decoration: BoxDecoration(
color: selected ? cs.primary.withValues(alpha: 0.1) : cs.surfaceContainerHighest,
shape: BoxShape.circle,
),
child: Center(
child: Icon(
Icons.directions_car_filled_rounded,
color: selected ? cs.primary : cs.onSurfaceVariant,
size: 32,
),
),
),
const SizedBox(width: T.s16),
// اسم الفئة + السعة
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
quoteClass.name,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w700,
color: cs.onSurface,
),
),
const SizedBox(height: 2),
Row(
children: [
Icon(Icons.person_outline_rounded,
size: 14, color: cs.onSurfaceVariant),
const SizedBox(width: 4),
Text(
l10n.capacity(quoteClass.capacity),
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: cs.onSurfaceVariant,
fontWeight: FontWeight.w500,
),
),
],
),
],
),
),
// الوقت التقديري + السعر
Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'${quoteClass.price} ${quoteClass.currency}',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w800,
color: selected ? cs.primary : cs.onSurface,
),
),
const SizedBox(height: 2),
Text(
quoteClass.estimatedTimeText,
style: Theme.of(context).textTheme.labelSmall?.copyWith(
color: cs.onSurfaceVariant,
fontWeight: FontWeight.w600,
),
),
],
),
],
),
),
);
}
}
@@ -0,0 +1,126 @@
import 'package:flutter/material.dart';
import '../../../../core/l10n/app_localizations.dart';
import '../../../../core/design/tokens.dart';
/// طبقة البحث عن سائق — نبض + مؤقت + زر إلغاء.
class SearchingOverlay extends StatefulWidget {
final int elapsed;
final VoidCallback? onCancel;
const SearchingOverlay({
super.key,
required this.elapsed,
this.onCancel,
});
@override
State<SearchingOverlay> createState() => _SearchingOverlayState();
}
class _SearchingOverlayState extends State<SearchingOverlay>
with SingleTickerProviderStateMixin {
late AnimationController _pulseController;
late Animation<double> _pulseAnimation;
@override
void initState() {
super.initState();
_pulseController = AnimationController(
vsync: this,
duration: const Duration(seconds: 2),
)..repeat(reverse: true);
_pulseAnimation = Tween<double>(begin: 0.8, end: 1.2).animate(
CurvedAnimation(parent: _pulseController, curve: Curves.easeInOut),
);
}
@override
void dispose() {
_pulseController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
final cs = Theme.of(context).colorScheme;
final minutes = widget.elapsed ~/ 60;
final seconds = widget.elapsed % 60;
final timeStr = '${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}';
return Material(
color: Colors.black54,
child: Center(
child: Container(
margin: const EdgeInsets.all(T.pagePadding * 2),
padding: const EdgeInsets.all(T.pagePadding * 1.5),
decoration: BoxDecoration(
color: cs.surface,
borderRadius: BorderRadius.circular(T.r16),
boxShadow: [T.shadowLg],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// نبض البحث
ScaleTransition(
scale: _pulseAnimation,
child: Container(
width: 80,
height: 80,
decoration: BoxDecoration(
color: cs.primaryContainer,
shape: BoxShape.circle,
),
child: Icon(
Icons.directions_car_filled_rounded,
size: 40,
color: cs.onPrimaryContainer,
),
),
),
const SizedBox(height: T.s16),
// نص البحث
Text(
l10n.searchingDriver,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
),
textAlign: TextAlign.center,
),
const SizedBox(height: T.s8),
// المؤقت
Text(
timeStr,
style: Theme.of(context).textTheme.headlineMedium?.copyWith(
color: cs.primary,
fontWeight: FontWeight.w700,
fontFeatures: const [FontFeature.tabularFigures()],
),
),
const SizedBox(height: T.s20),
// زر الإلغاء
SizedBox(
width: double.infinity,
child: OutlinedButton(
onPressed: widget.onCancel,
style: OutlinedButton.styleFrom(
foregroundColor: cs.error,
side: BorderSide(color: cs.error),
),
child: Text(l10n.cancelSearch),
),
),
],
),
),
),
);
}
}