From df0452ecba7e08677c032ab5634581e4497dc50f Mon Sep 17 00:00:00 2001 From: AKILIMAILI CIZUNGU Innocent <51681130+Innocent-Akim@users.noreply.github.com> Date: Thu, 31 Oct 2024 22:01:09 +0200 Subject: [PATCH 1/5] [Feat]: Implement dynamic date range picker for timesheet filtering (#3213) * feat: Implement dynamic date range picker for timesheet filtering * fix: Resolved * improve: timesheet date filter --- .../timesheet/components/TimesheetFilter.tsx | 66 +++--- .../components/TimesheetFilterDate.tsx | 197 ++++++++++++++++++ .../[locale]/timesheet/components/index.tsx | 1 + 3 files changed, 227 insertions(+), 37 deletions(-) create mode 100644 apps/web/app/[locale]/timesheet/components/TimesheetFilterDate.tsx diff --git a/apps/web/app/[locale]/timesheet/components/TimesheetFilter.tsx b/apps/web/app/[locale]/timesheet/components/TimesheetFilter.tsx index 9249a9036..0430a0aab 100644 --- a/apps/web/app/[locale]/timesheet/components/TimesheetFilter.tsx +++ b/apps/web/app/[locale]/timesheet/components/TimesheetFilter.tsx @@ -1,47 +1,39 @@ import { FilterWithStatus } from './FilterWithStatus'; -import { FilterTaskActionMenu, FrequencySelect } from '.'; +import { FrequencySelect, TimesheetFilterDate } from '.'; import { Button } from 'lib/components'; -import { TimeSheetFilterPopover } from './time-sheet-filter-popover'; -import { Cross2Icon } from '@radix-ui/react-icons'; +import { SettingFilterIcon } from '@/assets/svg'; export function TimesheetFilter() { return ( - <> - -
-
- { - // TODO: Implement filter toggle handler - }} - /> -
-
-
- -
- - -
- - -
+
+
+ { + console.log(label) + }} + /> +
+
+
+
+ + + +
- +
) } diff --git a/apps/web/app/[locale]/timesheet/components/TimesheetFilterDate.tsx b/apps/web/app/[locale]/timesheet/components/TimesheetFilterDate.tsx new file mode 100644 index 000000000..f6532210c --- /dev/null +++ b/apps/web/app/[locale]/timesheet/components/TimesheetFilterDate.tsx @@ -0,0 +1,197 @@ +import { cn } from "@/lib/utils" +import { DatePicker } from "@components/ui/DatePicker" +import { Button } from "@components/ui/button" +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@components/ui/popover" +import { CalendarIcon } from "@radix-ui/react-icons" +import { format } from "date-fns" +import React from "react" +import { MdKeyboardArrowRight } from "react-icons/md" +import { PiCalendarDotsThin } from "react-icons/pi" + +interface DatePickerInputProps { + date: Date | null; + label: string; +} +interface TimesheetFilterDateProps { + onChange?: (range: { from: Date | null; to: Date | null }) => void; + initialRange?: { from: Date | null; to: Date | null }; + minDate?: Date; + maxDate?: Date; +} + +export function TimesheetFilterDate({ + onChange, + initialRange, + minDate, + maxDate +}: TimesheetFilterDateProps) { + + const [dateRange, setDateRange] = React.useState<{ from: Date | null; to: Date | null }>({ + from: initialRange?.from ?? new Date(), + to: initialRange?.to ?? new Date(), + }); + + const handleFromChange = (fromDate: Date | null) => { + if (maxDate && fromDate && fromDate > maxDate) { + return; + } + setDateRange((prev) => ({ ...prev, from: fromDate })); + onChange?.({ ...dateRange, from: fromDate }); + }; + + const handleToChange = (toDate: Date | null) => { + if (dateRange.from && toDate && toDate < dateRange.from) { + return; + } + setDateRange((prev) => ({ ...prev, to: toDate })); + }; + + const handlePresetClick = (preset: string) => { + const today = new Date(); + switch (preset) { + case 'Today': + setDateRange({ from: today, to: today }); + break; + case 'Last 7 days': + setDateRange({ + from: new Date(today.getFullYear(), today.getMonth(), today.getDate() - 7), + to: today + }); + break; + case 'Last 30 days': + setDateRange({ + from: new Date(today.getFullYear(), today.getMonth(), today.getDate() - 30), + to: today + }); + break; + case `This year (${today.getFullYear()})`: + setDateRange({ + from: new Date(today.getFullYear(), 0, 1), + to: today + }); + break; + case 'Custom Date Range': + setDateRange({ from: null, to: null }); + break; + default: + break; + } + }; + + + return (<> + + + + + +
+ + +
+
+ {["Today", "Last 7 days", "Last 30 days", `This year (${new Date().getFullYear()})`, "Custom Date Range"].map((label, index) => ( + + ))} +
+
+
+ + ) +} + + +const DatePickerInput: React.FC = ({ date, label }) => ( + <> + + + +); + +export function DatePickerFilter({ + label, + date, + setDate, + minDate, + maxDate +}: { + label: string; + date: Date | null; + setDate: (date: Date | null) => void; + minDate?: Date | null; + maxDate?: Date | null + +}) { + const isDateDisabled = React.useCallback((date: Date) => { + if (minDate && date < minDate) return true; + if (maxDate && date > maxDate) return true; + return false; + }, [minDate, maxDate]); + + return ( +
+ } + mode="single" + numberOfMonths={1} + initialFocus + defaultMonth={date ?? new Date()} + selected={date ?? new Date()} + onSelect={(selectedDate) => { + if (selectedDate && !isDateDisabled(selectedDate)) { + setDate(selectedDate); + } + }} + modifiersClassNames={{ + disabled: 'text-gray-300 cursor-not-allowed', + }} + disabled={[ + ...(minDate ? [{ before: minDate }] : []), + ...(maxDate ? [{ after: maxDate }] : []) + ]} + /> +
+ ); +} diff --git a/apps/web/app/[locale]/timesheet/components/index.tsx b/apps/web/app/[locale]/timesheet/components/index.tsx index 12cf616a7..ed9e14172 100644 --- a/apps/web/app/[locale]/timesheet/components/index.tsx +++ b/apps/web/app/[locale]/timesheet/components/index.tsx @@ -4,3 +4,4 @@ export * from './CalendarView'; export * from './TimesheetFilter'; export * from './FrequencySelect'; export * from './FilterWithStatus'; +export * from './TimesheetFilterDate'; From 4f30b1222e044f232072427dd571f9623f8683e8 Mon Sep 17 00:00:00 2001 From: AKILIMAILI CIZUNGU Innocent <51681130+Innocent-Akim@users.noreply.github.com> Date: Sat, 2 Nov 2024 21:59:17 +0200 Subject: [PATCH 2/5] [Feat]: DataTableTimeSheet and SelectFilter components for improved and status management (#3223) * feat: Refactor DataTableTimeSheet and SelectFilter components for improved readability and status management * fix: resolve * fix: resolve * feat: enhance timesheet component --- .../components/CalendarView.tsx | 0 .../components/FilterWithStatus.tsx | 4 +- .../components/FrequencySelect.tsx | 2 +- .../components/TimeSheetFilterPopover.tsx} | 10 +- .../[memberId]/components/TimesheetAction.tsx | 55 +++ .../components/TimesheetCard.tsx | 0 .../components/TimesheetFilter.tsx | 12 +- .../components/TimesheetFilterDate.tsx | 63 ++-- .../components/TimesheetView.tsx | 5 +- .../{ => [memberId]}/components/index.tsx | 2 + .../timesheet/{ => [memberId]}/page.tsx | 27 +- apps/web/app/helpers/date.ts | 17 + apps/web/components/app-sidebar.tsx | 300 ++++++++--------- apps/web/components/ui/data-table.tsx | 6 +- .../components/custom-select/multi-select.tsx | 8 +- apps/web/lib/components/types.ts | 33 ++ .../calendar/confirm-change-status.tsx | 10 +- .../integrations/calendar/helper-calendar.ts | 142 +++++++- .../calendar/table-time-sheet.tsx | 312 ++++++++++-------- .../calendar/time-sheet-filter-popover.tsx | 2 +- apps/web/lib/features/user-profile-plans.tsx | 5 +- 21 files changed, 658 insertions(+), 357 deletions(-) rename apps/web/app/[locale]/timesheet/{ => [memberId]}/components/CalendarView.tsx (100%) rename apps/web/app/[locale]/timesheet/{ => [memberId]}/components/FilterWithStatus.tsx (93%) rename apps/web/app/[locale]/timesheet/{ => [memberId]}/components/FrequencySelect.tsx (97%) rename apps/web/app/[locale]/timesheet/{components/time-sheet-filter-popover.tsx => [memberId]/components/TimeSheetFilterPopover.tsx} (91%) create mode 100644 apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetAction.tsx rename apps/web/app/[locale]/timesheet/{ => [memberId]}/components/TimesheetCard.tsx (100%) rename apps/web/app/[locale]/timesheet/{ => [memberId]}/components/TimesheetFilter.tsx (61%) rename apps/web/app/[locale]/timesheet/{ => [memberId]}/components/TimesheetFilterDate.tsx (72%) rename apps/web/app/[locale]/timesheet/{ => [memberId]}/components/TimesheetView.tsx (51%) rename apps/web/app/[locale]/timesheet/{ => [memberId]}/components/index.tsx (76%) rename apps/web/app/[locale]/timesheet/{ => [memberId]}/page.tsx (89%) diff --git a/apps/web/app/[locale]/timesheet/components/CalendarView.tsx b/apps/web/app/[locale]/timesheet/[memberId]/components/CalendarView.tsx similarity index 100% rename from apps/web/app/[locale]/timesheet/components/CalendarView.tsx rename to apps/web/app/[locale]/timesheet/[memberId]/components/CalendarView.tsx diff --git a/apps/web/app/[locale]/timesheet/components/FilterWithStatus.tsx b/apps/web/app/[locale]/timesheet/[memberId]/components/FilterWithStatus.tsx similarity index 93% rename from apps/web/app/[locale]/timesheet/components/FilterWithStatus.tsx rename to apps/web/app/[locale]/timesheet/[memberId]/components/FilterWithStatus.tsx index f03c3f2e4..008a1fa04 100644 --- a/apps/web/app/[locale]/timesheet/components/FilterWithStatus.tsx +++ b/apps/web/app/[locale]/timesheet/[memberId]/components/FilterWithStatus.tsx @@ -26,11 +26,11 @@ export function FilterWithStatus({ key={index} className={clsxm( 'group flex items-center justify-start h-[2.2rem] rounded-xl border w-full', - 'dark:bg-dark--theme-light dark:border-gray-700 bg-[#e2e8f0aa] text[#71717A] w-[80px]', + 'dark:bg-dark--theme-light dark:border-gray-700 bg-transparent text[#71717A] w-[80px]', activeStatus === label && 'text-primary bg-white shadow-lg font-bold' )} onClick={() => onToggle(label)}> - {label} + {label} {count} ))} diff --git a/apps/web/app/[locale]/timesheet/components/FrequencySelect.tsx b/apps/web/app/[locale]/timesheet/[memberId]/components/FrequencySelect.tsx similarity index 97% rename from apps/web/app/[locale]/timesheet/components/FrequencySelect.tsx rename to apps/web/app/[locale]/timesheet/[memberId]/components/FrequencySelect.tsx index f9cf9a678..d94137daf 100644 --- a/apps/web/app/[locale]/timesheet/components/FrequencySelect.tsx +++ b/apps/web/app/[locale]/timesheet/[memberId]/components/FrequencySelect.tsx @@ -39,7 +39,7 @@ export function FrequencySelect() {
@@ -122,7 +131,7 @@ function TimeSheetPage() {
{timesheetNavigator === 'ListView' ? - + : }
@@ -133,9 +142,9 @@ function TimeSheetPage() { ) -} +}) -export default withAuthentication(TimeSheetPage, { displayName: 'TimeSheet' }); +export default withAuthentication(TimeSheet, { displayName: 'TimeSheet' }); const FooterTimeSheet: React.FC = ({ fullWidth }) => { return ( diff --git a/apps/web/app/helpers/date.ts b/apps/web/app/helpers/date.ts index 5bc4349fa..c038dceeb 100644 --- a/apps/web/app/helpers/date.ts +++ b/apps/web/app/helpers/date.ts @@ -198,3 +198,20 @@ export function formatTimeString(timeString: string): string { return result.length ? result : '0h 00m'; } + +export const getGreeting = () => { + const GREETING_TIMES = { + MORNING_START: 5, + AFTERNOON_START: 12, + EVENING_START: 18 + } as const + const currentHour = new Date().getHours(); + + if (currentHour >= GREETING_TIMES.MORNING_START && currentHour < GREETING_TIMES.AFTERNOON_START) { + return "Good morning"; + } else if (currentHour >= GREETING_TIMES.AFTERNOON_START && currentHour < GREETING_TIMES.EVENING_START) { + return "Good afternoon"; + } else { + return "Good evening"; + } +} diff --git a/apps/web/components/app-sidebar.tsx b/apps/web/components/app-sidebar.tsx index 8465d56c1..44536f9a5 100644 --- a/apps/web/components/app-sidebar.tsx +++ b/apps/web/components/app-sidebar.tsx @@ -69,60 +69,60 @@ export function AppSidebar({ publicTeam, ...props }: AppSidebarProps) { items: favoriteTasks && favoriteTasks.length > 0 ? favoriteTasks - .sort((a, b) => a.title.toLowerCase().localeCompare(b.title.toLowerCase())) - .map((task, index) => ({ - title: task?.title, - url: '#', - component: ( - - - - {task && ( - // Show task issue and task number - - )} - - - #{task?.taskNumber} - - - {task?.title} - + .sort((a, b) => a.title.toLowerCase().localeCompare(b.title.toLowerCase())) + .map((task, index) => ({ + title: task?.title, + url: '#', + component: ( + + + + {task && ( + // Show task issue and task number + + )} + + + #{task?.taskNumber} + + + {task?.title} - - toggleFavorite(task)} - /> - - - ) - })) + + + toggleFavorite(task)} + /> + + + ) + })) : [ - { - title: t('common.NO_FAVORITE_TASK'), - url: '#', - label: 'no-task' - } - ] + { + title: t('common.NO_FAVORITE_TASK'), + url: '#', + label: 'no-task' + } + ] }, { title: t('sidebar.TASKS'), @@ -142,73 +142,73 @@ export function AppSidebar({ publicTeam, ...props }: AppSidebarProps) { }, ...(userManagedTeams && userManagedTeams.length > 0 ? [ - { - title: t('sidebar.PROJECTS'), - label: 'projects', - url: '#', - icon: FolderKanban, - items: [ - ...userManagedTeams - .sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase())) - .map((team, index) => ({ - title: team.name, - url: '#', - component: ( - - - - ) - })), - { - title: t('common.NO_PROJECT'), + { + title: t('sidebar.PROJECTS'), + label: 'projects', + url: '#', + icon: FolderKanban, + items: [ + ...userManagedTeams + .sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase())) + .map((team, index) => ({ + title: team.name, url: '#', component: ( - - + + + + + ) - } - ] - } - ] + })), + { + title: t('common.NO_PROJECT'), + url: '#', + component: ( + + + + ) + } + ] + } + ] : []), { title: t('sidebar.MY_WORKS'), @@ -227,42 +227,42 @@ export function AppSidebar({ publicTeam, ...props }: AppSidebarProps) { }, ...(isTeamManager ? [ - { - title: t('sidebar.REPORTS'), - url: '#', - icon: SquareActivity, - items: [ - { - title: t('sidebar.TIMESHEETS'), - url: '#' - }, - { - title: t('sidebar.MANUAL_TIME_EDIT'), - url: '#' - }, - { - title: t('sidebar.WEEKLY_LIMIT'), - url: '#' - }, - { - title: t('sidebar.ACTUAL_AND_EXPECTED_HOURS'), - url: '#' - }, - { - title: t('sidebar.PAYMENTS_DUE'), - url: '#' - }, - { - title: t('sidebar.PROJECT_BUDGET'), - url: '#' - }, - { - title: t('sidebar.TIME_AND_ACTIVITY'), - url: '#' - } - ] - } - ] + { + title: t('sidebar.REPORTS'), + url: '#', + icon: SquareActivity, + items: [ + { + title: t('sidebar.TIMESHEETS'), + url: `/timesheet/${user?.id}?name=${username || ''}` + }, + { + title: t('sidebar.MANUAL_TIME_EDIT'), + url: '#' + }, + { + title: t('sidebar.WEEKLY_LIMIT'), + url: '#' + }, + { + title: t('sidebar.ACTUAL_AND_EXPECTED_HOURS'), + url: '#' + }, + { + title: t('sidebar.PAYMENTS_DUE'), + url: '#' + }, + { + title: t('sidebar.PROJECT_BUDGET'), + url: '#' + }, + { + title: t('sidebar.TIME_AND_ACTIVITY'), + url: '#' + } + ] + } + ] : []) ] }; diff --git a/apps/web/components/ui/data-table.tsx b/apps/web/components/ui/data-table.tsx index 8a9ceaf8e..09c74e340 100644 --- a/apps/web/components/ui/data-table.tsx +++ b/apps/web/components/ui/data-table.tsx @@ -86,9 +86,9 @@ function DataTable({ columns, data, footerRows, isHeader }: DataT {header.isPlaceholder ? null : flexRender( - header.column.columnDef.header, - header.getContext() - )} + header.column.columnDef.header, + header.getContext() + )}
diff --git a/apps/web/lib/components/custom-select/multi-select.tsx b/apps/web/lib/components/custom-select/multi-select.tsx index a88cb2e65..3b8a298b4 100644 --- a/apps/web/lib/components/custom-select/multi-select.tsx +++ b/apps/web/lib/components/custom-select/multi-select.tsx @@ -1,8 +1,10 @@ +import { clsxm } from '@/app/utils'; import { Button } from '@components/ui/button'; import { Popover, PopoverContent, PopoverTrigger } from '@components/ui/popover'; import { cn } from 'lib/utils'; import { useEffect, useState, useRef } from 'react'; import { MdOutlineKeyboardArrowDown, MdClose } from 'react-icons/md'; +import { statusColor } from '..'; interface MultiSelectProps { items: T[]; @@ -134,7 +136,11 @@ export function MultiSelect({ {selectedItems.map((item) => (
{itemToString(item)} - - - -
+
+ + Page {table.getState().pagination.pageIndex + 1} of {table.getPageCount()} + + + + +
- + + ) } @@ -334,8 +335,6 @@ export function SelectFilter({ selectedStatus }: { selectedStatus?: string }) { default: return "text-gray-500 border-gray-200"; } - - }; @@ -409,11 +408,11 @@ const TaskActionMenu = ({ idTasks }: { idTasks: any }) => { const TaskDetails = ({ description, name }: { description: string; name: string }) => { return ( -
-
- ever +
+
+ ever
- + {name}
{description}
@@ -423,22 +422,43 @@ const TaskDetails = ({ description, name }: { description: string; name: string export const StatusTask = () => { return ( - - - Status - - - - {statusOptions?.map((status, index) => ( - + <> + + + Change status + + + + {statusOptions?.map((status, index) => ( + +
+
+ {status.label} +
+
+ ))} +
+
+
+ + + Billable + + + +
-
- {status.label} + Oui
- ))} -
-
-
+ +
+ No +
+
+
+
+
+ ) } diff --git a/apps/web/lib/features/integrations/calendar/time-sheet-filter-popover.tsx b/apps/web/lib/features/integrations/calendar/time-sheet-filter-popover.tsx index d441894e2..40a1eb39f 100644 --- a/apps/web/lib/features/integrations/calendar/time-sheet-filter-popover.tsx +++ b/apps/web/lib/features/integrations/calendar/time-sheet-filter-popover.tsx @@ -1,5 +1,5 @@ import { useOrganizationTeams, useTeamTasks } from "@app/hooks"; -import { Button } from "@components/ui/button" +import { Button } from "@components/ui/button"; import { Modal } from "lib/components"; import { statusOptions } from "@app/constants"; import { MultiSelect } from "lib/components/custom-select/multi-select"; diff --git a/apps/web/lib/features/user-profile-plans.tsx b/apps/web/lib/features/user-profile-plans.tsx index 0ec07b9c9..203d5808e 100644 --- a/apps/web/lib/features/user-profile-plans.tsx +++ b/apps/web/lib/features/user-profile-plans.tsx @@ -444,9 +444,8 @@ export function PlanHeader({ plan, planMode }: { plan: IDailyPlan; planMode: Fil return (
{/* Planned Time */} From cc4e2bc1b530398a2c57c9575371ac1740146dfc Mon Sep 17 00:00:00 2001 From: syns Date: Mon, 4 Nov 2024 00:42:07 +0700 Subject: [PATCH 3/5] feat: server web setup wizard (#3226) * feat: server web setup wizard * feat: server web setup wizard --------- Co-authored-by: nyomansutralia-jubelio --- apps/server-web/src/main/helpers/constant.ts | 1 + .../src/main/helpers/interfaces/i-server.ts | 1 + apps/server-web/src/main/main.ts | 50 ++++-- apps/server-web/src/renderer/App.css | 2 +- apps/server-web/src/renderer/App.tsx | 11 +- .../src/renderer/components/About.tsx | 2 +- .../src/renderer/components/Server.tsx | 4 +- .../src/renderer/components/SideBar.tsx | 4 +- .../src/renderer/components/Updater.tsx | 8 +- .../renderer/components/svgs/CheckIcon.tsx | 18 +++ apps/server-web/src/renderer/pages/Server.tsx | 12 +- apps/server-web/src/renderer/pages/Setup.tsx | 41 +++++ .../renderer/pages/setup/AdvancedSetting.tsx | 151 ++++++++++++++++++ .../src/renderer/pages/setup/Landing.tsx | 46 ++++++ 14 files changed, 322 insertions(+), 29 deletions(-) create mode 100644 apps/server-web/src/renderer/components/svgs/CheckIcon.tsx create mode 100644 apps/server-web/src/renderer/pages/Setup.tsx create mode 100644 apps/server-web/src/renderer/pages/setup/AdvancedSetting.tsx create mode 100644 apps/server-web/src/renderer/pages/setup/Landing.tsx diff --git a/apps/server-web/src/main/helpers/constant.ts b/apps/server-web/src/main/helpers/constant.ts index b6bc8e792..b2ebfcb96 100644 --- a/apps/server-web/src/main/helpers/constant.ts +++ b/apps/server-web/src/main/helpers/constant.ts @@ -17,6 +17,7 @@ export const EventLists = { SERVER_WINDOW: 'SERVER_WINDOW', RESTART_SERVER: 'RESTART_SERVER', CHANGE_THEME: 'CHANGE_THEME', + SETUP_WINDOW: 'SETUP_WINDOW' } export const SettingPageTypeMessage = { diff --git a/apps/server-web/src/main/helpers/interfaces/i-server.ts b/apps/server-web/src/main/helpers/interfaces/i-server.ts index 469c87b9d..072dcc572 100644 --- a/apps/server-web/src/main/helpers/interfaces/i-server.ts +++ b/apps/server-web/src/main/helpers/interfaces/i-server.ts @@ -3,6 +3,7 @@ interface GeneralConfig { autoUpdate?: boolean updateCheckPeriode?: string theme?: string + setup?: boolean [key: string]: any } diff --git a/apps/server-web/src/main/main.ts b/apps/server-web/src/main/main.ts index 33ad2a1c0..254355e84 100644 --- a/apps/server-web/src/main/main.ts +++ b/apps/server-web/src/main/main.ts @@ -1,4 +1,4 @@ -import path from 'path' +import path from 'path'; import { app, ipcMain, Tray, dialog, BrowserWindow, shell } from 'electron'; import { DesktopServer } from './helpers/desktop-server'; import { LocalStore } from './helpers/services/libs/desktop-store'; @@ -40,6 +40,7 @@ let intervalUpdate: NodeJS.Timeout; let tray: Tray; let settingWindow: BrowserWindow | null = null; let logWindow: BrowserWindow | null = null; +let setupWindow: BrowserWindow | any = null; let SettingMenu: any = null; let ServerWindowMenu: any = null; @@ -149,13 +150,14 @@ const installExtensions = async () => { }; -const createWindow = async (type: 'SETTING_WINDOW' | 'LOG_WINDOW') => { +const createWindow = async (type: 'SETTING_WINDOW' | 'LOG_WINDOW' | 'SETUP_WINDOW') => { if (isDebug) { await installExtensions(); } const defaultOptionWindow = { title: app.name, + frame: true, show: false, width: 1024, height: 728, @@ -199,6 +201,15 @@ const createWindow = async (type: 'SETTING_WINDOW' | 'LOG_WINDOW') => { } ServerWindowMenu.buildMenu(); break; + case 'SETUP_WINDOW': + setupWindow = new BrowserWindow(defaultOptionWindow); + url = resolveHtmlPath('index.html', 'setup'); + setupWindow?.loadURL(url); + mainBindings(ipcMain, setupWindow, fs); + setupWindow.on('closed', () => { + setupWindow = null; + }) + break; default: break; } @@ -418,7 +429,17 @@ const onInitApplication = () => { (async () => { await app.whenReady() - onInitApplication(); + const storeConfig:WebServer = LocalStore.getStore('config'); + if (storeConfig?.general?.setup) { + onInitApplication(); + } else { + if (!setupWindow) { + await createWindow('SETUP_WINDOW'); + } + if (setupWindow) { + setupWindow?.show() + } + } })() app.on('window-all-closed', () => { @@ -453,12 +474,23 @@ ipcMain.on(IPC_TYPES.SETTING_PAGE, async (event, arg) => { } } ) - event.sender.send(IPC_TYPES.SETTING_PAGE, { - type: SettingPageTypeMessage.mainResponse, data: { - status: true, - isServerRun: isServerRun - } - }); + if (arg.isSetup) { + LocalStore.updateConfigSetting({ + general: { + setup: true + } + }); + setupWindow?.close(); + onInitApplication(); + eventEmitter.emit(EventLists.SERVER_WINDOW); + } else { + event.sender.send(IPC_TYPES.SETTING_PAGE, { + type: SettingPageTypeMessage.mainResponse, data: { + status: true, + isServerRun: isServerRun + } + }); + } break; case SettingPageTypeMessage.checkUpdate: updater.checkUpdate(); diff --git a/apps/server-web/src/renderer/App.css b/apps/server-web/src/renderer/App.css index f6d269756..7ec5f474b 100644 --- a/apps/server-web/src/renderer/App.css +++ b/apps/server-web/src/renderer/App.css @@ -453,7 +453,7 @@ html.dark { } .switch-root[data-state='checked'] { - background-color: rgb(96 165 250/var(--tw-bg-opacity)); + @apply bg-violet-800 } .switch-thumb { diff --git a/apps/server-web/src/renderer/App.tsx b/apps/server-web/src/renderer/App.tsx index 3ad4a3986..dbeebce43 100644 --- a/apps/server-web/src/renderer/App.tsx +++ b/apps/server-web/src/renderer/App.tsx @@ -3,18 +3,20 @@ import { HashRouter as Router, Routes, Route } from 'react-router-dom'; import './App.css'; import { Setting } from './pages/Setting'; import i18next from 'i18next'; -import { ServerPage } from './pages/Server'; import { ThemeProvider, useTheme } from './ThemeContext'; +import SetupPage from './pages/Setup'; +import { ServerPage } from './pages/Server'; export default function App() { const [language, setLanguage] = useState('en'); const { theme } = useTheme(); const setTheme = async (htmlElement: HTMLElement) => { - const currentTheme = await window.electron.ipcRenderer.invoke('current-theme'); + const currentTheme = + await window.electron.ipcRenderer.invoke('current-theme'); htmlElement.classList.remove('dark', 'light'); htmlElement.classList.toggle(currentTheme || theme); - } + }; useEffect(() => { const htmlElement = document.documentElement; @@ -26,7 +28,7 @@ export default function App() { console.log(value); htmlElement.classList.remove('dark', 'light'); htmlElement.classList.toggle(value.data); - }) + }); i18next.changeLanguage(language); }, [language]); return ( @@ -35,6 +37,7 @@ export default function App() { } /> } /> + } /> diff --git a/apps/server-web/src/renderer/components/About.tsx b/apps/server-web/src/renderer/components/About.tsx index 2e8807d71..0a1260f48 100644 --- a/apps/server-web/src/renderer/components/About.tsx +++ b/apps/server-web/src/renderer/components/About.tsx @@ -4,7 +4,7 @@ import { IAbout } from '../libs/interfaces'; export const AboutComponent = (props: IAbout) => { return (
-
+
diff --git a/apps/server-web/src/renderer/components/Server.tsx b/apps/server-web/src/renderer/components/Server.tsx index 9acf59048..e985469b1 100644 --- a/apps/server-web/src/renderer/components/Server.tsx +++ b/apps/server-web/src/renderer/components/Server.tsx @@ -20,7 +20,7 @@ export const ServerComponent = (props: IServerComponent) => { <>
-
+
@@ -97,7 +97,7 @@ export const ServerComponent = (props: IServerComponent) => {
-
+
diff --git a/apps/server-web/src/renderer/components/svgs/CheckIcon.tsx b/apps/server-web/src/renderer/components/svgs/CheckIcon.tsx new file mode 100644 index 000000000..47ee82088 --- /dev/null +++ b/apps/server-web/src/renderer/components/svgs/CheckIcon.tsx @@ -0,0 +1,18 @@ +const CheckIcon = ({ className }: { className?: string }) => ( + + + +); + +export default CheckIcon; diff --git a/apps/server-web/src/renderer/pages/Server.tsx b/apps/server-web/src/renderer/pages/Server.tsx index ab018e213..be91e7efb 100644 --- a/apps/server-web/src/renderer/pages/Server.tsx +++ b/apps/server-web/src/renderer/pages/Server.tsx @@ -49,17 +49,17 @@ export function ServerPage() {
-
+
- Server Logs + Server Logs -
+
{logs.length > 0 && logs.map((log, i) => (
diff --git a/apps/server-web/src/renderer/pages/Setup.tsx b/apps/server-web/src/renderer/pages/Setup.tsx new file mode 100644 index 000000000..864466f1f --- /dev/null +++ b/apps/server-web/src/renderer/pages/Setup.tsx @@ -0,0 +1,41 @@ +import { useState } from 'react'; +import AdvancedSetting from './setup/AdvancedSetting'; +import Landing from './setup/Landing'; +import CheckIcon from '../components/svgs/CheckIcon'; +const steps: number[] = [1, 2]; +const SetupPage = () => { + const [currentStep, setCurrentStep] = useState(1); + + const letsGo = () => { + setCurrentStep(2); + }; + + const goBack = () => { + setCurrentStep(1); + }; + + return ( +
+
+
+
+ {currentStep === 1 ? 1 : } +
+
+
+ 2 +
+
+
+ {currentStep === 1 ? ( + + ) : ( + + )} +
+ ); +}; + +export default SetupPage; diff --git a/apps/server-web/src/renderer/pages/setup/AdvancedSetting.tsx b/apps/server-web/src/renderer/pages/setup/AdvancedSetting.tsx new file mode 100644 index 000000000..9dc92f497 --- /dev/null +++ b/apps/server-web/src/renderer/pages/setup/AdvancedSetting.tsx @@ -0,0 +1,151 @@ +import { useTranslation } from 'react-i18next'; +import { IServerSetting } from '../../libs/interfaces'; +import { useState } from 'react'; +import { SettingPageTypeMessage } from '../../libs/constant'; +type Props = { + back: () => void; +}; + +const AdvancedSetting = (props: Props) => { + const { t } = useTranslation(); + const [serverSetting, setServerSetting] = useState({ + PORT: 3000, + GAUZY_API_SERVER_URL: 'http://localhost:3030', + NEXT_PUBLIC_GAUZY_API_SERVER_URL: 'http://localhost:3030', + }); + const saveSetting = (e: any) => { + e.preventDefault(); + + window.electron.ipcRenderer.sendMessage('setting-page', { + data: serverSetting, + type: SettingPageTypeMessage.saveSetting, + isSetup: true, + }); + }; + const handleChange = (event: any) => { + const { id, value } = event.target; + setServerSetting((prevData: any) => ({ ...prevData, [id]: value })); + }; + return ( + <> +
+

+ Are you ready for some advanced settings? +

+

+ This is the final step where you can get to the nitty-gritty of your + Gauzy Platform. +

+
+ + {/* Input Fields */} + +
+
+
+
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+
+ {/* Buttons */} +
+ +
+ + +
+
+ + + ); +}; + +export default AdvancedSetting; diff --git a/apps/server-web/src/renderer/pages/setup/Landing.tsx b/apps/server-web/src/renderer/pages/setup/Landing.tsx new file mode 100644 index 000000000..06ee23568 --- /dev/null +++ b/apps/server-web/src/renderer/pages/setup/Landing.tsx @@ -0,0 +1,46 @@ +import { EverTeamsLogo } from '../../components/svgs/index'; +type props = { + nextAction: () => void; +}; +const Landing = (props: props) => { + return ( +
+
+ +
+ +
+
+ +
+

+ Welcome to Ever® Teams - Open-Source Business Management Platform + (ERP/CRM/HRM) +

+

+ Ever Teams Desktop App provides the full functionality of the Gauzy + Platform available directly on your desktop computer or a laptop. In + addition, it allows tracking work time, activity recording, and the + ability to receive tracking reminders/notifications. +

+
+ + {/* Button */} +
+ +
+
+ ); +}; + +export default Landing; From 448fb961a997683f33f0b05aac7c1b25e42af7ea Mon Sep 17 00:00:00 2001 From: AKILIMAILI CIZUNGU Innocent <51681130+Innocent-Akim@users.noreply.github.com> Date: Sun, 3 Nov 2024 21:32:03 +0200 Subject: [PATCH 4/5] [Feat]: Add Multilingual Support for Timesheet Component (#3225) * feat: Add multilingual support for timesheet component * fix: bug * improv: update multilingual support for timesheet component * fix: change * fix: sug-coderabbita * fix: deepscan --- .../components/FilterWithStatus.tsx | 6 ++--- .../[memberId]/components/FrequencySelect.tsx | 2 +- .../[memberId]/components/TimesheetAction.tsx | 18 +++++++------ .../[memberId]/components/TimesheetCard.tsx | 4 ++- .../[memberId]/components/TimesheetView.tsx | 20 +++++++++++--- .../[locale]/timesheet/[memberId]/page.tsx | 15 +++++++---- apps/web/app/helpers/date.ts | 9 ++++--- .../calendar/table-time-sheet.tsx | 11 +++++--- apps/web/locales/ar.json | 23 ++++++++++++++++ apps/web/locales/bg.json | 23 ++++++++++++++++ apps/web/locales/de.json | 27 +++++++++++++++++-- apps/web/locales/en.json | 23 ++++++++++++++++ apps/web/locales/es.json | 23 ++++++++++++++++ apps/web/locales/fr.json | 23 ++++++++++++++++ apps/web/locales/he.json | 23 ++++++++++++++++ apps/web/locales/it.json | 23 ++++++++++++++++ apps/web/locales/nl.json | 23 ++++++++++++++++ apps/web/locales/pl.json | 23 ++++++++++++++++ apps/web/locales/pt.json | 23 ++++++++++++++++ apps/web/locales/ru.json | 23 ++++++++++++++++ apps/web/locales/zh.json | 23 ++++++++++++++++ 21 files changed, 357 insertions(+), 31 deletions(-) diff --git a/apps/web/app/[locale]/timesheet/[memberId]/components/FilterWithStatus.tsx b/apps/web/app/[locale]/timesheet/[memberId]/components/FilterWithStatus.tsx index 008a1fa04..14d66eb2c 100644 --- a/apps/web/app/[locale]/timesheet/[memberId]/components/FilterWithStatus.tsx +++ b/apps/web/app/[locale]/timesheet/[memberId]/components/FilterWithStatus.tsx @@ -25,9 +25,9 @@ export function FilterWithStatus({