// ----------------------------------------------------------------------------- // House-Ka — Homes-for-sale aggregator (Canada outside Québec) // Author: Simon-Pierre Boucher — contact@spboucher.ai // account.tsx : shared account context — signed-in profile + ♥ favourites. // One fetch when the app mounts; the listing page, header and account page // all read the same state. Favourites live at the Groupe KA HUB (central // "My Ka universe" store): each ♥ is optimistic on screen and pushed to the // server, which relays to the hub. Signed out → ♥ redirects to KA ID login. // ----------------------------------------------------------------------------- import { ReactNode, createContext, useCallback, useContext, useEffect, useState, } from "react"; import { Listing, User, favItemFromListing, fetchFavorites, fetchMe, toggleFavorite, } from "./api"; interface AccountState { user: User | null; enabled: boolean; // SSO configured server-side loaded: boolean; // first fetch done favs: Set; // favourite uids (hub mirror) toggleFav: (l: Listing) => void; refresh: () => void; // re-fetch profile + favourites (after login) } const Ctx = createContext({ user: null, enabled: false, loaded: false, favs: new Set(), toggleFav: () => {}, refresh: () => {}, }); export const useAccount = () => useContext(Ctx); /** Redirects to the KA ID login, returning to the current page. */ export function kaLogin() { const next = window.location.pathname + window.location.search; window.location.href = `/api/auth/ka/login?next=${encodeURIComponent(next)}`; } export function AccountProvider({ children }: { children: ReactNode }) { const [user, setUser] = useState(null); const [enabled, setEnabled] = useState(false); const [loaded, setLoaded] = useState(false); const [favs, setFavs] = useState>(new Set()); const refresh = useCallback(() => { fetchMe() .then((r) => { setUser(r.user); setEnabled(r.enabled !== false); setLoaded(true); if (r.user && r.user.ka_id) { fetchFavorites() .then((f) => setFavs(new Set(f.ids))) .catch(() => setFavs(new Set())); } else { setFavs(new Set()); } }) .catch(() => { setUser(null); setLoaded(true); }); }, []); useEffect(() => { refresh(); }, [refresh]); const toggleFav = useCallback((l: Listing) => { if (!user || !user.ka_id) { kaLogin(); return; } // ♥ = KA account required setFavs((prev) => { const next = new Set(prev); const on = !next.has(l.uid); if (on) next.add(l.uid); else next.delete(l.uid); toggleFavorite(on, favItemFromListing(l)).catch((e) => { if (String(e).includes("401")) kaLogin(); // session expired }); return next; }); }, [user]); return ( {children} ); }