import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../../../core/availability/mitra_availability_notifier.dart'; import '../../../core/constants.dart'; import '../../../core/pairing/pairing_notifier.dart'; import '../../../core/theme/halo_tokens.dart'; import '../../../core/theme/widgets/widgets.dart'; import '../../payment/state/payment_draft_provider.dart'; import '../../support/widgets/tanya_admin_sheet.dart'; /// Phase 4 Stage 8 — `BestieOfflinePopup`. /// /// Three variants: /// - [BestieOfflineVariant.returning] — the customer tried to chat with a /// specific mitra (history "Curhat lagi"); the targeted attempt failed /// (409 `targeted_mitra_offline`, or WS `returning_chat_timeout` / /// `returning_chat_rejected`). Payment session is still `confirmed`, so we /// surface a `Chat dengan bestie lain` primary CTA when other besties are /// reachable (calls [Pairing.fallbackToBlast]). /// - [BestieOfflineVariant.prePayReturning] — Stage 5.3: the customer tapped /// a dimmed (offline) row in `BestieHistoryList` BEFORE any payment. No /// payment session exists yet, so the "cari bestie lain" CTA resets the /// payment draft and pushes `/payment/entry` for a fresh blast-payment /// flow. This branch never calls [Pairing.fallbackToBlast] because there's /// no `paymentRequestId` to attach to. /// - [BestieOfflineVariant.new_] — the customer triggered a general blast /// that bottomed out (no online besties). No fallback button; just a /// ghost `tanya admin` and a `kembali ke home` exit. /// /// All variants expose `tanya admin` via a ghost CTA that opens the /// [TanyaAdminSheet]. enum BestieOfflineVariant { returning, prePayReturning, new_ } class BestieOfflinePopup extends ConsumerWidget { final BestieOfflineVariant variant; final String mitraName; final String? paymentRequestId; final TopicSensitivity? topicSensitivity; const BestieOfflinePopup({ super.key, required this.variant, required this.mitraName, this.paymentRequestId, this.topicSensitivity, }); static Future show( BuildContext context, { required BestieOfflineVariant variant, required String mitraName, String? paymentRequestId, TopicSensitivity? topicSensitivity, }) { return showDialog( context: context, barrierDismissible: false, barrierColor: const Color(0x66000000), builder: (_) => BestieOfflinePopup( variant: variant, mitraName: mitraName, paymentRequestId: paymentRequestId, topicSensitivity: topicSensitivity, ), ); } @override Widget build(BuildContext context, WidgetRef ref) { final availabilityAsync = ref.watch(mitraAvailabilityProvider); final hasOtherAvailable = availabilityAsync.valueOrNull ?? false; final isReturning = variant == BestieOfflineVariant.returning; final isPrePayReturning = variant == BestieOfflineVariant.prePayReturning; final mentionsBestie = isReturning || isPrePayReturning; final title = mentionsBestie ? '$mitraName lagi nggak online' : 'semua bestie lagi istirahat'; final body = mentionsBestie ? 'bestie kamu belum bisa nerima chat sekarang. coba bestie lain atau balik ke beranda dulu ya.' : 'lagi nggak ada bestie yang siap dengerin. coba lagi bentar, atau hubungin admin biar dibantu.'; final canFallbackToBlast = isReturning && hasOtherAvailable && paymentRequestId != null && topicSensitivity != null; return Dialog( backgroundColor: HaloTokens.surface, elevation: 0, shape: const RoundedRectangleBorder(borderRadius: HaloRadius.xl), insetPadding: const EdgeInsets.symmetric(horizontal: HaloSpacing.s24), child: Padding( padding: const EdgeInsets.all(HaloSpacing.s24), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Center( child: Container( width: 64, height: 64, decoration: const BoxDecoration( color: HaloTokens.brandSofter, shape: BoxShape.circle, ), alignment: Alignment.center, child: const Icon( Icons.cloud_off_outlined, color: HaloTokens.brandDark, size: 28, ), ), ), const SizedBox(height: HaloSpacing.s16), Text( title, textAlign: TextAlign.center, style: const TextStyle( fontFamily: HaloTokens.fontDisplay, fontSize: 22, height: 28 / 22, fontWeight: FontWeight.w700, color: HaloTokens.ink, ), ), const SizedBox(height: HaloSpacing.s12), Text( body, textAlign: TextAlign.center, style: const TextStyle( fontFamily: HaloTokens.fontBody, fontSize: 15, height: 22 / 15, color: HaloTokens.inkSoft, ), ), const SizedBox(height: HaloSpacing.s24), if (canFallbackToBlast) HaloButton( label: 'chat dengan bestie lain', fullWidth: true, onPressed: () { Navigator.of(context).pop(); // ignore: discarded_futures ref.read(pairingProvider.notifier).fallbackToBlast( paymentRequestId: paymentRequestId!, topicSensitivity: topicSensitivity!, ); }, ) else if (isPrePayReturning) HaloButton( label: 'cari bestie lain', fullWidth: true, onPressed: () { // No payment session yet — clear any targeted-mitra intent // on the draft so the fresh `/payment/entry` flow falls // through to the blast branch. ref.read(paymentDraftNotifierProvider.notifier).reset(); Navigator.of(context).pop(); context.push('/payment/entry'); }, ) else HaloButton( label: 'kembali ke home', fullWidth: true, onPressed: () { ref.read(pairingProvider.notifier).reset(); Navigator.of(context).pop(); context.go('/home'); }, ), const SizedBox(height: HaloSpacing.s8), HaloButton( label: 'tanya admin', variant: HaloButtonVariant.ghost, fullWidth: true, onPressed: () { // Keep the popup open underneath; the sheet sits on top and // closes back to it. // ignore: discarded_futures TanyaAdminSheet.show(context); }, ), if (canFallbackToBlast || isPrePayReturning) ...[ const SizedBox(height: HaloSpacing.s4), HaloButton( label: 'kembali ke home', variant: HaloButtonVariant.ghost, fullWidth: true, onPressed: () { ref.read(pairingProvider.notifier).reset(); Navigator.of(context).pop(); context.go('/home'); }, ), ], ], ), ), ); } }