Compare commits
2 Commits
ec383c109f
...
42dd4da26b
| Author | SHA1 | Date |
|---|---|---|
|
|
42dd4da26b | |
|
|
e2b0561251 |
File diff suppressed because it is too large
Load Diff
|
|
@ -21,6 +21,7 @@
|
||||||
"@tailwindcss/vite": "^4.1.16",
|
"@tailwindcss/vite": "^4.1.16",
|
||||||
"axios": "^1.13.2",
|
"axios": "^1.13.2",
|
||||||
"electron-store": "^11.0.2",
|
"electron-store": "^11.0.2",
|
||||||
|
"get-windows": "^9.2.3",
|
||||||
"lucide-react": "^0.552.0",
|
"lucide-react": "^0.552.0",
|
||||||
"os-utils": "^0.0.14",
|
"os-utils": "^0.0.14",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
|
|
|
||||||
|
|
@ -2,19 +2,21 @@
|
||||||
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
|
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
|
||||||
import { getToken } from '../utils/tokenHelper.js';
|
import { getToken } from '../utils/tokenHelper.js';
|
||||||
|
|
||||||
const TOKEN_KEY = 'auth_token';
|
const TOKEN_KEY = 'ACCESS_TOKEN';
|
||||||
|
|
||||||
const api: AxiosInstance = axios.create({
|
const api: AxiosInstance = axios.create({
|
||||||
baseURL: 'https://wired-terminally-muskrat.ngrok-free.app/api/v1', // 🔁 your backend
|
baseURL: 'https://wired-terminally-muskrat.ngrok-free.app/api/v1/va', // 🔁 your backend
|
||||||
timeout: 10000,
|
// timeout: 10000,
|
||||||
});
|
});
|
||||||
|
|
||||||
// --- Request Interceptor ---
|
// --- Request Interceptor ---
|
||||||
api.interceptors.request.use(
|
api.interceptors.request.use(
|
||||||
async (config: AxiosRequestConfig): Promise<any> => {
|
async (config: AxiosRequestConfig): Promise<any> => {
|
||||||
const token = await getToken(TOKEN_KEY);
|
const token = await getToken(TOKEN_KEY);
|
||||||
if (token && config.headers) {
|
config.headers = config.headers || {}
|
||||||
config.headers.token = token;
|
|
||||||
|
if (token) {
|
||||||
|
config.headers['token'] = token;
|
||||||
config.headers['ngrok-skip-browser-warning'] = 98098;
|
config.headers['ngrok-skip-browser-warning'] = 98098;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
// electron/ipc/tokenHandler.ts
|
// electron/ipc/tokenHandler.ts
|
||||||
import { ipcMain } from 'electron';
|
import { ipcMain } from 'electron';
|
||||||
import { getToken, saveToken, clearToken } from '../utils/tokenHelper.js';
|
import { getToken, saveToken, clearToken } from '../utils/tokenHelper.js';
|
||||||
import { handleLogin, takeScreenshot } from '../utils/utilityFunctions.js';
|
import { getActiveApp, handleLogin, takeScreenshot } from '../utils/utilityFunctions.js';
|
||||||
import api from '../api/axiosClient.js';
|
import api from '../api/axiosClient.js';
|
||||||
|
|
||||||
ipcMain.handle('get-token', async (_, TOKEN_KEY: string) => {
|
ipcMain.handle('get-token', async (_, TOKEN_KEY: "ACCESS_TOKEN" | "REFRESH_TOKEN") => {
|
||||||
return await getToken(TOKEN_KEY);
|
return await getToken(TOKEN_KEY);
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle('save-token', async (_, TOKEN_KEY: string, token: string) => {
|
ipcMain.handle('save-token', async (_, TOKEN_KEY: "ACCESS_TOKEN" | "REFRESH_TOKEN", token: string) => {
|
||||||
await saveToken(TOKEN_KEY, token);
|
await saveToken(TOKEN_KEY, token);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
@ -29,8 +29,19 @@ ipcMain.handle('login-request', async (event, credentials: { email: string, pass
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle('logout-request', async () => {
|
ipcMain.handle('logout-request', async () => {
|
||||||
(async () => {
|
try {
|
||||||
console.log("Handle Logout listened")
|
console.log("Handle Logout listened")
|
||||||
await api.get("/logout");
|
console.log("Token", await getToken("ACCESS_TOKEN"))
|
||||||
})()
|
const res = await api.get("/logout");
|
||||||
|
if(res && ("success" in res) && res.success) {
|
||||||
|
return {success: true, message: "Logout Successfully"}
|
||||||
|
}
|
||||||
|
return {success: false, message: ""}
|
||||||
|
} catch(error) {
|
||||||
|
return {success: false, message: ""}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.handle('get-active-app', () => {
|
||||||
|
return getActiveApp();
|
||||||
});
|
});
|
||||||
|
|
@ -11,6 +11,12 @@ app.on('ready', async () => {
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
preload: getPreloadPath(),
|
preload: getPreloadPath(),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
resizable: false, // disables resizing (no maximize)
|
||||||
|
minimizable: false, // disables minimize button
|
||||||
|
maximizable: false, // disables maximize button
|
||||||
|
closable: true,
|
||||||
|
alwaysOnTop: true,
|
||||||
// disables default system frame (dont do this if you want a proper working menu bar)
|
// disables default system frame (dont do this if you want a proper working menu bar)
|
||||||
frame: process.platform === 'darwin' ? false : true,
|
frame: process.platform === 'darwin' ? false : true,
|
||||||
autoHideMenuBar: true
|
autoHideMenuBar: true
|
||||||
|
|
@ -30,19 +36,19 @@ app.on('ready', async () => {
|
||||||
return getStaticData();
|
return getStaticData();
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMainOn('sendFrameAction', (payload) => {
|
// ipcMainOn('sendFrameAction', (payload) => {
|
||||||
switch (payload) {
|
// switch (payload) {
|
||||||
case 'CLOSE':
|
// case 'CLOSE':
|
||||||
mainWindow.close();
|
// mainWindow.close();
|
||||||
break;
|
// break;
|
||||||
case 'MAXIMIZE':
|
// case 'MAXIMIZE':
|
||||||
mainWindow.maximize();
|
// mainWindow.maximize();
|
||||||
break;
|
// break;
|
||||||
case 'MINIMIZE':
|
// case 'MINIMIZE':
|
||||||
mainWindow.minimize();
|
// mainWindow.minimize();
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
|
|
||||||
// createTray(mainWindow);
|
// createTray(mainWindow);
|
||||||
handleCloseEvents(mainWindow);
|
handleCloseEvents(mainWindow);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { contextBridge, ipcRenderer } from "electron";
|
||||||
|
console.log("setting PreLoad")
|
||||||
|
|
||||||
|
|
||||||
|
contextBridge.exposeInMainWorld('electron', {
|
||||||
|
login: (credentials: { email: string, password: string }) => ipcRenderer.invoke('login-request', credentials),
|
||||||
|
logout: () => ipcRenderer.invoke('logout-request'),
|
||||||
|
getToken: (TOKEN_KEY: "ACCESS_TOKEN" | "REFRESH_TOKEN") => ipcRenderer.invoke('get-token', TOKEN_KEY),
|
||||||
|
uploadScreenshot: () => ipcRenderer.invoke('upload-screenshot'),
|
||||||
|
getActiveAppDetails: () => ipcRenderer.invoke('get-active-app'),
|
||||||
|
} satisfies Window['electron']);
|
||||||
|
|
||||||
|
// function ipcInvoke<Key extends keyof EventPayloadMapping>(
|
||||||
|
// key: Key
|
||||||
|
// ): Promise<EventPayloadMapping[Key]> {
|
||||||
|
// return ipcRenderer.invoke(key);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// function ipcOn<Key extends keyof EventPayloadMapping>(
|
||||||
|
// key: Key,
|
||||||
|
// callback: (payload: EventPayloadMapping[Key]) => void
|
||||||
|
// ) {
|
||||||
|
// const cb = (_: Electron.IpcRendererEvent, payload: any) => callback(payload);
|
||||||
|
// ipcRenderer.on(key, cb);
|
||||||
|
// return () => ipcRenderer.off(key, cb);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// function ipcSend<Key extends keyof EventPayloadMapping>(
|
||||||
|
// key: Key,
|
||||||
|
// payload: EventPayloadMapping[Key]
|
||||||
|
// ) {
|
||||||
|
// ipcRenderer.send(key, payload);
|
||||||
|
// }
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
import { contextBridge, ipcRenderer } from "electron";
|
|
||||||
|
|
||||||
const electron = require('electron');
|
|
||||||
|
|
||||||
console.log("setting PreLoad")
|
|
||||||
|
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('electron', {
|
|
||||||
subscribeStatistics: (callback) =>
|
|
||||||
ipcOn('statistics', (stats) => {
|
|
||||||
callback(stats);
|
|
||||||
}),
|
|
||||||
subscribeChangeView: (callback) =>
|
|
||||||
ipcOn('changeView', (view) => {
|
|
||||||
callback(view);
|
|
||||||
}),
|
|
||||||
getStaticData: () => ipcInvoke('getStaticData'),
|
|
||||||
sendFrameAction: (payload) => ipcSend('sendFrameAction', payload),
|
|
||||||
|
|
||||||
login: (credentials: { email: string, password: string }) => ipcRenderer.invoke('login-request', credentials),
|
|
||||||
|
|
||||||
logout: () => ipcRenderer.invoke('logout-request'),
|
|
||||||
|
|
||||||
getToken: (TOKEN_KEY: string) => ipcRenderer.invoke('get-token', TOKEN_KEY),
|
|
||||||
uploadScreenshot: () => ipcRenderer.invoke('upload-screenshot'),
|
|
||||||
} satisfies Window['electron']);
|
|
||||||
|
|
||||||
function ipcInvoke<Key extends keyof EventPayloadMapping>(
|
|
||||||
key: Key
|
|
||||||
): Promise<EventPayloadMapping[Key]> {
|
|
||||||
return electron.ipcRenderer.invoke(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
function ipcOn<Key extends keyof EventPayloadMapping>(
|
|
||||||
key: Key,
|
|
||||||
callback: (payload: EventPayloadMapping[Key]) => void
|
|
||||||
) {
|
|
||||||
const cb = (_: Electron.IpcRendererEvent, payload: any) => callback(payload);
|
|
||||||
electron.ipcRenderer.on(key, cb);
|
|
||||||
return () => electron.ipcRenderer.off(key, cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
function ipcSend<Key extends keyof EventPayloadMapping>(
|
|
||||||
key: Key,
|
|
||||||
payload: EventPayloadMapping[Key]
|
|
||||||
) {
|
|
||||||
electron.ipcRenderer.send(key, payload);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('electronAPI', {
|
|
||||||
getToken: (key: string) => ipcRenderer.invoke('get-token', key),
|
|
||||||
saveToken: (key: string, token: string) => ipcRenderer.invoke('save-token', key, token),
|
|
||||||
clearToken: (key: string) => ipcRenderer.invoke('clear-token', key),
|
|
||||||
});
|
|
||||||
|
|
@ -4,14 +4,14 @@ import Store from 'electron-store';
|
||||||
|
|
||||||
const store = new Store();
|
const store = new Store();
|
||||||
|
|
||||||
export async function getToken(TOKEN_KEY: string): Promise<string | null> {
|
export async function getToken(TOKEN_KEY: "ACCESS_TOKEN" | "REFRESH_TOKEN"): Promise<string | null> {
|
||||||
const encryptedBase64 = store.get(TOKEN_KEY) as string | undefined;
|
const encryptedBase64 = store.get(TOKEN_KEY) as string | undefined;
|
||||||
if (!encryptedBase64) return null;
|
if (!encryptedBase64) return null;
|
||||||
const encryptedBuffer = Buffer.from(encryptedBase64, 'base64');
|
const encryptedBuffer = Buffer.from(encryptedBase64, 'base64');
|
||||||
return safeStorage.decryptString(encryptedBuffer);
|
return safeStorage.decryptString(encryptedBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function saveToken(TOKEN_KEY: string, token: string): Promise<void> {
|
export async function saveToken(TOKEN_KEY: "ACCESS_TOKEN" | "REFRESH_TOKEN", token: string): Promise<void> {
|
||||||
const encryptedBuffer = safeStorage.encryptString(token);
|
const encryptedBuffer = safeStorage.encryptString(token);
|
||||||
store.set(TOKEN_KEY, encryptedBuffer.toString('base64'));
|
store.set(TOKEN_KEY, encryptedBuffer.toString('base64'));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import path from "path";
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import sharp from 'sharp';
|
import sharp from 'sharp';
|
||||||
import { saveToken } from "./tokenHelper.js";
|
import { saveToken } from "./tokenHelper.js";
|
||||||
|
import { activeWindow } from "get-windows";
|
||||||
|
|
||||||
// Blur using an offscreen canvas
|
// Blur using an offscreen canvas
|
||||||
async function blurAndCompressBase64Image(base64: string): Promise<Buffer> {
|
async function blurAndCompressBase64Image(base64: string): Promise<Buffer> {
|
||||||
|
|
@ -62,7 +63,10 @@ export const handleLogin = async (credentials: { email: string, password: string
|
||||||
|
|
||||||
console.log("API CAlled", response)
|
console.log("API CAlled", response)
|
||||||
const { accessToken, refreshToken } = response.data;
|
const { accessToken, refreshToken } = response.data;
|
||||||
await saveToken(accessToken, refreshToken);
|
|
||||||
|
await saveToken("ACCESS_TOKEN", accessToken);
|
||||||
|
await saveToken("REFRESH_TOKEN", refreshToken);
|
||||||
|
|
||||||
return { success: true, user: response.data.user };
|
return { success: true, user: response.data.user };
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -90,3 +94,8 @@ export const handleLogin = async (credentials: { email: string, password: string
|
||||||
return { success: false, error: "Unexpected error occurred" };
|
return { success: false, error: "Unexpected error occurred" };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getActiveApp = async () => {
|
||||||
|
const result = await activeWindow();
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
@ -101,22 +101,28 @@ const DashboardLayout: React.FC<DashboardLayoutProps> = ({ setUser }) => {
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleLogout = async () => {
|
const handleLogout = async () => {
|
||||||
localStorage.removeItem("user");
|
|
||||||
setUser(null);
|
|
||||||
|
|
||||||
console.log("calling Logout UI")
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await window.electron.logout()
|
const res = await window.electron.logout()
|
||||||
console.log(res)
|
if (res && res.success) {
|
||||||
|
localStorage.removeItem("user");
|
||||||
|
setUser(null);
|
||||||
|
navigate("/login");
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
navigate("/login");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setInterval(async () => {
|
||||||
|
const details = await window.electron.getActiveAppDetails()
|
||||||
|
console.log(details)
|
||||||
|
}, 15000)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
|
||||||
const toggleSidebar = () => setSidebarOpen(!isSidebarOpen);
|
const toggleSidebar = () => setSidebarOpen(!isSidebarOpen);
|
||||||
|
|
||||||
const closeSidebarOnMobile = () => {
|
const closeSidebarOnMobile = () => {
|
||||||
|
|
|
||||||
|
|
@ -25,18 +25,11 @@ type UnsubscribeFunction = () => void;
|
||||||
|
|
||||||
interface Window {
|
interface Window {
|
||||||
electron: {
|
electron: {
|
||||||
subscribeStatistics: (
|
|
||||||
callback: (statistics: Statistics) => void
|
|
||||||
) => UnsubscribeFunction;
|
|
||||||
getStaticData: () => Promise<StaticData>;
|
|
||||||
subscribeChangeView: (
|
|
||||||
callback: (view: View) => void
|
|
||||||
) => UnsubscribeFunction;
|
|
||||||
sendFrameAction: (payload: FrameWindowAction) => void;
|
|
||||||
login: (credentials: { email: string; password: string }) => Promise<any>;
|
login: (credentials: { email: string; password: string }) => Promise<any>;
|
||||||
logout: () => {};
|
logout: () => Promise<any>;
|
||||||
getToken: (tokenKey: string) => Promise<string | null>;
|
getToken: (tokenKey: "ACCESS_TOKEN" | "REFRESH_TOKEN") => Promise<string | null>;
|
||||||
uploadScreenshot: () => {};
|
uploadScreenshot: () => {};
|
||||||
|
getActiveAppDetails: () => {};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue