leafittome/lib/features/auth/presentation/bootstrap_gate.dart
cschlaefke 5ed3a68e45 Fix: Reaktiver Haushalts-Bootstrap + BootstrapGate (Apple-Login legte keinen Haushalt an)
Der Bootstrap hing an signInWithApple und lief erst, nachdem der Router
den Nutzer schon in die App geleitet hatte — Fehler blieben unsichtbar,
der Account blieb ohne users-Doc/Haushalt und alle Writes scheiterten an
den Rules. Jetzt beobachtet householdBootstrapProvider das users-Dokument
und legt Profil + Haushalt reaktiv an (alle Login-Wege); das BootstrapGate
hält die App so lange zurück und macht Fehler mit „Erneut versuchen"
sichtbar. Bestehende kaputte Accounts heilen beim nächsten Start selbst.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 17:49:49 +02:00

69 lines
2.6 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../../core/firebase/firebase_providers.dart';
import '../../../l10n/generated/app_localizations.dart';
import '../data/household_bootstrap_provider.dart';
/// Hält die App zurück, solange zum angemeldeten Nutzer noch kein
/// users-Dokument (und damit kein Haushalt) existiert.
///
/// Beim ersten Login (z. B. mit Apple) legt [householdBootstrapProvider]
/// beides an; bis dahin gibt es einen Warte-Bildschirm. Schlägt der
/// Bootstrap fehl, wird der Fehler hier sichtbar — vorher konnte man in
/// der App landen, deren Schreibzugriffe dann alle an den Rules scheiterten.
class BootstrapGate extends ConsumerWidget {
const BootstrapGate({super.key, required this.child});
final Widget child;
@override
Widget build(BuildContext context, WidgetRef ref) {
final user = ref.watch(authStateProvider).value;
if (user == null) return child; // Login-Screen übernimmt.
final profile = ref.watch(userProfileProvider).value;
final profileReady =
profile != null && profile.id == user.uid && profile.exists;
if (profileReady) return child;
final bootstrap = ref.watch(householdBootstrapProvider);
final l10n = AppLocalizations.of(context);
final theme = Theme.of(context);
return Scaffold(
body: SafeArea(
child: Center(
child: Padding(
padding: const EdgeInsets.all(24),
child: bootstrap.hasError
? Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.cloud_off,
size: 48, color: theme.colorScheme.error),
const SizedBox(height: 16),
Text(l10n.bootstrapFailed, textAlign: TextAlign.center),
const SizedBox(height: 16),
FilledButton(
onPressed: () => ref
.read(householdBootstrapProvider.notifier)
.retry(),
child: Text(l10n.bootstrapRetry),
),
],
)
: Column(
mainAxisSize: MainAxisSize.min,
children: [
const CircularProgressIndicator(),
const SizedBox(height: 16),
Text(l10n.bootstrapPreparing,
textAlign: TextAlign.center),
],
),
),
),
),
);
}
}