import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../../../core/chat/chat_opening_provider.dart'; import '../../../core/constants.dart'; import '../../../core/theme/halo_tokens.dart'; import '../../../core/theme/widgets/halo_button.dart'; import '../state/payment_draft_provider.dart'; /// S6 first-session discount paywall. /// /// Renders only when `chat-pricing.first_session_discount.eligible == true`. /// Layout: struck-through gimmick price next to a prominent actual price, /// "untuk N menit ngobrol" subtitle, and a primary CTA that seeds the payment /// draft and routes to `/payment/method`. class DiscountPaywallScreen extends ConsumerWidget { const DiscountPaywallScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final pricingAsync = ref.watch(chatPricingProvider); return Scaffold( backgroundColor: HaloTokens.bg, appBar: AppBar( backgroundColor: HaloTokens.bg, elevation: 0, leading: IconButton( icon: const Icon(Icons.chevron_left, color: HaloTokens.brandDark), onPressed: () { if (context.canPop()) { context.pop(); } else { context.go('/home'); } }, ), ), body: pricingAsync.when( loading: () => const Center(child: CircularProgressIndicator()), error: (_, __) => const Center( child: Padding( padding: EdgeInsets.all(HaloSpacing.s24), child: Text( 'Gagal memuat harga. Coba lagi.', textAlign: TextAlign.center, ), ), ), data: (pricing) { final discount = pricing.firstSessionDiscount; if (discount == null || !discount.eligible) { // Defensive: route guard normally prevents this. If we got here // anyway (stale state), kick over to method-pick. WidgetsBinding.instance.addPostFrameCallback((_) { if (!context.mounted) return; context.go('/payment/method-pick'); }); return const SizedBox.shrink(); } return _Body(discount: discount); }, ), ); } } class _Body extends ConsumerWidget { final FirstSessionDiscount discount; const _Body({required this.discount}); void _onMulai(BuildContext context, WidgetRef ref) { ref.read(paymentDraftNotifierProvider.notifier).setDiscountPlan( durationMinutes: discount.durationMinutes, priceIDR: discount.actualPriceIDR, ); context.push('/payment/method'); } @override Widget build(BuildContext context, WidgetRef ref) { final showModeToggle = discount.modes.length > 1; final actual = formatRupiah(discount.actualPriceIDR); final gimmick = formatRupiah(discount.gimmickPriceIDR); return Column( children: [ Expanded( child: SingleChildScrollView( padding: const EdgeInsets.fromLTRB( HaloSpacing.s24, HaloSpacing.s8, HaloSpacing.s24, HaloSpacing.s16, ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (showModeToggle) const _ModeToggleHidden(), const Text( '🌷', style: TextStyle(fontSize: 38), ), const SizedBox(height: HaloSpacing.s12), Text( 'biar yakin yang mau cerita,\nbestie cuma minta $actual', style: const TextStyle( fontFamily: HaloTokens.fontDisplay, fontSize: 26, fontWeight: FontWeight.w700, color: HaloTokens.brandDark, height: 1.2, letterSpacing: -0.5, ), ), const SizedBox(height: HaloSpacing.s16), const Text( 'bukan biaya — anggap aja seperti senyum hangat di awal pertemuan, biar bestie tau kamu beneran mau ngobrol.', style: TextStyle( fontSize: 14, color: HaloTokens.inkSoft, height: 1.55, ), ), const SizedBox(height: HaloSpacing.s20), _PriceCard( actual: actual, gimmick: gimmick, durationMinutes: discount.durationMinutes, ), const SizedBox(height: HaloSpacing.s12), const Center( child: Text( 'sesi-sesi berikutnya pakai harga normal, sesuai durasi yang kamu pilih.', textAlign: TextAlign.center, style: TextStyle( fontSize: 12, color: HaloTokens.inkMuted, height: 1.5, ), ), ), ], ), ), ), Container( padding: const EdgeInsets.fromLTRB( HaloSpacing.s24, HaloSpacing.s12, HaloSpacing.s24, HaloSpacing.s32, ), decoration: const BoxDecoration( color: HaloTokens.bg, border: Border(top: BorderSide(color: HaloTokens.border)), ), child: Column( children: [ HaloButton( label: 'mulai · $actual', size: HaloButtonSize.lg, fullWidth: true, onPressed: () => _onMulai(context, ref), ), const SizedBox(height: HaloSpacing.s8), const Text( 'QRIS · GoPay · OVO · DANA · ShopeePay', style: TextStyle(fontSize: 11, color: HaloTokens.inkMuted), ), ], ), ), ], ); } } class _PriceCard extends StatelessWidget { final String actual; final String gimmick; final int durationMinutes; const _PriceCard({ required this.actual, required this.gimmick, required this.durationMinutes, }); @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.all(HaloSpacing.s20), decoration: BoxDecoration( gradient: const LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [HaloTokens.brandSofter, HaloTokens.surface], ), borderRadius: HaloRadius.xl, border: Border.all(color: HaloTokens.brandSoft), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'SESI PERTAMA', style: TextStyle( fontSize: 11, color: HaloTokens.inkSoft, fontWeight: FontWeight.w500, letterSpacing: 0.6, ), ), const SizedBox(height: HaloSpacing.s4), Row( crossAxisAlignment: CrossAxisAlignment.end, children: [ Text( actual, style: const TextStyle( fontFamily: HaloTokens.fontDisplay, fontSize: 36, fontWeight: FontWeight.w700, color: HaloTokens.brandDark, height: 1, letterSpacing: -1, ), ), const SizedBox(width: HaloSpacing.s8), Padding( padding: const EdgeInsets.only(bottom: 4), child: Text( gimmick, style: const TextStyle( fontSize: 14, color: HaloTokens.inkMuted, decoration: TextDecoration.lineThrough, ), ), ), ], ), const SizedBox(height: HaloSpacing.s4), Text( 'untuk $durationMinutes menit ngobrol', style: const TextStyle( fontSize: 13, color: HaloTokens.inkSoft, ), ), ], ), ), Container( padding: const EdgeInsets.symmetric( horizontal: HaloSpacing.s12, vertical: 6, ), decoration: const BoxDecoration( color: HaloTokens.mint, borderRadius: HaloRadius.pill, ), child: const Text( 'HANYA SEKALI', style: TextStyle( fontSize: 10, fontWeight: FontWeight.w700, color: Color(0xFF1F4D34), letterSpacing: 0.6, ), ), ), ], ), const Padding( padding: EdgeInsets.symmetric(vertical: HaloSpacing.s16), child: Divider(height: 1, color: HaloTokens.border), ), ..._features.map((row) => Padding( padding: const EdgeInsets.only(bottom: HaloSpacing.s8), child: Row( children: [ Text(row.$1, style: const TextStyle(fontSize: 14)), const SizedBox(width: HaloSpacing.s8), Expanded( child: Text( row.$2, style: const TextStyle( fontSize: 13, color: HaloTokens.ink, ), ), ), ], ), )), ], ), ); } static const List<(String, String)> _features = [ ('🤍', 'menit private sama bestie kamu'), ('👤', 'manusia nyata, bukan AI'), ('🛡️', 'gak cocok? sesi gratis tanpa tanya'), ]; } /// Placeholder for the chat|call mode toggle on the discount screen. Default /// config is chat-only (`modes = ['chat']`) so we never render anything yet — /// kept as a marker so the spot is reserved when ops eventually flips /// `first_session_discount_modes` to `['chat', 'call']`. class _ModeToggleHidden extends StatelessWidget { const _ModeToggleHidden(); @override Widget build(BuildContext context) => const SizedBox.shrink(); }