onboardingState function
Resolves the current onboarding status for the signed-in user. The gate watches this and redirects (or shows the invitation modal) accordingly.
Implementation
@riverpod
Future<OnboardingStatus> onboardingState(Ref ref) async {
final profile = await ref.watch(currentProfileProvider.future);
// No profile row yet — the auto-profile trigger runs on signup so this is
// transient. Treat as "needs profile completion" to force a refetch via
// the profile screen; if the row is genuinely missing updateProfile will
// upsert via RLS.
if (profile == null) return OnboardingStatus.needsProfileCompletion;
final displayName = profile.displayName?.trim();
if (displayName == null || displayName.isEmpty) {
return OnboardingStatus.needsProfileCompletion;
}
final persona = profile.persona;
if (persona == null || persona.isEmpty) {
return OnboardingStatus.needsPersona;
}
final invitations = await ref.watch(myInvitationsProvider.future);
final dismissed = ref
.watch(onboardingSessionStateProvider)
.invitationsDismissed;
if (invitations.isNotEmpty && !dismissed) {
return OnboardingStatus.hasPendingInvitations;
}
// Learner onboarding applies to solo personas. Team leads skip the
// pedagogical tour (they manage learners; they'll experience it only if
// they also learn — reachable via Settings "Replay").
if (persona == 'solo' && profile.onboardingCompletedAt == null) {
return OnboardingStatus.needsLearnerOnboarding;
}
final isAdmin = await ref.watch(isOrgAdminProvider.future);
if (isAdmin && profile.adminOnboardingCompletedAt == null) {
return OnboardingStatus.needsAdminOnboarding;
}
return OnboardingStatus.complete;
}