63 lines
1.6 KiB
TypeScript
63 lines
1.6 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
import { apiFetch } from '../lib/api';
|
|
|
|
export type Plan = 'free' | 'pro' | 'legend';
|
|
|
|
/**
|
|
* Single source of truth für den eingeloggten User. /api/auth/me joint
|
|
* `auth.users` mit `rebreak.profiles` server-side — wir bekommen alles in
|
|
* einem Request: plan, avatar, nickname, streak.
|
|
*
|
|
* WICHTIG: nicht aus `supabase.auth.getUser().user_metadata` lesen — das
|
|
* sind nur die JWT-Claims vom Signup-Zeitpunkt, NICHT der aktuelle Profile-
|
|
* Stand (Avatar/Nickname/Plan werden via Profile-Edit-API geupdated, landen
|
|
* in der DB, NICHT zurück ins JWT-Claim).
|
|
*/
|
|
export type Me = {
|
|
id: string;
|
|
email: string;
|
|
username: string;
|
|
nickname: string | null;
|
|
avatar: string | null;
|
|
plan: Plan;
|
|
streak: number;
|
|
created_at?: string;
|
|
};
|
|
|
|
let cachedMe: Me | null = null;
|
|
|
|
export function useMe(): { me: Me | null; loading: boolean; reload: () => void } {
|
|
const [me, setMe] = useState<Me | null>(cachedMe);
|
|
const [loading, setLoading] = useState(cachedMe === null);
|
|
const [version, setVersion] = useState(0);
|
|
|
|
useEffect(() => {
|
|
let cancelled = false;
|
|
(async () => {
|
|
try {
|
|
const res = await apiFetch<Me>('/api/auth/me');
|
|
if (cancelled) return;
|
|
cachedMe = res;
|
|
setMe(res);
|
|
} catch (e) {
|
|
console.warn('[useMe] fetch failed:', e);
|
|
} finally {
|
|
if (!cancelled) setLoading(false);
|
|
}
|
|
})();
|
|
return () => {
|
|
cancelled = true;
|
|
};
|
|
}, [version]);
|
|
|
|
return {
|
|
me,
|
|
loading,
|
|
reload: () => {
|
|
cachedMe = null;
|
|
setLoading(true);
|
|
setVersion((v) => v + 1);
|
|
},
|
|
};
|
|
}
|