fix(profile): Logbuch-KPI und Statistik-Fallback robuster laden
Profil bleibt bei fehlenden Client-Stats sichtbar; logbookCount nutzt lokale logbooks.length mit Server-Fallback statt totem ?? in ungerenderter Sektion. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -106,12 +106,16 @@ export default function UserProfilePage({ onBack, onLogout }: UserProfilePagePro
|
|||||||
setLoading(true)
|
setLoading(true)
|
||||||
setError(null)
|
setError(null)
|
||||||
try {
|
try {
|
||||||
const [profileData, stats] = await Promise.all([
|
const profileData = await fetchUserProfile()
|
||||||
fetchUserProfile(),
|
|
||||||
loadAccountStats(false)
|
|
||||||
])
|
|
||||||
setProfile(profileData)
|
setProfile(profileData)
|
||||||
setAccountStats(stats)
|
|
||||||
|
try {
|
||||||
|
const stats = await loadAccountStats(false)
|
||||||
|
setAccountStats(stats)
|
||||||
|
} catch (statsErr) {
|
||||||
|
console.error('Failed to load account stats for profile:', statsErr)
|
||||||
|
setAccountStats(null)
|
||||||
|
}
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
setError(err instanceof Error ? err.message : t('profile.load_error'))
|
setError(err instanceof Error ? err.message : t('profile.load_error'))
|
||||||
} finally {
|
} finally {
|
||||||
@@ -124,6 +128,8 @@ export default function UserProfilePage({ onBack, onLogout }: UserProfilePagePro
|
|||||||
}, [loadData])
|
}, [loadData])
|
||||||
|
|
||||||
const statsTotals = accountStats?.totals
|
const statsTotals = accountStats?.totals
|
||||||
|
const logbookCount =
|
||||||
|
accountStats?.logbooks.length ?? profile?.serverMeta.ownedLogbookCount ?? 0
|
||||||
|
|
||||||
const accountAgeLabel = useMemo(() => {
|
const accountAgeLabel = useMemo(() => {
|
||||||
if (!profile?.createdAt) return '—'
|
if (!profile?.createdAt) return '—'
|
||||||
@@ -420,52 +426,56 @@ export default function UserProfilePage({ onBack, onLogout }: UserProfilePagePro
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{statsTotals && (
|
{(statsTotals || profile) && (
|
||||||
<div className="stats-kpi-grid">
|
<div className="stats-kpi-grid">
|
||||||
<KpiCard
|
<KpiCard
|
||||||
icon={<BookOpen size={20} />}
|
icon={<BookOpen size={20} />}
|
||||||
label={t('profile.stats_logbooks')}
|
label={t('profile.stats_logbooks')}
|
||||||
value={String(accountStats?.logbooks.length ?? profile.serverMeta.ownedLogbookCount)}
|
value={String(logbookCount)}
|
||||||
/>
|
|
||||||
<KpiCard
|
|
||||||
icon={<Anchor size={20} />}
|
|
||||||
label={t('stats.travel_days')}
|
|
||||||
value={String(statsTotals.travelDayCount)}
|
|
||||||
/>
|
|
||||||
<KpiCard
|
|
||||||
icon={<Gauge size={20} />}
|
|
||||||
label={t('stats.total_distance')}
|
|
||||||
value={formatNm(statsTotals.totalDistanceNm)}
|
|
||||||
unit={t('stats.unit_nm')}
|
|
||||||
/>
|
|
||||||
<KpiCard
|
|
||||||
icon={<Sailboat size={20} />}
|
|
||||||
label={t('stats.sail_distance')}
|
|
||||||
value={formatNm(statsTotals.sailDistanceNm)}
|
|
||||||
unit={t('stats.unit_nm')}
|
|
||||||
/>
|
|
||||||
<KpiCard
|
|
||||||
icon={<Gauge size={20} />}
|
|
||||||
label={t('stats.motor_distance')}
|
|
||||||
value={formatNm(statsTotals.motorDistanceNm)}
|
|
||||||
unit={t('stats.unit_nm')}
|
|
||||||
/>
|
|
||||||
<KpiCard
|
|
||||||
icon={<Timer size={20} />}
|
|
||||||
label={t('stats.motor_hours_total')}
|
|
||||||
value={formatHours(statsTotals.totalMotorHours)}
|
|
||||||
unit={t('stats.unit_h')}
|
|
||||||
/>
|
/>
|
||||||
|
{statsTotals && (
|
||||||
|
<>
|
||||||
|
<KpiCard
|
||||||
|
icon={<Anchor size={20} />}
|
||||||
|
label={t('stats.travel_days')}
|
||||||
|
value={String(statsTotals.travelDayCount)}
|
||||||
|
/>
|
||||||
|
<KpiCard
|
||||||
|
icon={<Gauge size={20} />}
|
||||||
|
label={t('stats.total_distance')}
|
||||||
|
value={formatNm(statsTotals.totalDistanceNm)}
|
||||||
|
unit={t('stats.unit_nm')}
|
||||||
|
/>
|
||||||
|
<KpiCard
|
||||||
|
icon={<Sailboat size={20} />}
|
||||||
|
label={t('stats.sail_distance')}
|
||||||
|
value={formatNm(statsTotals.sailDistanceNm)}
|
||||||
|
unit={t('stats.unit_nm')}
|
||||||
|
/>
|
||||||
|
<KpiCard
|
||||||
|
icon={<Gauge size={20} />}
|
||||||
|
label={t('stats.motor_distance')}
|
||||||
|
value={formatNm(statsTotals.motorDistanceNm)}
|
||||||
|
unit={t('stats.unit_nm')}
|
||||||
|
/>
|
||||||
|
<KpiCard
|
||||||
|
icon={<Timer size={20} />}
|
||||||
|
label={t('stats.motor_hours_total')}
|
||||||
|
value={formatHours(statsTotals.totalMotorHours)}
|
||||||
|
unit={t('stats.unit_h')}
|
||||||
|
/>
|
||||||
|
<KpiCard
|
||||||
|
icon={<Share2 size={20} />}
|
||||||
|
label={t('profile.stats_shared_logbooks')}
|
||||||
|
value={String(sharedLogbookCount)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<KpiCard
|
<KpiCard
|
||||||
icon={<Calendar size={20} />}
|
icon={<Calendar size={20} />}
|
||||||
label={t('profile.stats_account_since')}
|
label={t('profile.stats_account_since')}
|
||||||
value={accountAgeLabel}
|
value={accountAgeLabel}
|
||||||
/>
|
/>
|
||||||
<KpiCard
|
|
||||||
icon={<Share2 size={20} />}
|
|
||||||
label={t('profile.stats_shared_logbooks')}
|
|
||||||
value={String(sharedLogbookCount)}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
Reference in New Issue
Block a user