import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../core/auth/auth_notifier.dart'; import '../../core/theme/halo_tokens.dart'; import '../../core/theme/widgets/widgets.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. /// /// Stage 4 deviation from the JSX: the Figma "Chat WhatsApp Kami / Chat /// Telegram Kami" rows surface customer-facing admin handles. Mitras are /// internal-only audience (see project memory `feedback_mitra_internal_audience`), /// so those two rows are replaced with a single "Hubungi Koordinator" entry /// pointing at the internal coordinator channel. 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. Hardcoded // for now to avoid pulling a new dependency. static const String _appVersion = '1.0.0'; @override Widget build(BuildContext context, WidgetRef ref) { final authState = ref.watch(mitraAuthProvider); final authData = authState.valueOrNull; 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( onTapCoordinator: () => _snack( context, 'Hubungi koordinator via grup internal — info lengkap segera tersedia', ), onTapTerms: () => _snack(context, 'Segera tersedia'), onTapPrivacy: () => _snack(context, 'Segera tersedia'), ), const SizedBox(height: 24), _DangerZone( onLogout: () => _confirmLogout(context, ref), onDelete: () => _snack( context, 'Hubungi koordinator untuk penghapusan akun', ), ), const SizedBox(height: 16), const _VersionFooter(version: _appVersion), ], ), ), ), ); } 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 — 3 stacked _MenuTile items ─────────────────────────────── class _MenuList extends StatelessWidget { final VoidCallback onTapCoordinator; final VoidCallback onTapTerms; final VoidCallback onTapPrivacy; const _MenuList({ required this.onTapCoordinator, required this.onTapTerms, required this.onTapPrivacy, }); @override Widget build(BuildContext context) { return Column( children: [ _MenuTile( icon: Icons.support_agent_outlined, label: 'Hubungi Koordinator', subtitle: 'via grup koordinator internal', onTap: onTapCoordinator, ), 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, ), ], ), ), ), ); } } // ─── Danger zone — Keluar (secondary) + Hapus Akun (danger text) ───────── class _DangerZone extends StatelessWidget { final VoidCallback onLogout; final VoidCallback onDelete; const _DangerZone({required this.onLogout, required this.onDelete}); @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ HaloButton( label: 'Keluar', fullWidth: true, variant: HaloButtonVariant.secondary, onPressed: onLogout, ), const SizedBox(height: 10), // Hapus Akun — destructive ghost-style with danger border + text. Material( color: HaloTokens.surface, borderRadius: HaloRadius.pill, child: InkWell( borderRadius: HaloRadius.pill, onTap: onDelete, child: Container( padding: const EdgeInsets.symmetric( horizontal: 24, vertical: 12, ), decoration: BoxDecoration( borderRadius: HaloRadius.pill, border: Border.all( color: HaloTokens.danger.withValues(alpha: 0.4), ), ), alignment: Alignment.center, child: const Row( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.delete_outline, size: 17, color: HaloTokens.danger, ), SizedBox(width: 8), Text( 'Hapus Akun', style: TextStyle( fontFamily: HaloTokens.fontBody, fontSize: 14, fontWeight: FontWeight.w600, color: HaloTokens.danger, ), ), ], ), ), ), ), ], ); } } // ─── 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, ), ), ); } }