Files
smart-go/web/lib/hooks/use-user-profile.ts
2026-04-23 18:58:13 +08:00

98 lines
2.6 KiB
TypeScript

'use client';
import { useEffect, useState } from 'react';
import { introspectAccessToken } from '@/lib/api/auth';
import { iamUser } from '@/lib/api/iam';
import type { IamUser } from '@/lib/api/types/user';
import { useAuthStore } from '@/stores/auth-store';
import { useTenantStore } from '@/stores/tenant-store';
type UserProfileState = {
profile: IamUser | null;
userSub: string | null;
loading: boolean;
label: string;
};
function displayLabel(profile: IamUser | null, userSub: string | null, loading: boolean): string {
if (loading) return '加载中…';
if (profile) {
const n = profile.real_name?.trim() || profile.user_name?.trim();
if (n) return n;
}
if (userSub) return userSub.length > 12 ? `${userSub.slice(0, 10)}` : userSub;
return '用户';
}
/** 从 UserMenu 提取的用户资料获取逻辑 */
export function useUserProfile(): UserProfileState {
const accessToken = useAuthStore((s) => s.accessToken);
const [profile, setProfile] = useState<IamUser | null>(null);
const [userSub, setUserSub] = useState<string | null>(null);
const [loading, setLoading] = useState(false);
useEffect(() => {
if (!accessToken) {
setProfile(null);
setUserSub(null);
setLoading(false);
return;
}
let cancelled = false;
setLoading(true);
setProfile(null);
setUserSub(null);
(async () => {
try {
const intro = await introspectAccessToken(accessToken);
if (cancelled) return;
if (!intro.active || !intro.sub) {
setUserSub(null);
setLoading(false);
return;
}
setUserSub(intro.sub);
try {
const u = await iamUser.get(intro.sub);
if (!cancelled) {
setProfile(u);
useTenantStore.getState().hydrateFromUserTenant(u.tenant_id);
}
} catch {
if (!cancelled) setProfile(null);
}
} catch {
if (!cancelled) {
setUserSub(null);
setProfile(null);
}
} finally {
if (!cancelled) setLoading(false);
}
})();
return () => {
cancelled = true;
};
}, [accessToken]);
return {
profile,
userSub,
loading,
label: displayLabel(profile, userSub, loading),
};
}
export function avatarInitials(profile: IamUser | null, userSub: string | null): string {
const name = profile?.real_name?.trim() || profile?.user_name?.trim();
if (name) {
const arr = [...name];
if (arr.length >= 2) return (arr[0] + arr[1]).toUpperCase();
return name.slice(0, 2).toUpperCase();
}
if (userSub) return userSub.replace(/-/g, '').slice(0, 2).toUpperCase() || '?';
return '?';
}