Files
urukprize/mobile/lib/features/membership/presentation/digital_card_screen.dart
T

432 lines
16 KiB
Dart

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:qr_flutter/qr_flutter.dart';
import '../../../core/theme/app_theme.dart';
import '../../admin/presentation/in_app_admin_modal.dart';
import '../../subscription/presentation/subscription_checkout_screen.dart';
import '../cubit/membership_cubit.dart';
import '../cubit/membership_state.dart';
class DigitalCardScreen extends StatefulWidget {
const DigitalCardScreen({super.key});
@override
State<DigitalCardScreen> createState() => _DigitalCardScreenState();
}
class _DigitalCardScreenState extends State<DigitalCardScreen> {
@override
void initState() {
super.initState();
context.read<MembershipCubit>().fetchCardDetails();
}
void _showDynamicQrModal(BuildContext context, String token, int? validUntil) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (modalCtx) => _DynamicQrSheet(
token: token,
validUntil: validUntil,
onRefresh: () => context.read<MembershipCubit>().refreshDynamicQr(),
),
);
}
@override
Widget build(BuildContext context) {
return Directionality(
textDirection: TextDirection.rtl,
child: Scaffold(
appBar: AppBar(
title: const Text('بطاقة العضوية الذكية'),
actions: [
IconButton(
icon: const Icon(Icons.refresh, color: AppTheme.goldAccent),
onPressed: () => context.read<MembershipCubit>().fetchCardDetails(),
),
],
),
body: BlocBuilder<MembershipCubit, MembershipState>(
builder: (context, state) {
if (state is MembershipLoading) {
return const Center(child: CircularProgressIndicator(color: AppTheme.goldAccent));
}
if (state is MembershipNotSubscribed) {
return _buildNotSubscribedView(context);
}
if (state is MembershipLoaded) {
final card = state.cardData;
final isActive = state.isActive;
return SingleChildScrollView(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Digital Executive Card Widget
_buildExecutiveCard(context, card, isActive),
const SizedBox(height: 24),
// Actions
if (isActive)
ElevatedButton.icon(
icon: const Icon(Icons.qr_code_2, size: 28),
label: const Text('إبراز رمز التحقق في المستشفى / الفندق'),
style: ElevatedButton.styleFrom(
backgroundColor: AppTheme.goldAccent,
foregroundColor: AppTheme.primaryDark,
padding: const EdgeInsets.symmetric(vertical: 16),
),
onPressed: () async {
final cubit = context.read<MembershipCubit>();
await cubit.refreshDynamicQr();
if (!mounted) return;
final updated = cubit.state;
if (updated is MembershipLoaded && updated.dynamicQrToken != null) {
_showDynamicQrModal(context, updated.dynamicQrToken!, updated.qrValidUntil);
}
},
)
else
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.amber.withOpacity(0.12),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.amber.withOpacity(0.4)),
),
child: const Row(
children: [
Icon(Icons.info_outline, color: Colors.amber),
SizedBox(width: 12),
Expanded(
child: Text(
'طلب العضوية قيد التحقق المالي. سيتم تفعيل البطاقة ورمز QR فور التأكد من الحوالة.',
style: TextStyle(color: Colors.white70, fontSize: 13),
),
),
],
),
),
const SizedBox(height: 24),
// Benefits Summary List
_buildBenefitsSection(),
],
),
);
}
return Center(
child: ElevatedButton(
onPressed: () => context.read<MembershipCubit>().fetchCardDetails(),
child: const Text('إعادة المحاولة'),
),
);
},
),
),
);
}
Widget _buildExecutiveCard(BuildContext context, Map<String, dynamic> card, bool isActive) {
return GestureDetector(
// Secret Long-Press (5 seconds) to trigger Hidden Admin Modal for Dr. Thamer!
onLongPress: () {
InAppAdminModal.show(context);
},
child: Container(
height: 220,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
gradient: const LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [Color(0xFF1E293B), Color(0xFF0F172A), Color(0xFF020617)],
),
border: Border.all(color: AppTheme.goldAccent.withOpacity(0.6), width: 1.5),
boxShadow: [
BoxShadow(
color: AppTheme.goldAccent.withOpacity(0.15),
blurRadius: 25,
spreadRadius: 2,
offset: const Offset(0, 10),
),
],
),
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Row(
children: [
Icon(Icons.workspace_premium, color: AppTheme.goldAccent, size: 30),
SizedBox(width: 8),
Text(
'جائزة أوروك الدولية',
style: TextStyle(
color: AppTheme.goldLight,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
],
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
decoration: BoxDecoration(
color: isActive ? AppTheme.emeraldGreen.withOpacity(0.2) : Colors.amber.withOpacity(0.2),
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: isActive ? AppTheme.emeraldGreen : Colors.amber,
width: 1,
),
),
child: Text(
isActive ? 'عضوية معتمدة' : 'قيد التدقيق',
style: TextStyle(
color: isActive ? AppTheme.emeraldGreen : Colors.amber,
fontSize: 11,
fontWeight: FontWeight.bold,
),
),
),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
card['full_name'] ?? 'عضو جائزة أوروك',
style: const TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold,
letterSpacing: 0.5,
),
),
const SizedBox(height: 6),
Text(
card['membership_number'] ?? 'URUK-2026-PENDING',
style: const TextStyle(
color: AppTheme.goldLight,
fontSize: 14,
letterSpacing: 2,
fontFamily: 'Courier',
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'صالحة لغاية: ${card['expires_at'] ?? '2028-01-01'}',
style: const TextStyle(color: AppTheme.textMuted, fontSize: 12),
),
const Text(
'خصم 50% صحي | 30 دورة',
style: TextStyle(color: AppTheme.goldAccent, fontSize: 11, fontWeight: FontWeight.w600),
),
],
),
],
),
),
);
}
Widget _buildNotSubscribedView(BuildContext context) {
return Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.card_membership, color: AppTheme.goldAccent, size: 70),
const SizedBox(height: 16),
const Text(
'لا توجد عضوية نشطة حالياً',
style: TextStyle(color: Colors.white, fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
const Text(
'اشترك الآن في عضوية جائزة أوروك الدولية وتمتع بخصم 50% في المستشفيات وأكثر من 30 تخصصاً تدريبياً لمدة سنتين.',
textAlign: TextAlign.center,
style: TextStyle(color: AppTheme.textMuted, fontSize: 14),
),
const SizedBox(height: 24),
ElevatedButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const SubscriptionCheckoutScreen()),
);
},
child: const Text('طلب الاشتراك الآن (100 دولار / سنتان)'),
),
],
),
),
);
}
Widget _buildBenefitsSection() {
return Container(
padding: const EdgeInsets.all(18),
decoration: BoxDecoration(
color: AppTheme.cardDark,
borderRadius: BorderRadius.circular(16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'المزايا المشمولة في بطاقتك:',
style: TextStyle(color: AppTheme.goldLight, fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
_buildBenefitRow(Icons.local_hospital, 'خصم 50% في المستشفيات والمراكز التخصصية (بغداد، أربيل، عمان، القاهرة، بيروت)'),
_buildBenefitRow(Icons.hotel, 'خصم من 40% إلى 60% في الفنادق السياحية الفاخرة المتعاقد معها'),
_buildBenefitRow(Icons.school, 'حضور أكثر من 30 دورة تدريبية تخصصية مجاناً مع شهادات معتمدة'),
_buildBenefitRow(Icons.verified_user, 'تغطية مستمرة لمدة سنتين كاملتين تبدأ من 1/1'),
],
),
);
}
Widget _buildBenefitRow(IconData icon, String text) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 6),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(icon, color: AppTheme.goldAccent, size: 18),
const SizedBox(width: 10),
Expanded(
child: Text(text, style: const TextStyle(color: Colors.white70, fontSize: 13, height: 1.4)),
),
],
),
);
}
}
class _DynamicQrSheet extends StatefulWidget {
final String token;
final int? validUntil;
final VoidCallback onRefresh;
const _DynamicQrSheet({required this.token, this.validUntil, required this.onRefresh});
@override
State<_DynamicQrSheet> createState() => _DynamicQrSheetState();
}
class _DynamicQrSheetState extends State<_DynamicQrSheet> {
Timer? _timer;
int _secondsRemaining = 90;
@override
void initState() {
super.initState();
_calculateRemaining();
_timer = Timer.periodic(const Duration(seconds: 1), (_) {
if (mounted) {
setState(() {
if (_secondsRemaining > 0) {
_secondsRemaining--;
} else {
widget.onRefresh();
_calculateRemaining();
}
});
}
});
}
void _calculateRemaining() {
if (widget.validUntil != null) {
final now = DateTime.now().millisecondsSinceEpoch ~/ 1000;
_secondsRemaining = widget.validUntil! - now;
if (_secondsRemaining < 0) _secondsRemaining = 0;
}
}
@override
void dispose() {
_timer?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(24),
decoration: const BoxDecoration(
color: AppTheme.primaryDark,
borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(width: 40, height: 4, decoration: BoxDecoration(color: Colors.white24, borderRadius: BorderRadius.circular(2))),
const SizedBox(height: 18),
const Text(
'رمز التحقق المشفر (Dynamic QR)',
style: TextStyle(color: AppTheme.goldLight, fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 6),
const Text(
'أبرز هذا الرمز لموظف الاستقبال في المستشفى أو الفندق لتأكيد الخصم',
style: TextStyle(color: AppTheme.textMuted, fontSize: 13),
textAlign: TextAlign.center,
),
const SizedBox(height: 20),
// Dynamic QR Code Container
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(color: AppTheme.goldAccent.withOpacity(0.3), blurRadius: 20, spreadRadius: 2),
],
),
child: QrImageView(
data: widget.token,
version: QrVersions.auto,
size: 220,
backgroundColor: Colors.white,
),
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.timer_outlined, color: AppTheme.goldAccent, size: 20),
const SizedBox(width: 6),
Text(
'يتجدد الرمز خلال $_secondsRemaining ثانية',
style: const TextStyle(color: AppTheme.goldAccent, fontSize: 14, fontWeight: FontWeight.bold),
),
],
),
const SizedBox(height: 20),
],
),
);
}
}