Merge branch 'master' of http://git.hicglobalsolutions.in/BhawanSingh/va-tracker into window-build - merge 1-14 12-Dec - B Master

This commit is contained in:
JaiPandey425 2025-12-04 13:14:46 +05:30
commit f5f94f016b
10 changed files with 227 additions and 1775 deletions

BIN
build/icon.icns Normal file

Binary file not shown.

1793
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -4,26 +4,59 @@
<style>
body {
margin: 0;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: #ffffff;
font-family: Arial, sans-serif;
}
.loader {
width: 50px;
height: 50px;
border: 5px solid #e0e0e0;
.loader-container {
position: relative;
width: 100px;
height: 100px;
}
/* Circular spinner */
.loader-ring {
width: 100%;
height: 100%;
border: 6px solid #e0e0e0;
border-top-color: #6a5acd;
border-radius: 50%;
animation: spin 1s linear infinite;
}
/* Logo in center */
.loader-logo {
position: absolute;
inset: 0;
display: flex;
justify-content: center;
align-items: center;
}
.loader-logo img {
width: 45px;
height: 45px;
object-fit: contain;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
</style>
</head>
<body>
<div class="loader"></div>
<div class="loader-container">
<div class="loader-ring"></div>
<!-- Place your logo here -->
<div class="loader-logo">
<img src="your-logo.png" alt="App Logo">
</div>
</div>
</body>
</html>

View File

@ -12,7 +12,8 @@ const httpsAgent = new https.Agent({
});
const api: AxiosInstance = axios.create({
baseURL: 'http://localhost:3000/api/v1/va', // 🔁 your backend
// https://dreadingly-unfighting-pandora.ngrok-free.dev/
baseURL: 'https://dreadingly-unfighting-pandora.ngrok-free.dev/api/v1/va', // 🔁 your backend
httpsAgent
// timeout: 10000,
});

View File

@ -78,10 +78,6 @@ app.on("ready", async () => {
);
// Create the main window
const win = new BrowserWindow({
width: 500,
@ -91,8 +87,8 @@ app.on("ready", async () => {
minimizable: false,
maximizable: false,
closable: true,
alwaysOnTop: true,
skipTaskbar: true,
// alwaysOnTop: true,
// skipTaskbar: true,
autoHideMenuBar: true,
frame: true,
show: false,
@ -105,9 +101,24 @@ app.on("ready", async () => {
},
});
win.setAlwaysOnTop(true, 'screen-saver');
// win.setAlwaysOnTop(true, 'screen-saver');
// win.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true });
// win.setFullScreenable(false);
// Cross-platform safe always-on-top
const isMac = process.platform === "darwin";
if (isMac) {
win.setAlwaysOnTop(true, "floating"); // best for macOS
win.setVisibleOnAllWorkspaces(true); // NO fullscreen override
} else {
win.setAlwaysOnTop(true, "normal"); // safest for Windows + Zoom
win.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true });
win.setFullScreenable(false);
}
mainWindow = win;
@ -149,7 +160,7 @@ app.on("ready", async () => {
// ------------------------------------
// HANDLE CLOSE EVENTS
// ------------------------------------
handleCloseEvents(win);
// handleCloseEvents(win);
});
@ -173,28 +184,28 @@ app.on("ready", async () => {
// ---------------------------
// CUSTOM CLOSE BEHAVIOR
// ---------------------------
function handleCloseEvents(window: BrowserWindow) {
let willClose = false;
// function handleCloseEvents(window: BrowserWindow) {
// let willClose = false;
window.on("close", (e) => {
if (willClose) return;
// window.on("close", (e) => {
// if (willClose) return;
e.preventDefault();
window.hide();
// e.preventDefault();
// window.hide();
if (app.dock) {
app.dock.hide();
}
});
// if (app.dock) {
// app.dock.hide();
// }
// });
app.on("before-quit", () => {
willClose = true;
});
// app.on("before-quit", () => {
// willClose = true;
// });
window.on("show", () => {
willClose = false;
});
}
// window.on("show", () => {
// willClose = false;
// });
// }
// ---------------------------
// GET MAIN WINDOW EXPORT

View File

@ -68,7 +68,7 @@ export const handleLogin = async (credentials: { email: string, password: string
try {
console.log("➡️ Calling API...");
const response = await axios.post(
'http://localhost:3000/api/v1/va/login',
'https://dreadingly-unfighting-pandora.ngrok-free.dev/api/v1/va/login',
{ userDetails: { ...credentials } },
{ headers: { "ngrok-skip-browser-warning": 69420 }, httpsAgent }
);

View File

@ -331,6 +331,7 @@ const DashboardLayout = () => {
const socketRef = useRef<Socket | null>(null);
const intervalRef = useRef<number | null>(null);
const lastAppsRef = useRef<Object | null>(null);
const [isConnected, setIsConnected] = useState(false);
useEffect(() => {
@ -540,6 +541,7 @@ const DashboardLayout = () => {
}
};
const handleSocketConnect = async () => {
const token = await window.electron.getToken("ACCESS_TOKEN");
@ -573,12 +575,56 @@ const DashboardLayout = () => {
setIsConnected(true);
// Start sending every 5 seconds
// intervalRef.current = setInterval(async () => {
// const apps = await window.electron.getRunningApps()
// socketRef.current?.emit("getVisibleApps", { token: await token, apps });
// }, 5000);
});
// socketRef.current.on("startSendAppsDetails", async ({ apps }) => {
// socketRef.current?.emit("getVisibleApps", { token: await token, apps });
// });
socketRef.current.on("startSendAppsDetails", async ({projId}) => {
if (projId !== selectedProject?.projectId) return;
console.log("▶️ startSendAppsDetails received");
// avoid multiple intervals
if (intervalRef.current) return;
intervalRef.current = setInterval(async () => {
const apps = await window.electron.getRunningApps()
socketRef.current?.emit("getVisibleApps", { token: await token, apps });
const currentApps = await window.electron.getRunningApps();
// Compare with last sent data
const hasChanged = JSON.stringify(currentApps) !== JSON.stringify(lastAppsRef.current);
if (hasChanged) {
lastAppsRef.current = currentApps;
socketRef.current?.emit("getVisibleApps", {
token: await token,
apps: currentApps,
});
}
}, 5000);
});
socketRef.current.on("stopSendAppsDetails", async ({projId}) => {
if (projId !== selectedProject?.projectId) return;
console.log("⏹ stopSendAppsDetails received");
// clear the interval
if (intervalRef.current) {
clearInterval(intervalRef.current);
intervalRef.current = null;
}
// Send final stop event to server
// socketRef.current?.emit("stopSendAppsDetails", {
// token: await token,
// });
});
socketRef.current.on("appToCapture", async ({ appTitle }) => {
console.log("📸 Capture requested for:", appTitle);

View File

@ -200,7 +200,7 @@ const PtoLeaveTab: React.FC<{
if (result.success) {
resetForm();
alert("PTO submitted!");
alert("PTO Request submitted!");
navigate('/dashboard/leave-adjustments')
} else {
setServerError(result.message || "Something went wrong");

View File

@ -126,6 +126,33 @@ const SickLeaveTab: React.FC<{
reader.readAsDataURL(file);
});
useEffect(() => {
const editor = quillRef.current?.getEditor();
if (!editor) return;
editor.getModule("clipboard").addMatcher(Node.ELEMENT_NODE, (node: any, delta: any) => {
return delta;
});
editor.root.addEventListener("paste", async (e: any) => {
const items = e.clipboardData?.items;
if (!items) return;
for (const item of items) {
if (item.type.indexOf("image") === 0) {
const file = item.getAsFile();
const base64 = await convertToBase64(file);
const range = editor.getSelection();
editor.insertEmbed(range.index, "image", base64);
}
}
});
}, []);
const validateLeaveForm = (data: LeaveFormData): Partial<LeaveFormData> => {
const errors: Partial<LeaveFormData> = {};
@ -161,7 +188,6 @@ const SickLeaveTab: React.FC<{
toDate: "",
comment: ""
};
setSickLeave(emptyForm);
setSickErrors({});
@ -190,7 +216,7 @@ const SickLeaveTab: React.FC<{
if (result.success) {
resetForm();
alert("SICK submitted!");
alert("SICK leave applied!");
navigate('/dashboard/leave-adjustments')
} else {
setServerError(result.message || "Something went wrong");

14
types.d.ts vendored
View File

@ -1,3 +1,13 @@
declare module "quill";
declare module "quill-image-resize-module";
declare module "quill-image-drop-module";
declare module "quill-image-resize-module-react" {
const ImageResize: any;
export default ImageResize;
}
type Statistics = {
cpuUsage: number;
ramUsage: number;
@ -144,14 +154,16 @@ interface Window {
vaId: string;
projectId: string;
type: string;
time:string
}) => Promise<any>;
stopProjectTracking: (data: {
vaId: string;
projectId: string;
type: string;
time:string
}) => Promise<any>;
trackingTabsOpeningClosing: (data: {
id?: string; // optional, only present if updating
id?: string;
logId: string;
projectId: string;
title: string;