Compare commits
16 Commits
52e45f8328
...
f5f94f016b
| Author | SHA1 | Date |
|---|---|---|
|
|
f5f94f016b | |
|
|
93704a70f6 | |
|
|
ed0bcb7107 | |
|
|
3ef615a160 | |
|
|
b55f9469ad | |
|
|
d23933c517 | |
|
|
92e8c15023 | |
|
|
35eb073f46 | |
|
|
94eedff8af | |
|
|
ac3ddf4b2b | |
|
|
a55e6ccba4 | |
|
|
bd4a3656e7 | |
|
|
345822885f | |
|
|
0ae8f6185a | |
|
|
882e8349c9 | |
|
|
d641e9432d |
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true });
|
||||
win.setFullScreenable(false);
|
||||
|
||||
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue