NuvioStreaming/src/contexts/AccountContext.tsx
2025-08-09 00:51:12 +05:30

97 lines
3.2 KiB
TypeScript

import React, { createContext, useContext, useEffect, useMemo, useState } from 'react';
import accountService, { AuthUser } from '../services/AccountService';
import supabase from '../services/supabaseClient';
import syncService from '../services/SyncService';
type AccountContextValue = {
user: AuthUser | null;
loading: boolean;
signIn: (email: string, password: string) => Promise<string | null>;
signUp: (email: string, password: string) => Promise<string | null>;
signOut: () => Promise<void>;
updateProfile: (partial: { avatarUrl?: string; displayName?: string }) => Promise<string | null>;
};
const AccountContext = createContext<AccountContextValue | undefined>(undefined);
export const AccountProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [user, setUser] = useState<AuthUser | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
// Initial session (load full profile)
(async () => {
const u = await accountService.getCurrentUser();
setUser(u);
setLoading(false);
syncService.init();
if (u) {
await syncService.migrateLocalScopeToUser();
await syncService.subscribeRealtime();
// Pull first to hydrate local state, then push to avoid wiping server with empty local
await syncService.fullPull();
await syncService.fullPush();
}
})();
// Auth state listener
const { data: subscription } = supabase.auth.onAuthStateChange(async (_event, session) => {
const fullUser = session?.user ? await accountService.getCurrentUser() : null;
setUser(fullUser);
if (fullUser) {
await syncService.migrateLocalScopeToUser();
await syncService.subscribeRealtime();
// Pull first to hydrate local state, then push to avoid wiping server with empty local
await syncService.fullPull();
await syncService.fullPush();
} else {
syncService.unsubscribeRealtime();
}
});
return () => {
subscription.subscription.unsubscribe();
};
}, []);
const value = useMemo<AccountContextValue>(() => ({
user,
loading,
signIn: async (email: string, password: string) => {
const { error } = await accountService.signInWithEmail(email, password);
return error || null;
},
signUp: async (email: string, password: string) => {
const { error } = await accountService.signUpWithEmail(email, password);
return error || null;
},
signOut: async () => {
await accountService.signOut();
setUser(null);
},
updateProfile: async (partial) => {
const err = await accountService.updateProfile(partial);
if (!err) {
// Refresh user from server to pick updated fields
const u = await accountService.getCurrentUser();
setUser(u);
}
return err;
}
}), [user, loading]);
return (
<AccountContext.Provider value={value}>
{children}
</AccountContext.Provider>
);
};
export const useAccount = (): AccountContextValue => {
const ctx = useContext(AccountContext);
if (!ctx) throw new Error('useAccount must be used within AccountProvider');
return ctx;
};
export default AccountContext;