logout error

This commit is contained in:
JaiPandey425 2025-11-06 17:01:59 +05:30
parent 6783fba264
commit ec383c109f
5 changed files with 87 additions and 64 deletions

View File

@ -5,34 +5,35 @@ import { getToken } from '../utils/tokenHelper.js';
const TOKEN_KEY = 'auth_token'; const TOKEN_KEY = 'auth_token';
const api: AxiosInstance = axios.create({ const api: AxiosInstance = axios.create({
baseURL: 'https://api.example.com', // 🔁 your backend baseURL: 'https://wired-terminally-muskrat.ngrok-free.app/api/v1', // 🔁 your backend
timeout: 10000, timeout: 10000,
}); });
// --- Request Interceptor --- // --- Request Interceptor ---
api.interceptors.request.use( api.interceptors.request.use(
async (config: AxiosRequestConfig) : Promise<any> => { async (config: AxiosRequestConfig): Promise<any> => {
const token = await getToken(TOKEN_KEY); const token = await getToken(TOKEN_KEY);
if (token && config.headers) { if (token && config.headers) {
config.headers.Authorization = `Bearer ${token}`; config.headers.token = token;
} config.headers['ngrok-skip-browser-warning'] = 98098;
}
console.log(`[Axios] ${config.method?.toUpperCase()} ${config.url}`); console.log(`[Axios] ${config.method?.toUpperCase()} ${config.url}`);
return config; return config;
}, },
(error) => Promise.reject(error) (error) => Promise.reject(error)
); );
// --- Response Interceptor --- // --- Response Interceptor ---
api.interceptors.response.use( api.interceptors.response.use(
(response: AxiosResponse) => response.data, (response: AxiosResponse) => response.data,
async (error) => { async (error) => {
console.error('[Axios Error]', error.message); console.error('[Axios Error]', error.message);
if (error.response?.status === 401) { if (error.response?.status === 401) {
console.warn('Token expired — trigger refresh logic if needed'); console.warn('Token expired — trigger refresh logic if needed');
}
return Promise.reject(error);
} }
return Promise.reject(error);
}
); );
export default api; export default api;

View File

@ -2,6 +2,7 @@
import { ipcMain } from 'electron'; import { ipcMain } from 'electron';
import { getToken, saveToken, clearToken } from '../utils/tokenHelper.js'; import { getToken, saveToken, clearToken } from '../utils/tokenHelper.js';
import { handleLogin, takeScreenshot } from '../utils/utilityFunctions.js'; import { handleLogin, takeScreenshot } from '../utils/utilityFunctions.js';
import api from '../api/axiosClient.js';
ipcMain.handle('get-token', async (_, TOKEN_KEY: string) => { ipcMain.handle('get-token', async (_, TOKEN_KEY: string) => {
return await getToken(TOKEN_KEY); return await getToken(TOKEN_KEY);
@ -25,4 +26,11 @@ ipcMain.handle('upload-screenshot', async () => {
// Handle login request from renderer // Handle login request from renderer
ipcMain.handle('login-request', async (event, credentials: { email: string, password: string }) => { ipcMain.handle('login-request', async (event, credentials: { email: string, password: string }) => {
return handleLogin(credentials); return handleLogin(credentials);
});
ipcMain.handle('logout-request', async () => {
(async () => {
console.log("Handle Logout listened")
await api.get("/logout");
})()
}); });

View File

@ -16,7 +16,11 @@ contextBridge.exposeInMainWorld('electron', {
}), }),
getStaticData: () => ipcInvoke('getStaticData'), getStaticData: () => ipcInvoke('getStaticData'),
sendFrameAction: (payload) => ipcSend('sendFrameAction', payload), sendFrameAction: (payload) => ipcSend('sendFrameAction', payload),
login: (credentials: { email: string, password: string }) => ipcRenderer.invoke('login-request', credentials), login: (credentials: { email: string, password: string }) => ipcRenderer.invoke('login-request', credentials),
logout: () => ipcRenderer.invoke('logout-request'),
getToken: (TOKEN_KEY: string) => ipcRenderer.invoke('get-token', TOKEN_KEY), getToken: (TOKEN_KEY: string) => ipcRenderer.invoke('get-token', TOKEN_KEY),
uploadScreenshot: () => ipcRenderer.invoke('upload-screenshot'), uploadScreenshot: () => ipcRenderer.invoke('upload-screenshot'),
} satisfies Window['electron']); } satisfies Window['electron']);

View File

