Files
tm_panel/src/contexts/User.ctx.tsx
T
AmirReza Jamali 2d664795ad feat(sidebar): add calls section to navigation menu
This commit introduces a new "Calls" section to the main sidebar navigation to provide users with access to call logs.

- Adds a new collapsible "Calls" menu item to the sidebar configuration.
- Includes sub-links for "All Calls", "Incoming", "Outgoing", and "Missed" calls.
- Creates new custom icons (GlobeSearch, CallIncome, CallMade, CallMissed, CallReceived) to support the new menu items.
- Updates `apexcharts` and `react-apexcharts` dependencies to newer versions.
2025-11-04 14:12:20 +03:30

106 lines
2.9 KiB
TypeScript

"use client";
import Cookies from "js-cookie";
import React, {
createContext,
Dispatch,
ReactNode,
SetStateAction,
useCallback,
useContext,
useEffect,
useMemo,
useState,
} from "react";
import { useRouter } from "next/navigation";
import { ILoginResponse, IUser, UserSchema } from "../lib/api/types";
import { COOKIE_KEYS } from "../lib/shared/cookies";
interface UserContextType {
user: IUser | null;
accessToken: string | null;
isAuthenticated: boolean;
isLoading: boolean;
setAuthState: (data: ILoginResponse) => void;
logout: () => void;
setUser: Dispatch<SetStateAction<IUser | null>>;
}
const UserContext = createContext<UserContextType | undefined>(undefined);
interface UserProviderProps {
children: ReactNode;
}
export const UserProvider: React.FC<UserProviderProps> = ({ children }) => {
const [user, setUser] = useState<IUser | null>(null);
const [accessToken, setAccessToken] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState<boolean>(true);
const router = useRouter();
const logout = useCallback(() => {
setUser(null);
setAccessToken(null);
Cookies.remove(COOKIE_KEYS.access_token);
Cookies.remove(COOKIE_KEYS.refresh_token);
Cookies.remove(COOKIE_KEYS.user);
window.location.href = "/auth/sign-in";
}, [router]);
useEffect(() => {
try {
const tokenFromCookie = Cookies.get(COOKIE_KEYS.access_token);
const userJson = Cookies.get(COOKIE_KEYS.user);
if (tokenFromCookie && userJson) {
const userFromCookie = JSON.parse(userJson);
const validation = UserSchema.safeParse(userFromCookie);
if (validation.success) {
setUser(validation.data);
setAccessToken(tokenFromCookie);
} else {
console.warn("Invalid user data in cookie:", validation.error);
logout();
}
}
} catch (e) {
console.error("Failed to parse user data from cookies", e);
logout();
} finally {
setIsLoading(false);
}
}, [logout]);
const setAuthState = useCallback((data: ILoginResponse) => {
setAccessToken(data.access_token);
setUser(data.user);
Cookies.set(COOKIE_KEYS.access_token, data.access_token);
Cookies.set(COOKIE_KEYS.refresh_token, data.refresh_token);
Cookies.set(COOKIE_KEYS.user, JSON.stringify(data.user));
}, []);
const value = useMemo(
() => ({
user,
accessToken,
isAuthenticated: !!accessToken,
isLoading,
setAuthState,
logout,
setUser,
}),
[user, accessToken, isLoading, setAuthState, logout, setUser],
);
return <UserContext.Provider value={value}>{children}</UserContext.Provider>;
};
export const useUser = (): UserContextType => {
const context = useContext(UserContext);
if (context === undefined) {
throw new Error("useUser must be used within a UserProvider");
}
return context;
};