From 8d2961c50d43ba44f2e87c24751001422abd45b1 Mon Sep 17 00:00:00 2001 From: JaiPandey425 Date: Thu, 13 Nov 2025 15:47:02 +0530 Subject: [PATCH] type error fix --- e2e/example.spec.js | 132 ++++++++++++++++++ playwright.config.js | 73 ++++++++++ src/electron/ipc/ipcHandler.ts | 2 +- src/electron/preload.cjs | 43 ++++++ src/ui/hooks/useActiveAppTracker.tsx | 20 ++- src/ui/layout/DashboardLayout.tsx | 4 +- .../LeaveAndAdjustments.tsx | 75 +++++----- src/ui/pages/Timesheets/Timesheets.tsx | 2 +- src/ui/store/windowSlice.tsx | 2 +- types.d.ts | 11 +- 10 files changed, 311 insertions(+), 53 deletions(-) create mode 100644 e2e/example.spec.js create mode 100644 playwright.config.js create mode 100644 src/electron/preload.cjs diff --git a/e2e/example.spec.js b/e2e/example.spec.js new file mode 100644 index 0000000..f3c2971 --- /dev/null +++ b/e2e/example.spec.js @@ -0,0 +1,132 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype); + return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var test_1 = require("@playwright/test"); +var electronApp; +var mainPage; +function waitForPreloadScript() { + return __awaiter(this, void 0, void 0, function () { + var _this = this; + return __generator(this, function (_a) { + return [2 /*return*/, new Promise(function (resolve) { + var interval = setInterval(function () { return __awaiter(_this, void 0, void 0, function () { + var electronBridge; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, mainPage.evaluate(function () { + return window.electron; + })]; + case 1: + electronBridge = _a.sent(); + if (electronBridge) { + clearInterval(interval); + resolve(true); + } + return [2 /*return*/]; + } + }); + }); }, 100); + })]; + }); + }); +} +test_1.test.beforeEach(function () { return __awaiter(void 0, void 0, void 0, function () { + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, test_1._electron.launch({ + args: ['.'], + env: { NODE_ENV: 'development' }, + })]; + case 1: + electronApp = _a.sent(); + return [4 /*yield*/, electronApp.firstWindow()]; + case 2: + mainPage = _a.sent(); + return [4 /*yield*/, waitForPreloadScript()]; + case 3: + _a.sent(); + return [2 /*return*/]; + } + }); +}); }); +test_1.test.afterEach(function () { return __awaiter(void 0, void 0, void 0, function () { + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, electronApp.close()]; + case 1: + _a.sent(); + return [2 /*return*/]; + } + }); +}); }); +(0, test_1.test)('custom frame should minimize the mainWindow', function () { return __awaiter(void 0, void 0, void 0, function () { + var isMinimized; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, mainPage.click('#minimize')]; + case 1: + _a.sent(); + return [4 /*yield*/, electronApp.evaluate(function (electron) { + return electron.BrowserWindow.getAllWindows()[0].isMinimized(); + })]; + case 2: + isMinimized = _a.sent(); + (0, test_1.expect)(isMinimized).toBeTruthy(); + return [2 /*return*/]; + } + }); +}); }); +(0, test_1.test)('should create a custom menu', function () { return __awaiter(void 0, void 0, void 0, function () { + var menu; + var _a, _b; + return __generator(this, function (_c) { + switch (_c.label) { + case 0: return [4 /*yield*/, electronApp.evaluate(function (electron) { + return electron.Menu.getApplicationMenu(); + })]; + case 1: + menu = _c.sent(); + (0, test_1.expect)(menu).not.toBeNull(); + (0, test_1.expect)(menu === null || menu === void 0 ? void 0 : menu.items).toHaveLength(2); + (0, test_1.expect)((_a = menu === null || menu === void 0 ? void 0 : menu.items[0].submenu) === null || _a === void 0 ? void 0 : _a.items).toHaveLength(2); + (0, test_1.expect)((_b = menu === null || menu === void 0 ? void 0 : menu.items[1].submenu) === null || _b === void 0 ? void 0 : _b.items).toHaveLength(3); + (0, test_1.expect)(menu === null || menu === void 0 ? void 0 : menu.items[1].label).toBe('View'); + return [2 /*return*/]; + } + }); +}); }); diff --git a/playwright.config.js b/playwright.config.js new file mode 100644 index 0000000..39d7c81 --- /dev/null +++ b/playwright.config.js @@ -0,0 +1,73 @@ +"use strict"; +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var test_1 = require("@playwright/test"); +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// require('dotenv').config(); +/** + * See https://playwright.dev/docs/test-configuration. + */ +exports.default = (0, test_1.defineConfig)({ + testDir: './e2e', + /* Run tests in files in parallel */ + fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: 'html', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + // baseURL: 'http://127.0.0.1:3000', + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + }, + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: __assign({}, test_1.devices['Desktop Chrome']), + }, + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { ...devices['Pixel 5'] }, + // }, + // { + // name: 'Mobile Safari', + // use: { ...devices['iPhone 12'] }, + // }, + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { ...devices['Desktop Edge'], channel: 'msedge' }, + // }, + // { + // name: 'Google Chrome', + // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, + // }, + ], + /* Run your local dev server before starting the tests */ + webServer: { + command: 'npm run dev:react', + url: 'http://localhost:5123', + reuseExistingServer: !process.env.CI, + }, +}); diff --git a/src/electron/ipc/ipcHandler.ts b/src/electron/ipc/ipcHandler.ts index fab46c6..59349ca 100644 --- a/src/electron/ipc/ipcHandler.ts +++ b/src/electron/ipc/ipcHandler.ts @@ -196,7 +196,7 @@ ipcMain.handle("get-project-logs", async (event, { projectID, fromDate, toDate } const response = await api.get(url); console.log("✅ response-logs:", response); - return response; + return { success: true, data: response.data }; } catch (error) { console.error("❌ Error fetching project logs:", error); throw error; diff --git a/src/electron/preload.cjs b/src/electron/preload.cjs new file mode 100644 index 0000000..786cf92 --- /dev/null +++ b/src/electron/preload.cjs @@ -0,0 +1,43 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var electron_1 = require("electron"); +console.log("setting PreLoad"); +electron_1.contextBridge.exposeInMainWorld('electron', { + login: function (credentials) { return electron_1.ipcRenderer.invoke('login-request', credentials); }, + logout: function () { return electron_1.ipcRenderer.invoke('logout-request'); }, + forgotPassword: function (email) { return electron_1.ipcRenderer.invoke("forgot-password", email); }, + getToken: function (TOKEN_KEY) { return electron_1.ipcRenderer.invoke('get-token', TOKEN_KEY); }, + uploadScreenshot: function () { return electron_1.ipcRenderer.invoke('upload-screenshot'); }, + getActiveAppDetails: function () { return electron_1.ipcRenderer.invoke('get-active-app'); }, + toggleCloseBtn: function (shouldEnable) { return electron_1.ipcRenderer.invoke('toggle-close-btn', shouldEnable); }, + resizeWindow: function (width, height) { return electron_1.ipcRenderer.invoke('resize-window', width, height); }, + getProjectList: function () { return electron_1.ipcRenderer.invoke("get-project-list"); }, + onWindowUpdate: function (callback) { + return electron_1.ipcRenderer.on("window:updated", function (_, data) { return callback(data); }); + }, + startProjectTracking: function (data) { return electron_1.ipcRenderer.invoke("start-project-tracking", data); }, + stopProjectTracking: function (data) { return electron_1.ipcRenderer.invoke("stop-project-tracking", data); }, + trackingTabsOpeningClosing: function (data) { + return electron_1.ipcRenderer.invoke("tracking-tabs-opening-and-closing", data); + }, + getProjectLogs: function (projectID, fromDate, toDate) { return electron_1.ipcRenderer.invoke("get-project-logs", { projectID: projectID, fromDate: fromDate, toDate: toDate }); }, +}); +// function ipcInvoke( +// key: Key +// ): Promise { +// return ipcRenderer.invoke(key); +// } +// function ipcOn( +// 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: Key, +// payload: EventPayloadMapping[Key] +// ) { +// ipcRenderer.send(key, payload); +// } diff --git a/src/ui/hooks/useActiveAppTracker.tsx b/src/ui/hooks/useActiveAppTracker.tsx index d726935..0727117 100644 --- a/src/ui/hooks/useActiveAppTracker.tsx +++ b/src/ui/hooks/useActiveAppTracker.tsx @@ -6,13 +6,13 @@ export const useActiveAppTracker = ( isTracking: boolean, activeProjectLogId: string | null, projectId: string | null, - projectName: string + projectName: string | null ) => { const dispatch = useDispatch(); const lastActiveRef = useRef(null); const lastLogIdRef = useRef(null); const lastTitleRef = useRef(null); - const intervalIdRef = useRef(null); + const intervalIdRef = useRef(null); const finalizeTrackingRef = useRef<(() => Promise) | null>(null); // ✅ Common guard to check if we can send @@ -31,15 +31,27 @@ export const useActiveAppTracker = ( } try { - const payload = { - id: !isNew ? lastLogIdRef.current : undefined, + const payload: { + id?: string; + logId: string; + projectId: string; + title: string; + appName: string; + } = { logId: projectLogId, projectId, title, appName, }; + // ✅ only attach `id` if it’s non-null and not undefined + if (!isNew && lastLogIdRef.current) { + payload.id = lastLogIdRef.current; + } + + console.log(isNew ? "➡️ POST new log" : "✏️ PATCH update log", payload); + const res = await window.electron.trackingTabsOpeningClosing(payload); if (isNew && res?._id) lastLogIdRef.current = res._id; diff --git a/src/ui/layout/DashboardLayout.tsx b/src/ui/layout/DashboardLayout.tsx index a55c857..6a8b46c 100644 --- a/src/ui/layout/DashboardLayout.tsx +++ b/src/ui/layout/DashboardLayout.tsx @@ -119,8 +119,8 @@ const DashboardLayout = () => { const { finalizeTracking } = useActiveAppTracker( isTracking, activeProjectLogId, - selectedProject?.projectId, - selectedProject?.projectName + selectedProject?.projectId ?? null, + selectedProject?.projectName ?? null ); const [projectsData, setProjectsData] = useState([]); diff --git a/src/ui/pages/LeaveAndAdjustments/LeaveAndAdjustments.tsx b/src/ui/pages/LeaveAndAdjustments/LeaveAndAdjustments.tsx index 0cab6db..e46fb97 100644 --- a/src/ui/pages/LeaveAndAdjustments/LeaveAndAdjustments.tsx +++ b/src/ui/pages/LeaveAndAdjustments/LeaveAndAdjustments.tsx @@ -42,6 +42,7 @@ const LeaveAndAdjustments: React.FC = () => { const [ptoLeave, setPtoLeave] = useState({ fromDate: '', toDate: '', + // description:"" }); const [ptoErrors, setPtoErrors] = useState>({}); @@ -49,6 +50,7 @@ const LeaveAndAdjustments: React.FC = () => { const [sickLeave, setSickLeave] = useState({ fromDate: '', toDate: '', + }); const [sickErrors, setSickErrors] = useState>({}); const [selectedProjectId, setSelectedProjectId] = useState("") @@ -80,9 +82,6 @@ const LeaveAndAdjustments: React.FC = () => { errors.toDate = 'To date must be after from date'; } - if (!data.description.trim()) { - errors.description = 'Description/Reason is required'; - } return errors; }; @@ -100,7 +99,7 @@ const LeaveAndAdjustments: React.FC = () => { console.log('Submitting PTO:', ptoLeave); alert('PTO request submitted successfully!'); - setPtoLeave({ fromDate: '', toDate: '', description: '' }); + setPtoLeave({ fromDate: '', toDate: '' }); setPtoErrors({}); } catch (error) { alert('Failed to submit request. Please try again.'); @@ -128,7 +127,7 @@ const LeaveAndAdjustments: React.FC = () => { console.log('Submitting Sick Leave:', sickLeave); alert('Sick Leave request submitted successfully!'); - setSickLeave({ fromDate: '', toDate: '', description: '' }); + setSickLeave({ fromDate: '', toDate: '' }); setSickErrors({}); } catch (error) { alert('Failed to submit request. Please try again.'); @@ -173,35 +172,35 @@ const LeaveAndAdjustments: React.FC = () => { - const fetchLogs = async () => { - const res = await window.electron.getProjectLogs( - selectedProjectId, - selectedDate || undefined, - selectedDate || undefined, - ); + // const fetchLogs = async () => { + // const res = await window.electron.getProjectLogs( + // selectedProjectId, + // selectedDate || undefined, + // selectedDate || undefined, + // ); - if (res.success) { - console.log("✅ Logs: fetchLogs", res); + // if (res.success) { + // console.log("✅ Logs: fetchLogs", res); - // Safely extract time if from/to exist - const fromTime = res.from ? new Date(res.from).toISOString().slice(11, 16) : ""; - const toTime = res.to ? new Date(res.to).toISOString().slice(11, 16) : ""; + // // Safely extract time if from/to exist + // const fromTime = res.from ? new Date(res.from).toISOString().slice(11, 16) : ""; + // const toTime = res.to ? new Date(res.to).toISOString().slice(11, 16) : ""; - setPtoLeave({ - fromDate: fromTime, - toDate: toTime, - }); - } else { - console.warn("⚠️ Failed to fetch project logs"); - } - }; + // setPtoLeave({ + // fromDate: fromTime, + // toDate: toTime, + // }); + // } else { + // console.warn("⚠️ Failed to fetch project logs"); + // } + // }; - useEffect(() => { - if (selectedProjectId && selectedDate) { - fetchLogs() - } - }, [selectedProjectId, selectedDate]) + // useEffect(() => { + // if (selectedProjectId && selectedDate) { + // fetchLogs() + // } + // }, [selectedProjectId, selectedDate]) return ( @@ -386,16 +385,12 @@ const LeaveAndAdjustments: React.FC = () => { Description / Reason