import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../core/chat/session_closure_notifier.dart'; import '../../../core/theme/halo_tokens.dart'; import '../../../core/theme/widgets/halo_bottom_sheet.dart'; import '../../../core/theme/widgets/halo_button.dart'; /// Stage 7 — replaces the legacy goodbye-composer screen with a bottom sheet. /// The sheet is launched after the two-step confirm; it submits the goodbye /// message AND closes the session. Both CTAs end the session — the difference /// is whether a closing message is sent first. class ClosingMessageSheet { const ClosingMessageSheet._(); static Future show( BuildContext context, { required String sessionId, required VoidCallback onCompleted, }) { return HaloBottomSheet.show( context, isScrollControlled: true, child: _ClosingMessageBody( sessionId: sessionId, onCompleted: onCompleted, ), ); } } class _ClosingMessageBody extends ConsumerStatefulWidget { final String sessionId; final VoidCallback onCompleted; const _ClosingMessageBody({ required this.sessionId, required this.onCompleted, }); @override ConsumerState<_ClosingMessageBody> createState() => _ClosingMessageBodyState(); } class _ClosingMessageBodyState extends ConsumerState<_ClosingMessageBody> { final _controller = TextEditingController(); bool _busy = false; @override void dispose() { _controller.dispose(); super.dispose(); } Future _sendAndEnd() async { final text = _controller.text.trim(); if (text.isEmpty || _busy) return; setState(() => _busy = true); final notifier = ref.read(sessionClosureProvider.notifier); await notifier.submitGoodbye(widget.sessionId, text); await notifier.closeSession(widget.sessionId); if (!mounted) return; Navigator.of(context).pop(); widget.onCompleted(); } Future _skipAndEnd() async { if (_busy) return; setState(() => _busy = true); await ref.read(sessionClosureProvider.notifier).closeSession(widget.sessionId); if (!mounted) return; Navigator.of(context).pop(); widget.onCompleted(); } @override Widget build(BuildContext context) { final viewInsets = MediaQuery.of(context).viewInsets.bottom; return Padding( padding: EdgeInsets.only(bottom: viewInsets), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const Text( 'pesan penutup', style: TextStyle( fontFamily: HaloTokens.fontDisplay, fontSize: 20, fontWeight: FontWeight.w700, color: HaloTokens.ink, ), textAlign: TextAlign.center, ), const SizedBox(height: HaloSpacing.s8), const Text( 'tulis sesuatu buat bestie sebelum sesi ditutup', style: TextStyle( fontFamily: HaloTokens.fontBody, fontSize: 14, color: HaloTokens.inkSoft, ), textAlign: TextAlign.center, ), const SizedBox(height: HaloSpacing.s16), TextField( controller: _controller, maxLines: 4, minLines: 3, enabled: !_busy, decoration: const InputDecoration( hintText: 'makasih ya bestie...', filled: true, fillColor: HaloTokens.brandSofter, border: OutlineInputBorder( borderRadius: HaloRadius.lg, borderSide: BorderSide.none, ), ), ), const SizedBox(height: HaloSpacing.s16), HaloButton( label: 'kirim & akhiri sesi', fullWidth: true, onPressed: _busy ? null : _sendAndEnd, ), const SizedBox(height: HaloSpacing.s8), HaloButton( label: 'lewat — langsung akhiri', variant: HaloButtonVariant.ghost, fullWidth: true, onPressed: _busy ? null : _skipAndEnd, ), ], ), ); } }