if any user start the tracking , not login other devices and the expire token then the logout
This commit is contained in:
parent
b56a6e11c4
commit
44d790abab
|
|
@ -2,6 +2,7 @@
|
|||
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
|
||||
import { getToken } from '../utils/tokenHelper.js';
|
||||
import chalk from "chalk";
|
||||
import { sendTokenExpired } from '../ipc/ipcHandler.js';
|
||||
|
||||
const TOKEN_KEY = 'ACCESS_TOKEN';
|
||||
|
||||
|
|
@ -37,6 +38,7 @@ api.interceptors.response.use(
|
|||
console.error('[Axios Error]', error.message);
|
||||
if (error.response?.status === 401) {
|
||||
console.warn('Token expired — trigger refresh logic if needed');
|
||||
sendTokenExpired();
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@ import { getActiveApp, handleLogin, takeScreenshot, startWindowPolling } from ".
|
|||
import api from "../api/axiosClient.js";
|
||||
import { getMainWindow } from '../main.js';
|
||||
|
||||
|
||||
|
||||
|
||||
export const registerIPCHandlers = (mainWindow: BrowserWindow) => {
|
||||
console.log("⚙️ Registering IPC Handlers...");
|
||||
|
||||
|
|
@ -44,6 +47,10 @@ export const registerIPCHandlers = (mainWindow: BrowserWindow) => {
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
ipcMain.handle("get-active-app", async () => {
|
||||
return await getActiveApp();
|
||||
});
|
||||
|
|
@ -80,15 +87,16 @@ ipcMain.handle("get-project-list", async () => {
|
|||
try {
|
||||
const res = await api.get("/list/projects");
|
||||
|
||||
// console.log(" API /list/project response:", res);
|
||||
console.log(" API /list/project response:", res);
|
||||
|
||||
// Return only serializable data
|
||||
return JSON.parse(JSON.stringify(res));
|
||||
} catch (error: any) {
|
||||
console.error(" get-project-list error:", error);
|
||||
console.error(" get-project-list error:", error.status);
|
||||
return {
|
||||
success: false,
|
||||
message: error?.message || String(error) || "Unknown error"
|
||||
message: error?.message || String(error) || "Unknown error",
|
||||
status:error?.status
|
||||
};
|
||||
}
|
||||
});
|
||||
|
|
@ -264,3 +272,14 @@ ipcMain.handle("change-password", async (event, data) => {
|
|||
};
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
export const sendTokenExpired = () => {
|
||||
console.log("⚠️ Sending token-expired event to renderer");
|
||||
|
||||
BrowserWindow.getAllWindows().forEach((win) => {
|
||||
if (!win.isDestroyed()) {
|
||||
win.webContents.send("token-expired");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -95,3 +95,4 @@ function handleCloseEvents(mainWindow: BrowserWindow) {
|
|||
export function getMainWindow() {
|
||||
return mainWindow;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,22 +15,34 @@ contextBridge.exposeInMainWorld('electron', {
|
|||
onWindowUpdate: (callback) =>
|
||||
ipcRenderer.on("window:updated", (_, data) => callback(data)),
|
||||
|
||||
|
||||
startProjectTracking: (data) => ipcRenderer.invoke("start-project-tracking", data),
|
||||
stopProjectTracking: (data) => ipcRenderer.invoke("stop-project-tracking", data),
|
||||
trackingTabsOpeningClosing: (data) =>
|
||||
ipcRenderer.invoke("tracking-tabs-opening-and-closing", data),
|
||||
|
||||
getProjectLogs: (
|
||||
projectID: string,
|
||||
fromDate?: string,
|
||||
toDate?: string
|
||||
) => ipcRenderer.invoke("get-project-logs", { projectID, fromDate, toDate }),
|
||||
projectID: string,
|
||||
fromDate?: string,
|
||||
toDate?: string
|
||||
) => ipcRenderer.invoke("get-project-logs", { projectID, fromDate, toDate }),
|
||||
|
||||
getProfile: () => ipcRenderer.invoke("get-profile"),
|
||||
getProfile: () => ipcRenderer.invoke("get-profile"),
|
||||
|
||||
changePassword: (data: { oldPassword: string; password: string; cPassword: string }) =>
|
||||
changePassword: (data: { oldPassword: string; password: string; cPassword: string }) =>
|
||||
ipcRenderer.invoke("change-password", data),
|
||||
|
||||
onTokenExpired: (callback) => {
|
||||
// Remove old listeners
|
||||
ipcRenderer.removeAllListeners("token-expired");
|
||||
|
||||
// Add single-use listener
|
||||
ipcRenderer.once("token-expired", () => {
|
||||
console.log("⚠️ Token expired event received in PRELOAD (ONE TIME)");
|
||||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
} satisfies Window['electron']);
|
||||
|
||||
// function ipcInvoke<Key extends keyof EventPayloadMapping>(
|
||||
|
|
|
|||
|
|
@ -115,3 +115,5 @@ export const startWindowPolling = (win: BrowserWindow) => {
|
|||
}
|
||||
}, 5000);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ const App: React.FC = () => {
|
|||
const theme = ThemeToggle();
|
||||
const dispatch = useDispatch<AppDispatch>();
|
||||
|
||||
|
||||
|
||||
// ✅ Get user directly from Redux
|
||||
const user = useSelector((state: RootState) => state.user.user);
|
||||
|
||||
|
|
|
|||
|
|
@ -126,6 +126,24 @@ const DashboardLayout = () => {
|
|||
|
||||
const [projectsData, setProjectsData] = useState<Project[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!window.electron?.onTokenExpired) return;
|
||||
|
||||
console.log("🔐 Token expiry listener registered");
|
||||
|
||||
window.electron.onTokenExpired(() => {
|
||||
console.log("🔥 Token expired — logging out...");
|
||||
handleLogout();
|
||||
});
|
||||
|
||||
return () => {
|
||||
console.log("🧹 Cleaning token-expired listener");
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
|
||||
|
||||
const fetchProfile = async () => {
|
||||
try {
|
||||
dispatch(setLoading(true));
|
||||
|
|
@ -210,10 +228,13 @@ const DashboardLayout = () => {
|
|||
// Set the initial elapsed time in the component state
|
||||
setElapsedTime(initialElapsedTime);
|
||||
}
|
||||
fetchProfile()
|
||||
fetchProfile()
|
||||
|
||||
} else {
|
||||
console.warn("⚠️ Unexpected response:", res);
|
||||
// if (res?.status) {
|
||||
// // handleLogout()
|
||||
// }
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("❌ Error fetching projects:", err);
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ interface ProjectListResponse {
|
|||
totalWorkTime?: string;
|
||||
totalWorkMs?: number;
|
||||
data?: any[]; // you can replace `any[]` with a typed array later
|
||||
status : number
|
||||
}
|
||||
|
||||
interface TabActivity {
|
||||
|
|
@ -142,7 +143,7 @@ interface Window {
|
|||
}) => Promise<{ success: boolean; message?: string; data?: any }>;
|
||||
|
||||
|
||||
|
||||
onTokenExpired: (callback: () => void) => void;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue