diff --git a/.env b/.env new file mode 100644 index 0000000..e69de29 diff --git a/src/electron/api/axiosClient.ts b/src/electron/api/axiosClient.ts index 53b5896..cc0acd5 100644 --- a/src/electron/api/axiosClient.ts +++ b/src/electron/api/axiosClient.ts @@ -71,4 +71,4 @@ api.interceptors.response.use( } ); -export default api; +export default api; \ No newline at end of file diff --git a/src/electron/api/regionCheck.ts b/src/electron/api/regionCheck.ts new file mode 100644 index 0000000..e4d1c45 --- /dev/null +++ b/src/electron/api/regionCheck.ts @@ -0,0 +1,57 @@ + +import axios from "axios"; +import https from "https"; + +const httpsAgent = new https.Agent({ rejectUnauthorized: false }); + +export const checkRegion = async () => { + const baseURL = "https://daniela-nonprofessed-boastfully.ngrok-free.app"; + + try { + + const res = await axios.get(`${baseURL}/health`, { + headers: { "ngrok-skip-browser-warning": "true" }, + httpsAgent + }); + + return { + success: true, + status: res.status, + data: res.data + }; + + } catch (error: any) { + const status = error?.response?.status || 500; + + console.log("Region Check Error:", status); + + // 🔁 Auto retry if 403 — server blocked first try + if (status === 403) { + try { + const retry = await axios.get(`${baseURL}/api`, { + headers: { "ngrok-skip-browser-warning": "true" }, + httpsAgent + }); + + return { + success: true, + status: retry.status, + data: retry.data, + retry: true + }; + } catch (retryErr: any) { + return { + success: false, + status: retryErr?.response?.status || 500, + message: "403 Retry failed" + }; + } + } + + return { + success: false, + status, + message: "Region check failed" + }; + } +}; diff --git a/src/electron/ipc/ipcHandler.ts b/src/electron/ipc/ipcHandler.ts index edaa1df..8465665 100644 --- a/src/electron/ipc/ipcHandler.ts +++ b/src/electron/ipc/ipcHandler.ts @@ -3,6 +3,7 @@ import { getToken, saveToken, clearToken } from "../utils/tokenHelper.js"; import { getActiveApp, handleLogin, takeScreenshot, startWindowPolling, getRunningAppsList, captureSpecificApp } from "../utils/utilityFunctions.js"; import api from "../api/axiosClient.js"; import { getMainWindow } from '../main.js'; +import { checkRegion } from "../api/regionCheck.js"; @@ -10,6 +11,8 @@ import { getMainWindow } from '../main.js'; export const registerIPCHandlers = (mainWindow: BrowserWindow) => { console.log("⚙️ Registering IPC Handlers..."); + + ipcMain.handle("get-token", async (_, key: "ACCESS_TOKEN" | "REFRESH_TOKEN") => { return await getToken(key); }); @@ -534,6 +537,11 @@ ipcMain.handle("update-payment", async (event, data: Record) => { +ipcMain.handle("check-region", async () => { + return await checkRegion(); +}); + + export const sendTokenExpired = () => { console.log("⚠️ Sending token-expired event to renderer"); diff --git a/src/electron/preload.cts b/src/electron/preload.cts index 870cf71..171a4ef 100644 --- a/src/electron/preload.cts +++ b/src/electron/preload.cts @@ -65,6 +65,8 @@ contextBridge.exposeInMainWorld('electron', { getLeaveList: () => ipcRenderer.invoke("get-leave-list"), getAdjustmentsList:(vaId: string) => ipcRenderer.invoke("get-adjustments-list",vaId), + checkRegion: () => ipcRenderer.invoke("check-region") + } satisfies Window['electron']); // function ipcInvoke( diff --git a/src/ui/App.tsx b/src/ui/App.tsx index 7de1c12..b55a71b 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -97,22 +97,23 @@ import Vpn from "./pages/Vpn/Vpn"; import Schedule from "./pages/Schedule/Schedule"; import PaysSlips from "./pages/PaySlips/PaysSlips"; import ApplyLeaveAndAdjustmentsTime from "./pages/LeaveAndAdjustments/ApplyLeaveAndAdjustmentsTime"; +import VpnGuard from "./pages/Vpn/VpnGuard"; const App: React.FC = () => { - + const dispatch = useDispatch(); // ✅ Get user directly from Redux const user = useSelector((state: RootState) => state.user.user); - + useEffect(() => { dispatch(loadUserFromStorage()); }, [dispatch]); - console.log("App.tsx → user:", user); + console.log("App.tsx → user:", user); return ( @@ -122,7 +123,9 @@ const App: React.FC = () => { path="/login" element={ - + + + } /> @@ -132,20 +135,22 @@ const App: React.FC = () => { path="/dashboard" element={ + {/* */} + {/* */} } > } /> } /> } /> - } /> + } /> } /> } /> } /> } /> - } /> - } /> + } /> + } /> {/* Default Redirect */} diff --git a/src/ui/layout/DashboardLayout.tsx b/src/ui/layout/DashboardLayout.tsx index 46d39d8..c24749b 100644 --- a/src/ui/layout/DashboardLayout.tsx +++ b/src/ui/layout/DashboardLayout.tsx @@ -167,6 +167,8 @@ const DashboardLayout = () => { `Timer will continue running. Please stop manually when ready.` ); + + console.log("✅ Alert shown, timer continues running"); }, [selectedProject]); diff --git a/src/ui/pages/Dashboard.tsx b/src/ui/pages/Dashboard.tsx index 8130cbe..ebf8f52 100644 --- a/src/ui/pages/Dashboard.tsx +++ b/src/ui/pages/Dashboard.tsx @@ -106,6 +106,7 @@ const Dashboard: React.FC = () => { const projectSummary = useSelector((state: any) => state.projects.projectSummary); const projectTrackingMap = useSelector((state: any) => state.projects.projectTrackingMap); const [isRefreshing, setIsRefreshing] = useState(false); + const isLimitReached = selectedProject ? isProjectLimitReached(selectedProject) : false; console.log("Line 111", projectsData, selectedProject, projectTrackingMap) @@ -156,7 +157,7 @@ const Dashboard: React.FC = () => { const firstProject = res.data[0]; - console.log("Line 158" , firstProject) + console.log("Line 158", firstProject) // Select the project dispatch(setSelectedProjectSlice(firstProject)); @@ -272,6 +273,11 @@ const Dashboard: React.FC = () => {

{formatTime(displayTime)}

+ + {/*

+ {formatTime(displayTime)} + {isLimitReached && " ⚠️"} +

*/}
Project:{" "} diff --git a/src/ui/pages/LeaveAndAdjustments/tabs/AdjustmentTab.tsx b/src/ui/pages/LeaveAndAdjustments/tabs/AdjustmentTab.tsx index 7e99b90..bd9c521 100644 --- a/src/ui/pages/LeaveAndAdjustments/tabs/AdjustmentTab.tsx +++ b/src/ui/pages/LeaveAndAdjustments/tabs/AdjustmentTab.tsx @@ -464,7 +464,7 @@ const AdjustmentTab: React.FC = ({ projects }) => { console.log("Timesheet Created Successfully"); resetForm(); // Show success toast instead of alert - showToast("PTO Request submitted successfully!", "success"); + showToast("Timesheet Request submitted successfully!", "success"); // Navigate after a small delay setTimeout(() => { @@ -680,4 +680,5 @@ const AdjustmentTab: React.FC = ({ projects }) => { ); }; -export default AdjustmentTab; \ No newline at end of file +export default AdjustmentTab; + diff --git a/src/ui/pages/Vpn/VpnGuard.tsx b/src/ui/pages/Vpn/VpnGuard.tsx index 5032cb9..f4bea63 100644 --- a/src/ui/pages/Vpn/VpnGuard.tsx +++ b/src/ui/pages/Vpn/VpnGuard.tsx @@ -1,54 +1,58 @@ import React, { useEffect, useState } from "react"; interface Props { - children: React.ReactNode; + children: React.ReactNode; } const VpnGuard: React.FC = ({ children }) => { - const [checking, setChecking] = useState(true); - const [vpnConnected, setVpnConnected] = useState(true); + const [checking, setChecking] = useState(true); + const [vpnConnected, setVpnConnected] = useState(true); -// const checkVPN = async () => { -// try { -// const res = await window.electron.checkVpnConnection(); -// setVpnConnected(res?.success); -// } catch { -// setVpnConnected(false); -// } finally { -// setChecking(false); -// } -// }; + const checkVPN = async () => { + setChecking(true) + try { + const res = await window.electron.checkRegion(); + console.log("VpnGuard", res) + if (res.success) { + setVpnConnected(true); + } + } catch { + setVpnConnected(false); + } finally { + setChecking(false); + } + }; - useEffect(() => { - // checkVPN(); - }, []); + useEffect(() => { + checkVPN(); + }, []); - if (checking) { - return ( -
- - Checking VPN... -
- ); - } + if (checking) { + return ( +
+ + Checking VPN... +
+ ); + } - if (!vpnConnected) { - return ( -
-
-

VPN Required

-

Please connect to your company VPN to continue.

+ if (!vpnConnected) { + return ( +
+
+

VPN Required

+

Please connect to your company VPN to continue.

- -
-
- ); - } + +
+
+ ); + } - return <>{children}; + return <>{children}; }; export default VpnGuard; diff --git a/types.d.ts b/types.d.ts index 8f20363..70f38ce 100644 --- a/types.d.ts +++ b/types.d.ts @@ -133,6 +133,15 @@ interface PayslipResponse { } +interface RegionResponse { + success: boolean; + status: number; + data?: any; + retry?: boolean; + message?: string; +} + + interface Window { electron: { login: (credentials: { email: string; password: string }) => Promise; @@ -241,6 +250,8 @@ interface Window { success: boolean; data?: any; }>; + + checkRegion: () => Promise; }; }