Compare commits
No commits in common. "f5f94f016b396d982f8dbd1f401261ab3847bed1" and "52e45f8328094ccf0af475363354778872a0354e" have entirely different histories.
f5f94f016b
...
52e45f8328
BIN
build/icon.icns
BIN
build/icon.icns
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
|
@ -4,59 +4,26 @@
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
height: 100vh;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
}
|
}
|
||||||
|
.loader {
|
||||||
.loader-container {
|
width: 50px;
|
||||||
position: relative;
|
height: 50px;
|
||||||
width: 100px;
|
border: 5px solid #e0e0e0;
|
||||||
height: 100px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Circular spinner */
|
|
||||||
.loader-ring {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
border: 6px solid #e0e0e0;
|
|
||||||
border-top-color: #6a5acd;
|
border-top-color: #6a5acd;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
animation: spin 1s linear infinite;
|
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 {
|
@keyframes spin {
|
||||||
to { transform: rotate(360deg); }
|
to { transform: rotate(360deg); }
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="loader-container">
|
<div class="loader"></div>
|
||||||
<div class="loader-ring"></div>
|
|
||||||
|
|
||||||
<!-- Place your logo here -->
|
|
||||||
<div class="loader-logo">
|
|
||||||
<img src="your-logo.png" alt="App Logo">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,7 @@ const httpsAgent = new https.Agent({
|
||||||
});
|
});
|
||||||
|
|
||||||
const api: AxiosInstance = axios.create({
|
const api: AxiosInstance = axios.create({
|
||||||
// https://dreadingly-unfighting-pandora.ngrok-free.dev/
|
baseURL: 'http://localhost:3000/api/v1/va', // 🔁 your backend
|
||||||
baseURL: 'https://dreadingly-unfighting-pandora.ngrok-free.dev/api/v1/va', // 🔁 your backend
|
|
||||||
httpsAgent
|
httpsAgent
|
||||||
// timeout: 10000,
|
// timeout: 10000,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,10 @@ app.on("ready", async () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Create the main window
|
// Create the main window
|
||||||
const win = new BrowserWindow({
|
const win = new BrowserWindow({
|
||||||
width: 500,
|
width: 500,
|
||||||
|
|
@ -87,8 +91,8 @@ app.on("ready", async () => {
|
||||||
minimizable: false,
|
minimizable: false,
|
||||||
maximizable: false,
|
maximizable: false,
|
||||||
closable: true,
|
closable: true,
|
||||||
// alwaysOnTop: true,
|
alwaysOnTop: true,
|
||||||
// skipTaskbar: true,
|
skipTaskbar: true,
|
||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
frame: true,
|
frame: true,
|
||||||
show: false,
|
show: false,
|
||||||
|
|
@ -101,24 +105,9 @@ app.on("ready", async () => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
win.setAlwaysOnTop(true, 'screen-saver');
|
||||||
|
win.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true });
|
||||||
// win.setAlwaysOnTop(true, 'screen-saver');
|
win.setFullScreenable(false);
|
||||||
// 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;
|
mainWindow = win;
|
||||||
|
|
||||||
|
|
@ -160,7 +149,7 @@ app.on("ready", async () => {
|
||||||
// ------------------------------------
|
// ------------------------------------
|
||||||
// HANDLE CLOSE EVENTS
|
// HANDLE CLOSE EVENTS
|
||||||
// ------------------------------------
|
// ------------------------------------
|
||||||
// handleCloseEvents(win);
|
handleCloseEvents(win);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -184,28 +173,28 @@ app.on("ready", async () => {
|
||||||
// ---------------------------
|
// ---------------------------
|
||||||
// CUSTOM CLOSE BEHAVIOR
|
// CUSTOM CLOSE BEHAVIOR
|
||||||
// ---------------------------
|
// ---------------------------
|
||||||
// function handleCloseEvents(window: BrowserWindow) {
|
function handleCloseEvents(window: BrowserWindow) {
|
||||||
// let willClose = false;
|
let willClose = false;
|
||||||
|
|
||||||
// window.on("close", (e) => {
|
window.on("close", (e) => {
|
||||||
// if (willClose) return;
|
if (willClose) return;
|
||||||
|
|
||||||
// e.preventDefault();
|
e.preventDefault();
|
||||||
// window.hide();
|
window.hide();
|
||||||
|
|
||||||
// if (app.dock) {
|
if (app.dock) {
|
||||||
// app.dock.hide();
|
app.dock.hide();
|
||||||
// }
|
}
|
||||||
// });
|
});
|
||||||
|
|
||||||
// app.on("before-quit", () => {
|
app.on("before-quit", () => {
|
||||||
// willClose = true;
|
willClose = true;
|
||||||
// });
|
});
|
||||||
|
|
||||||
// window.on("show", () => {
|
window.on("show", () => {
|
||||||
// willClose = false;
|
willClose = false;
|
||||||
// });
|
});
|
||||||
// }
|
}
|
||||||
|
|
||||||
// ---------------------------
|
// ---------------------------
|
||||||
// GET MAIN WINDOW EXPORT
|
// GET MAIN WINDOW EXPORT
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ export const handleLogin = async (credentials: { email: string, password: string
|
||||||
try {
|
try {
|
||||||
console.log("➡️ Calling API...");
|
console.log("➡️ Calling API...");
|
||||||
const response = await axios.post(
|
const response = await axios.post(
|
||||||
'https://dreadingly-unfighting-pandora.ngrok-free.dev/api/v1/va/login',
|
'http://localhost:3000/api/v1/va/login',
|
||||||
{ userDetails: { ...credentials } },
|
{ userDetails: { ...credentials } },
|
||||||
{ headers: { "ngrok-skip-browser-warning": 69420 }, httpsAgent }
|
{ headers: { "ngrok-skip-browser-warning": 69420 }, httpsAgent }
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -331,7 +331,6 @@ const DashboardLayout = () => {
|
||||||
|
|
||||||
const socketRef = useRef<Socket | null>(null);
|
const socketRef = useRef<Socket | null>(null);
|
||||||
const intervalRef = useRef<number | null>(null);
|
const intervalRef = useRef<number | null>(null);
|
||||||
const lastAppsRef = useRef<Object | null>(null);
|
|
||||||
const [isConnected, setIsConnected] = useState(false);
|
const [isConnected, setIsConnected] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -541,7 +540,6 @@ const DashboardLayout = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const handleSocketConnect = async () => {
|
const handleSocketConnect = async () => {
|
||||||
|
|
||||||
const token = await window.electron.getToken("ACCESS_TOKEN");
|
const token = await window.electron.getToken("ACCESS_TOKEN");
|
||||||
|
|
@ -575,56 +573,12 @@ const DashboardLayout = () => {
|
||||||
setIsConnected(true);
|
setIsConnected(true);
|
||||||
|
|
||||||
// Start sending every 5 seconds
|
// 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 () => {
|
intervalRef.current = setInterval(async () => {
|
||||||
const currentApps = await window.electron.getRunningApps();
|
const apps = await window.electron.getRunningApps()
|
||||||
|
socketRef.current?.emit("getVisibleApps", { token: await token, apps });
|
||||||
// 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);
|
}, 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 }) => {
|
socketRef.current.on("appToCapture", async ({ appTitle }) => {
|
||||||
console.log("📸 Capture requested for:", appTitle);
|
console.log("📸 Capture requested for:", appTitle);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -200,7 +200,7 @@ const PtoLeaveTab: React.FC<{
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
resetForm();
|
resetForm();
|
||||||
alert("PTO Request submitted!");
|
alert("PTO submitted!");
|
||||||
navigate('/dashboard/leave-adjustments')
|
navigate('/dashboard/leave-adjustments')
|
||||||
} else {
|
} else {
|
||||||
setServerError(result.message || "Something went wrong");
|
setServerError(result.message || "Something went wrong");
|
||||||
|
|
|
||||||
|
|
@ -126,33 +126,6 @@ const SickLeaveTab: React.FC<{
|
||||||
reader.readAsDataURL(file);
|
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 validateLeaveForm = (data: LeaveFormData): Partial<LeaveFormData> => {
|
||||||
const errors: Partial<LeaveFormData> = {};
|
const errors: Partial<LeaveFormData> = {};
|
||||||
|
|
||||||
|
|
@ -188,6 +161,7 @@ const SickLeaveTab: React.FC<{
|
||||||
toDate: "",
|
toDate: "",
|
||||||
comment: ""
|
comment: ""
|
||||||
};
|
};
|
||||||
|
|
||||||
setSickLeave(emptyForm);
|
setSickLeave(emptyForm);
|
||||||
setSickErrors({});
|
setSickErrors({});
|
||||||
|
|
||||||
|
|
@ -216,7 +190,7 @@ const SickLeaveTab: React.FC<{
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
resetForm();
|
resetForm();
|
||||||
alert("SICK leave applied!");
|
alert("SICK submitted!");
|
||||||
navigate('/dashboard/leave-adjustments')
|
navigate('/dashboard/leave-adjustments')
|
||||||
} else {
|
} else {
|
||||||
setServerError(result.message || "Something went wrong");
|
setServerError(result.message || "Something went wrong");
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,3 @@
|
||||||
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 = {
|
type Statistics = {
|
||||||
cpuUsage: number;
|
cpuUsage: number;
|
||||||
ramUsage: number;
|
ramUsage: number;
|
||||||
|
|
@ -154,16 +144,14 @@ interface Window {
|
||||||
vaId: string;
|
vaId: string;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
type: string;
|
type: string;
|
||||||
time:string
|
|
||||||
}) => Promise<any>;
|
}) => Promise<any>;
|
||||||
stopProjectTracking: (data: {
|
stopProjectTracking: (data: {
|
||||||
vaId: string;
|
vaId: string;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
type: string;
|
type: string;
|
||||||
time:string
|
|
||||||
}) => Promise<any>;
|
}) => Promise<any>;
|
||||||
trackingTabsOpeningClosing: (data: {
|
trackingTabsOpeningClosing: (data: {
|
||||||
id?: string;
|
id?: string; // optional, only present if updating
|
||||||
logId: string;
|
logId: string;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
title: string;
|
title: string;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue