import "dart:async"; import "package:bus_running_record/provider/collaboration_state.dart"; import "package:bus_running_record/provider/supabase_state.dart"; import "package:flutter/foundation.dart"; import "package:go_router/go_router.dart"; import "package:provider/provider.dart"; import "package:shadcn_flutter/shadcn_flutter.dart"; class InvitePage extends StatefulWidget { const InvitePage({required this.token, super.key}); final String token; static final GoRoute route = GoRoute( path: "/invite/:token", builder: (context, state) { final token = state.pathParameters["token"] ?? ""; return InvitePage(token: token); }, ); @override State createState() => _InvitePageState(); } class _InvitePageState extends State { bool _accepting = false; bool _accepted = false; String? _error; @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { if (!mounted) return; final isLoggedIn = context.read().isAuthenticated; if (isLoggedIn) { unawaited(_acceptInvite()); } }); } @override Widget build(BuildContext context) { final supabase = context.watch(); final isLoggedIn = supabase.isAuthenticated; return Scaffold( child: Center( child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 480), child: Padding( padding: const EdgeInsets.all(16), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("Organization Invite").x2Large.semiBold, const Gap(8), Text("Token: ${widget.token}").xSmall.muted, const Gap(16), if (!isLoggedIn) ...[ Text("Sign in to accept this invite.").small, const Gap(12), Button.primary( onPressed: () { final next = Uri.encodeComponent("/invite/${widget.token}"); context.go("/login?next=$next"); }, child: const Text("Sign in"), ), ] else if (_accepting) ...[ Row( children: [ const CircularProgressIndicator(), const Gap(10), Text("Accepting invite...").small, ], ), ] else if (_accepted) ...[ Text("Invite accepted.").small, const Gap(12), Button.primary( onPressed: () => context.go("/"), child: const Text("Open workspace"), ), ] else ...[ if (_error != null) Text(_error!).small, const Gap(12), Button.primary( onPressed: () => unawaited(_acceptInvite()), child: const Text("Accept invite"), ), ], ], ), ), ), ), ); } Future _acceptInvite() async { if (_accepting) return; setState(() { _accepting = true; _error = null; }); try { await context.read().acceptInviteToken(widget.token); if (!mounted) return; setState(() { _accepted = true; }); } catch (error, stackTrace) { debugPrint("[InvitePage] acceptInvite failed: $error"); debugPrintStack(stackTrace: stackTrace); if (!mounted) return; setState(() { _error = error.toString(); }); } finally { if (mounted) { setState(() { _accepting = false; }); } } } }