115 lines
3.6 KiB
TypeScript
115 lines
3.6 KiB
TypeScript
'use client';
|
|
|
|
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
|
|
|
const SELECTED_FAMILY_STORAGE_KEY = 'id-selected-family-group-id';
|
|
|
|
type FamilyOverlayContextValue = {
|
|
openMiniChat: () => void;
|
|
openChatRoom: (roomId: string) => void;
|
|
openChatWithMember: (memberUserId: string, memberName: string, options?: { isBot?: boolean; botUsername?: string }) => void;
|
|
closeMiniChat: () => void;
|
|
miniChatOpen: boolean;
|
|
pendingRoomId: string | null;
|
|
pendingMember: { userId: string; name: string; isBot?: boolean; botUsername?: string } | null;
|
|
clearPending: () => void;
|
|
selectedGroupId: string | null;
|
|
setSelectedGroupId: (groupId: string | null) => void;
|
|
};
|
|
|
|
const FamilyOverlayContext = createContext<FamilyOverlayContextValue | null>(null);
|
|
|
|
export function FamilyOverlayProvider({ children }: { children: React.ReactNode }) {
|
|
const [miniChatOpen, setMiniChatOpen] = useState(false);
|
|
const [pendingRoomId, setPendingRoomId] = useState<string | null>(null);
|
|
const [pendingMember, setPendingMember] = useState<{ userId: string; name: string; isBot?: boolean; botUsername?: string } | null>(null);
|
|
const [selectedGroupId, setSelectedGroupIdState] = useState<string | null>(null);
|
|
const pendingMemberRef = useRef<{ userId: string; name: string; isBot?: boolean; botUsername?: string } | null>(null);
|
|
const selectionHydratedRef = useRef(false);
|
|
|
|
useEffect(() => {
|
|
if (selectionHydratedRef.current) return;
|
|
selectionHydratedRef.current = true;
|
|
const stored = window.localStorage.getItem(SELECTED_FAMILY_STORAGE_KEY);
|
|
if (stored) setSelectedGroupIdState(stored);
|
|
}, []);
|
|
|
|
const setSelectedGroupId = useCallback((groupId: string | null) => {
|
|
setSelectedGroupIdState(groupId);
|
|
if (groupId) {
|
|
window.localStorage.setItem(SELECTED_FAMILY_STORAGE_KEY, groupId);
|
|
} else {
|
|
window.localStorage.removeItem(SELECTED_FAMILY_STORAGE_KEY);
|
|
}
|
|
}, []);
|
|
|
|
const openMiniChat = useCallback(() => {
|
|
setMiniChatOpen(true);
|
|
}, []);
|
|
|
|
const closeMiniChat = useCallback(() => {
|
|
setMiniChatOpen(false);
|
|
}, []);
|
|
|
|
const openChatRoom = useCallback((roomId: string) => {
|
|
setPendingRoomId(roomId);
|
|
setPendingMember(null);
|
|
pendingMemberRef.current = null;
|
|
setMiniChatOpen(true);
|
|
}, []);
|
|
|
|
const openChatWithMember = useCallback(
|
|
(memberUserId: string, memberName: string, options?: { isBot?: boolean; botUsername?: string }) => {
|
|
const payload = { userId: memberUserId, name: memberName, ...options };
|
|
setPendingMember(payload);
|
|
pendingMemberRef.current = payload;
|
|
setPendingRoomId(null);
|
|
setMiniChatOpen(true);
|
|
},
|
|
[]
|
|
);
|
|
|
|
const clearPending = useCallback(() => {
|
|
setPendingRoomId(null);
|
|
setPendingMember(null);
|
|
pendingMemberRef.current = null;
|
|
}, []);
|
|
|
|
const value = useMemo(
|
|
() => ({
|
|
openMiniChat,
|
|
openChatRoom,
|
|
openChatWithMember,
|
|
closeMiniChat,
|
|
miniChatOpen,
|
|
pendingRoomId,
|
|
pendingMember,
|
|
clearPending,
|
|
selectedGroupId,
|
|
setSelectedGroupId
|
|
}),
|
|
[
|
|
clearPending,
|
|
closeMiniChat,
|
|
miniChatOpen,
|
|
openChatRoom,
|
|
openChatWithMember,
|
|
openMiniChat,
|
|
pendingMember,
|
|
pendingRoomId,
|
|
selectedGroupId,
|
|
setSelectedGroupId
|
|
]
|
|
);
|
|
|
|
return <FamilyOverlayContext.Provider value={value}>{children}</FamilyOverlayContext.Provider>;
|
|
}
|
|
|
|
export function useFamilyOverlay() {
|
|
const context = useContext(FamilyOverlayContext);
|
|
if (!context) {
|
|
throw new Error('useFamilyOverlay must be used within FamilyOverlayProvider');
|
|
}
|
|
return context;
|
|
}
|