128 lines
3.4 KiB
TypeScript
128 lines
3.4 KiB
TypeScript
import { useMTP } from "@tensamin/mtp";
|
|
import {
|
|
createContext,
|
|
type ReactNode,
|
|
useState,
|
|
useContext,
|
|
useEffect,
|
|
} from "react";
|
|
import { useStorage } from "./context";
|
|
import type { Contacts, Communities, Calls } from "@tensamin/shared/data";
|
|
|
|
interface SessionContextType {
|
|
contacts: Contacts;
|
|
communities: Communities;
|
|
calls: Calls;
|
|
moveUserIdToTop: (userId: number) => void;
|
|
insertContact: (userId: number) => void;
|
|
insertCall: (call: Calls[number]) => void;
|
|
}
|
|
|
|
const SessionContext = createContext<SessionContextType | undefined>(undefined);
|
|
|
|
export default function SessionProvider({ children }: { children: ReactNode }) {
|
|
const { freshContacts, freshCommunities, freshCalls } = useMTP();
|
|
const { load, save } = useStorage();
|
|
const [contacts, setContacts] = useState<Contacts>([]);
|
|
const [communities, setCommunities] = useState<Communities>([]);
|
|
const [localCalls, setLocalCalls] = useState<Calls>([]);
|
|
const calls = [
|
|
...freshCalls,
|
|
...localCalls.filter(
|
|
(call) => !freshCalls.some((fresh) => fresh.CallId === call.CallId),
|
|
),
|
|
];
|
|
|
|
// Cached session data fills in items the server did not return freshly.
|
|
useEffect(() => {
|
|
load("cached_contacts").then((cachedData) => {
|
|
setContacts([
|
|
...freshContacts,
|
|
...cachedData.filter(
|
|
(item) =>
|
|
!freshContacts.some((fresh) => fresh.UserId === item.UserId),
|
|
),
|
|
]);
|
|
});
|
|
load("cached_communities").then((cachedData) => {
|
|
if (cachedData && freshCommunities) {
|
|
setCommunities([
|
|
...freshCommunities,
|
|
...cachedData.filter(
|
|
(item) =>
|
|
!freshCommunities.some(
|
|
(fresh) => fresh.community_id === item.community_id,
|
|
),
|
|
),
|
|
]);
|
|
}
|
|
});
|
|
}, [load, freshContacts, freshCommunities]);
|
|
|
|
useEffect(() => {
|
|
save("cached_contacts", contacts);
|
|
}, [contacts, save]);
|
|
useEffect(() => {
|
|
save("cached_communities", communities);
|
|
}, [communities, save]);
|
|
|
|
const moveUserIdToTop = (userId: number) => {
|
|
setContacts((prevContacts) => {
|
|
const userIndex = prevContacts.findIndex(
|
|
(contact) => contact.UserId === userId,
|
|
);
|
|
if (userIndex === -1) return prevContacts;
|
|
const [user] = prevContacts.splice(userIndex, 1);
|
|
return [user, ...prevContacts];
|
|
});
|
|
};
|
|
|
|
const insertContact = (userId: number) => {
|
|
setContacts((prevContacts) => {
|
|
if (prevContacts.some((contact) => contact.UserId === userId)) {
|
|
return prevContacts;
|
|
}
|
|
|
|
const newUser = {
|
|
UserId: userId,
|
|
LastMessageAt: new Date().getTime(),
|
|
Messages: [],
|
|
} satisfies Contacts[0];
|
|
|
|
return [newUser, ...prevContacts];
|
|
});
|
|
};
|
|
|
|
const insertCall = (call: Calls[number]) => {
|
|
setLocalCalls((prevCalls) => {
|
|
if (prevCalls.some((prevCall) => prevCall.CallId === call.CallId)) {
|
|
return prevCalls;
|
|
}
|
|
|
|
return [call, ...prevCalls];
|
|
});
|
|
};
|
|
|
|
return (
|
|
<SessionContext.Provider
|
|
value={{
|
|
contacts,
|
|
communities,
|
|
calls,
|
|
moveUserIdToTop,
|
|
insertContact,
|
|
insertCall,
|
|
}}
|
|
>
|
|
{children}
|
|
</SessionContext.Provider>
|
|
);
|
|
}
|
|
|
|
export function useSession(): SessionContextType {
|
|
const context = useContext(SessionContext);
|
|
if (context === undefined) {
|
|
throw new Error("useSession must be used within a SessionProvider");
|
|
}
|
|
return context;
|
|
}
|