@ -68,25 +68,25 @@ const DashboardLayout: React.FC<DashboardLayoutProps> = ({ setUser }) => {
const navigate = useNavigate(); const navigate = useNavigate();
const location = useLocation(); const location = useLocation();
// Tracking states // Tracking states
const [selectedProject, setSelectedProject] = useState<Project | null>(null); const [selectedProject, setSelectedProject] = useState<Project | null>(null);
const [isTracking, setIsTracking] = useState(false); const [isTracking, setIsTracking] = useState(false);
const [isPaused, setIsPaused] = useState(false); const [isPaused, setIsPaused] = useState(false);
const [elapsedTime, setElapsedTime] = useState(0); const [elapsedTime, setElapsedTime] = useState(0);
const [startTime, setStartTime] = useState<Date | null>(null); const [startTime, setStartTime] = useState<Date | null>(null);
const [endTime, setEndTime] = useState<Date | null>(null); const [endTime, setEndTime] = useState<Date | null>(null);
const timerRef = useRef<ReturnType<typeof setInterval> | null>(null); const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);
const [projectsData, setProjectsData] = useState<Project[]>([ const [projectsData, setProjectsData] = useState<Project[]>([
{ id: 1, projectName: "CRM Redesign", clientName: "Salesforce" }, { id: 1, projectName: "CRM Redesign", clientName: "Salesforce" },
{ id: 2, projectName: "AI Assistant", clientName: "OpenAI" }, { id: 2, projectName: "AI Assistant", clientName: "OpenAI" },
{ id: 3, projectName: "Marketing Dashboard", clientName: "Google" }, { id: 3, projectName: "Marketing Dashboard", clientName: "Google" },
]); ]);
const [projectTrackingMap, setProjectTrackingMap] = useState< const [projectTrackingMap, setProjectTrackingMap] = useState<
Map<number, ProjectTrackingData> Map<number, ProjectTrackingData>
>(new Map()); >(new Map());
useEffect(() => { useEffect(() => {
const handleResize = () => { const handleResize = () => {
@ -100,9 +100,20 @@ const DashboardLayout: React.FC<DashboardLayoutProps> = ({ setUser }) => {
return () => window.removeEventListener("resize", handleResize); return () => window.removeEventListener("resize", handleResize);
}, []); }, []);
const handleLogout = () => { const handleLogout = async () => {
localStorage.removeItem("user"); localStorage.removeItem("user");
setUser(null); setUser(null);
console.log("calling Logout UI")
try {
const res = await window.electron.logout()
console.log(res)
} catch (error) {
console.log(error)
}
navigate("/login"); navigate("/login");
}; };
@ -122,7 +133,7 @@ const DashboardLayout: React.FC<DashboardLayoutProps> = ({ setUser }) => {
]; ];
// Sync global states with selected project tracking data // Sync global states with selected project tracking data
useEffect(() => { useEffect(() => {
if (selectedProject) { if (selectedProject) {
const projectData = projectTrackingMap.get(selectedProject.id); const projectData = projectTrackingMap.get(selectedProject.id);
@ -159,7 +170,7 @@ const DashboardLayout: React.FC<DashboardLayoutProps> = ({ setUser }) => {
current.isTracking = true; current.isTracking = true;
current.isPaused = false; current.isPaused = false;
updated.set(project.id, current); updated.set(project.id, current);
return updated; return updated;
}); });
@ -173,7 +184,7 @@ const DashboardLayout: React.FC<DashboardLayoutProps> = ({ setUser }) => {
setProjectTrackingMap((prev) => { setProjectTrackingMap((prev) => {
const updated = new Map(prev); const updated = new Map(prev);
const current = updated.get(project.id); const current = updated.get(project.id);
// Only increment when tracking AND not paused // Only increment when tracking AND not paused
if (current && current.isTracking && !current.isPaused) { if (current && current.isTracking && !current.isPaused) {
current.elapsedTime += 1; current.elapsedTime += 1;
@ -187,25 +198,25 @@ const DashboardLayout: React.FC<DashboardLayoutProps> = ({ setUser }) => {
// Pause/Resume tracking // Pause/Resume tracking
const handlePauseResume = () => { const handlePauseResume = () => {
if (!selectedProject) return; if (!selectedProject) return;
// Get current state before toggling to avoid double-click issues // Get current state before toggling to avoid double-click issues
const currentProjectData = projectTrackingMap.get(selectedProject.id); const currentProjectData = projectTrackingMap.get(selectedProject.id);
if (!currentProjectData || !currentProjectData.isTracking) return; if (!currentProjectData || !currentProjectData.isTracking) return;
const newPausedState = !currentProjectData.isPaused; const newPausedState = !currentProjectData.isPaused;
setProjectTrackingMap((prev) => { setProjectTrackingMap((prev) => {
const updated = new Map(prev); const updated = new Map(prev);
const current = updated.get(selectedProject.id); const current = updated.get(selectedProject.id);
if (!current) return updated; if (!current) return updated;
// Set the new pause state // Set the new pause state
current.isPaused = newPausedState; current.isPaused = newPausedState;
updated.set(selectedProject.id, { ...current }); updated.set(selectedProject.id, { ...current });
return updated; return updated;
}); });
// Update global isPaused state immediately // Update global isPaused state immediately
setIsPaused(newPausedState); setIsPaused(newPausedState);
}; };
@ -231,7 +242,7 @@ const DashboardLayout: React.FC<DashboardLayoutProps> = ({ setUser }) => {
current.isPaused = false; current.isPaused = false;
current.endTime = now; current.endTime = now;
updated.set(selectedProject.id, { ...current }); updated.set(selectedProject.id, { ...current });
return updated; return updated;
}); });
@ -240,7 +251,7 @@ const DashboardLayout: React.FC<DashboardLayoutProps> = ({ setUser }) => {
setIsPaused(false); setIsPaused(false);
setEndTime(new Date()); setEndTime(new Date());
console.log("projectTrackingMap",projectTrackingMap) console.log("projectTrackingMap", projectTrackingMap)
}; };
// Cleanup timer on unmount // Cleanup timer on unmount
@ -256,11 +267,11 @@ const DashboardLayout: React.FC<DashboardLayoutProps> = ({ setUser }) => {
const handleProjectSelect = (id: number) => { const handleProjectSelect = (id: number) => {
// Only allow project selection when not tracking // Only allow project selection when not tracking
if (isTracking) return; if (isTracking) return;
const project = projectsData.find((p) => p.id === id); const project = projectsData.find((p) => p.id === id);
if (project) { if (project) {
setSelectedProject(project); setSelectedProject(project);
// Load existing tracking data if available // Load existing tracking data if available
const projectData = projectTrackingMap.get(id); const projectData = projectTrackingMap.get(id);
if (projectData) { if (projectData) {
@ -302,12 +313,11 @@ const DashboardLayout: React.FC<DashboardLayoutProps> = ({ setUser }) => {
className={` className={`
fixed md:relative inset-y-0 left-0 z-40 transform fixed md:relative inset-y-0 left-0 z-40 transform
bg-base-100 border-r border-t border-base-300 transition-all duration-300 ease-in-out bg-base-100 border-r border-t border-base-300 transition-all duration-300 ease-in-out
${ ${isMobile
isMobile ? isSidebarOpen
? isSidebarOpen ? "translate-x-0 w-64"
? "translate-x-0 w-64" : "-translate-x-full w-64"
: "-translate-x-full w-64" : isSidebarOpen
: isSidebarOpen
? "w-50" ? "w-50"
: "w-20" : "w-20"
} }
@ -339,10 +349,9 @@ const DashboardLayout: React.FC<DashboardLayoutProps> = ({ setUser }) => {
to={item.path} to={item.path}
end={item.exact} end={item.exact}
className={({ isActive }) => className={({ isActive }) =>
`flex items-center gap-3 my-1 font-medium transition-all duration-150 ${ `flex items-center gap-3 my-1 font-medium transition-all duration-150 ${isActive
isActive ? "bg-primary text-primary-content rounded-lg"
? "bg-primary text-primary-content rounded-lg" : "hover:bg-base-300 rounded-lg"
: "hover:bg-base-300 rounded-lg"
}` }`
} }
onClick={closeSidebarOnMobile} onClick={closeSidebarOnMobile}
@ -380,8 +389,8 @@ const DashboardLayout: React.FC<DashboardLayoutProps> = ({ setUser }) => {
{location.pathname.includes("projects") {location.pathname.includes("projects")
? "Projects" ? "Projects"
: location.pathname.includes("leave-adjustments") : location.pathname.includes("leave-adjustments")
? "Leave & Adjustments" ? "Leave & Adjustments"
: "Dashboard"} : "Dashboard"}
</span> </span>
</div> </div>
@ -418,7 +427,7 @@ const DashboardLayout: React.FC<DashboardLayoutProps> = ({ setUser }) => {
{/* Page Content */} {/* Page Content */}
<main className="flex-1 overflow-y-auto p-4 md:px-6 no-scrollbar"> <main className="flex-1 overflow-y-auto p-4 md:px-6 no-scrollbar">
<Outlet context={trackingState}/> <Outlet context={trackingState} />
</main> </main>
</div> </div>
</div> </div>

1
types.d.ts vendored
View File

@ -34,6 +34,7 @@ interface Window {
) => UnsubscribeFunction; ) => UnsubscribeFunction;
sendFrameAction: (payload: FrameWindowAction) => void; sendFrameAction: (payload: FrameWindowAction) => void;
login: (credentials: { email: string; password: string }) => Promise<any>; login: (credentials: { email: string; password: string }) => Promise<any>;
logout: () => {};
getToken: (tokenKey: string) => Promise<string | null>; getToken: (tokenKey: string) => Promise<string | null>;
uploadScreenshot: () => {}; uploadScreenshot: () => {};
}; };