import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:url_launcher/url_launcher.dart'; import '../../core/auth/auth_notifier.dart'; import '../../core/theme/halo_tokens.dart'; import '../../core/theme/widgets/widgets.dart'; import 'support_handles_provider.dart'; /// Bestie Profil tab — mirrors /// `figma-bestie/project/screens/v5.jsx::BestieProfile`. /// /// Lives inside branch 2 of the shell (`router.dart`), so `BestieTabBar` is /// rendered by `ShellScreen` — this screen owns body content only. /// /// Menu items mirror the figma: Chat WhatsApp Kami + Chat Telegram Kami /// (both deep-link via `support_handles_json` from backend config), then /// Syarat & Ketentuan + Kebijakan Privasi (TODO content). Danger zone is /// Keluar (logout) only — account deletion is intentionally not exposed /// in-app; mitras request deletion via the same WA/TG channels. class ProfilScreen extends ConsumerWidget { const ProfilScreen({super.key}); // TODO(stage-4): replace with `PackageInfo.fromPlatform().version` when // the `package_info_plus` package is added in a future change. static const String _appVersion = '1.0.0'; @override Widget build(BuildContext context, WidgetRef ref) { final authState = ref.watch(mitraAuthProvider); final authData = authState.valueOrNull; final handlesAsync = ref.watch(supportHandlesProvider); final profile = authData is MitraAuthAuthenticatedData ? authData.profile : null; final displayName = (profile?['display_name'] as String?) ?? 'Bestie'; final phone = (profile?['phone'] as String?) ?? ''; return Scaffold( backgroundColor: HaloTokens.bg, body: SafeArea( child: SingleChildScrollView( padding: const EdgeInsets.fromLTRB(20, 24, 20, 40), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const _Header(), const SizedBox(height: 20), _ProfileCard(displayName: displayName, phone: phone), const SizedBox(height: 28), _MenuList( onTapWa: () => _launchHandle(context, handlesAsync.valueOrNull?.wa), onTapTelegram: () => _launchHandle(context, handlesAsync.valueOrNull?.telegram), onTapTerms: () => _snack(context, 'Segera tersedia'), onTapPrivacy: () => _snack(context, 'Segera tersedia'), ), const SizedBox(height: 24), HaloButton( label: 'Keluar', fullWidth: true, variant: HaloButtonVariant.secondary, onPressed: () => _confirmLogout(context, ref), ), const SizedBox(height: 16), const _VersionFooter(version: _appVersion), ], ), ), ), ); } Future _launchHandle(BuildContext context, SupportHandle? handle) async { if (handle == null || handle.deeplink.isEmpty) { _snack(context, 'Kontak belum tersedia'); return; } final uri = Uri.tryParse(handle.deeplink); if (uri == null) { _snack(context, 'Tautan tidak valid'); return; } final ok = await launchUrl(uri, mode: LaunchMode.externalApplication); if (!ok && context.mounted) { _snack(context, 'Gagal membuka ${handle.label}'); } } void _snack(BuildContext context, String message) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( message, style: const TextStyle(fontFamily: HaloTokens.fontBody), ), behavior: SnackBarBehavior.floating, ), ); } Future _confirmLogout(BuildContext context, WidgetRef ref) async { final confirmed = await showDialog( context: context, barrierDismissible: true, builder: (ctx) => AlertDialog( title: const Text( 'Yakin mau keluar?', style: TextStyle( fontFamily: HaloTokens.fontDisplay, fontWeight: FontWeight.w700, color: HaloTokens.brandDark, ), ), content: const Text( 'Kamu bakal sign-out dari akun mitra ini. Login lagi pakai nomor HP yang sama untuk masuk.', style: TextStyle( fontFamily: HaloTokens.fontBody, fontSize: 13.5, height: 1.4, color: HaloTokens.inkSoft, ), ), actions: [ TextButton( onPressed: () => Navigator.of(ctx).pop(false), child: const Text( 'Batal', style: TextStyle( fontFamily: HaloTokens.fontBody, color: HaloTokens.inkSoft, fontWeight: FontWeight.w600, ), ), ), TextButton( onPressed: () => Navigator.of(ctx).pop(true), child: const Text( 'Keluar', style: TextStyle( fontFamily: HaloTokens.fontBody, color: HaloTokens.danger, fontWeight: FontWeight.w700, ), ), ), ], ), ); if (confirmed == true) { await ref.read(mitraAuthProvider.notifier).logout(); // Router redirect handles navigation to /login on auth state change. } } } // ─── Header — centered "Profil" title (no back arrow; tab nav owns nav) ── class _Header extends StatelessWidget { const _Header(); @override Widget build(BuildContext context) { return const Center( child: Text( 'Profil', style: TextStyle( fontFamily: HaloTokens.fontDisplay, fontSize: 22, fontWeight: FontWeight.w700, color: HaloTokens.brandDark, letterSpacing: -0.4, ), ), ); } } // ─── Profile card — HaloOrb + display name + role + phone ──────────────── class _ProfileCard extends StatelessWidget { final String displayName; final String phone; const _ProfileCard({required this.displayName, required this.phone}); @override Widget build(BuildContext context) { // Deterministic seed from phone — same number always gets the same orb. final seed = phone.isEmpty ? 0 : phone.hashCode; return Container( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 24), decoration: BoxDecoration( color: HaloTokens.surface, borderRadius: HaloRadius.lg, border: Border.all(color: HaloTokens.border), boxShadow: HaloShadows.soft, ), child: Column( children: [ HaloOrb(size: 96, seed: seed), const SizedBox(height: 16), Text( displayName, textAlign: TextAlign.center, style: const TextStyle( fontFamily: HaloTokens.fontDisplay, fontSize: 24, fontWeight: FontWeight.w700, color: HaloTokens.brandDark, letterSpacing: -0.4, ), ), const SizedBox(height: 4), const Text( 'Bestie · Mitra Halo Bestie', textAlign: TextAlign.center, style: TextStyle( fontFamily: HaloTokens.fontBody, fontSize: 13, color: HaloTokens.inkSoft, ), ), if (phone.isNotEmpty) ...[ const SizedBox(height: 6), Text( phone, textAlign: TextAlign.center, style: const TextStyle( fontFamily: HaloTokens.fontMono, fontSize: 12.5, color: HaloTokens.inkMuted, ), ), ], ], ), ); } } // ─── Menu list — WA + Telegram + Terms + Privacy ───────────────────────── class _MenuList extends StatelessWidget { final VoidCallback onTapWa; final VoidCallback onTapTelegram; final VoidCallback onTapTerms; final VoidCallback onTapPrivacy; const _MenuList({ required this.onTapWa, required this.onTapTelegram, required this.onTapTerms, required this.onTapPrivacy, }); @override Widget build(BuildContext context) { return Column( children: [ _MenuTile( icon: FontAwesomeIcons.whatsapp, label: 'Chat WhatsApp Kami', onTap: onTapWa, ), const SizedBox(height: 10), _MenuTile( icon: FontAwesomeIcons.telegram, label: 'Chat Telegram Kami', onTap: onTapTelegram, ), const SizedBox(height: 10), _MenuTile( icon: Icons.description_outlined, label: 'Syarat & Ketentuan', onTap: onTapTerms, ), const SizedBox(height: 10), _MenuTile( icon: Icons.lock_outline, label: 'Kebijakan Privasi', onTap: onTapPrivacy, ), ], ); } } class _MenuTile extends StatelessWidget { final IconData icon; final String label; final String? subtitle; final VoidCallback onTap; const _MenuTile({ required this.icon, required this.label, this.subtitle, required this.onTap, }); @override Widget build(BuildContext context) { return Material( color: HaloTokens.surface, borderRadius: HaloRadius.md, child: InkWell( borderRadius: HaloRadius.md, onTap: onTap, child: Container( constraints: const BoxConstraints(minHeight: 56), padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12), decoration: BoxDecoration( borderRadius: HaloRadius.md, border: Border.all(color: HaloTokens.border), ), child: Row( children: [ Container( width: 36, height: 36, decoration: const BoxDecoration( color: HaloTokens.brandSofter, borderRadius: HaloRadius.sm, ), alignment: Alignment.center, child: Icon(icon, size: 18, color: HaloTokens.brandDark), ), const SizedBox(width: 14), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text( label, style: const TextStyle( fontFamily: HaloTokens.fontBody, fontSize: 14, fontWeight: FontWeight.w500, color: HaloTokens.ink, ), ), if (subtitle != null) ...[ const SizedBox(height: 2), Text( subtitle!, style: const TextStyle( fontFamily: HaloTokens.fontBody, fontSize: 11.5, color: HaloTokens.inkMuted, ), ), ], ], ), ), const Icon( Icons.chevron_right, size: 20, color: HaloTokens.inkMuted, ), ], ), ), ), ); } } // ─── Version footer ────────────────────────────────────────────────────── class _VersionFooter extends StatelessWidget { final String version; const _VersionFooter({required this.version}); @override Widget build(BuildContext context) { return Center( child: Text( 'HaloBestie · v$version', style: const TextStyle( fontFamily: HaloTokens.fontBody, fontSize: 11, color: HaloTokens.inkMuted, ), ), ); } }