+ Shinkan ist die Trainingsplanungs-Plattform für Vereine. Um Übungen, Planung und Medien zu nutzen,
+ brauchst du eine Mitgliedschaft in einem Verein — oder du beantragst die Gründung eines neuen Vereins.
+
+
+
+
+ {!emailOk ? (
+
+
+ Bitte bestätige zuerst deine E-Mail-Adresse. Danach kannst du einen Beitrittsantrag stellen.
+
+
+ ) : (
+ <>
+ {ok ? (
+
+ {ok}
+
+ ) : null}
+ {error ? (
+
+ {error}
+
+ ) : null}
+
+
+
Bestehendem Verein beitreten
+
+ Wähle einen Verein und sende einen Beitrittsantrag. Nach Freigabe durch den Vereinsadmin
+ stehen dir alle Funktionen zur Verfügung.
+
+ Die Beantragung einer neuen Vereinsgründung wird als Nächstes freigeschaltet (Freigabe durch
+ den Plattform-Administrator). Bis dahin wende dich an{' '}
+ support@jinkendo.de oder tritt einem bestehenden Verein bei.
+
+
+ >
+ )}
+
+
+ Einstellungen (Passwort, Profil)
+
+
+ )
+}
diff --git a/frontend/src/utils/accountState.js b/frontend/src/utils/accountState.js
new file mode 100644
index 0000000..43fc7ef
--- /dev/null
+++ b/frontend/src/utils/accountState.js
@@ -0,0 +1,38 @@
+/**
+ * Account-Lifecycle-Helfer (CAPABILITY_CATALOG §3, Phase A Onboarding).
+ */
+
+export function resolveAccountState(user) {
+ if (!user) return 'anonymous'
+ if (user.account_state) return user.account_state
+ const clubs = user.clubs || []
+ const hasActive = clubs.some(
+ (c) => String(c.membership_status || 'active').toLowerCase() === 'active'
+ )
+ if (hasActive) return 'active_member'
+ const verified =
+ user.email_verified === true ||
+ user.email_verified === 't' ||
+ user.email_verified === 1 ||
+ user.email_verified === 'true'
+ if (!verified) return 'unverified'
+ return 'verified_pending_club'
+}
+
+export function isPlatformAccountState(state) {
+ return state === 'platform_admin'
+}
+
+/** Eingeschränkter Modus: noch kein aktiver Vereinszugang bzw. E-Mail offen. */
+export function isOnboardingRestricted(user) {
+ const state = resolveAccountState(user)
+ if (isPlatformAccountState(state)) return false
+ return state === 'verified_pending_club' || state === 'unverified'
+}
+
+const ONBOARDING_PATHS = ['/onboarding', '/settings', '/settings/legal', '/settings/system']
+
+export function isOnboardingAllowedPath(pathname) {
+ const p = pathname || ''
+ return ONBOARDING_PATHS.some((base) => p === base || p.startsWith(`${base}/`))
+}