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; 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 90% rename from apps/web/app/[locale]/timesheet/components/FilterWithStatus.tsx rename to apps/web/app/[locale]/timesheet/[memberId]/components/FilterWithStatus.tsx index f03c3f2e4..14d66eb2c 100644 --- a/apps/web/app/[locale]/timesheet/components/FilterWithStatus.tsx +++ b/apps/web/app/[locale]/timesheet/[memberId]/components/FilterWithStatus.tsx @@ -25,12 +25,12 @@ export function FilterWithStatus({ ))} 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..df8b3054c 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() {
{/* */}
- +
{timesheetNavigator === 'ListView' ? - + : }
@@ -133,9 +154,9 @@ function TimeSheetPage() { ) -} +}) -export default withAuthentication(TimeSheetPage, { displayName: 'TimeSheet' }); +export default withAuthentication(TimeSheet, { displayName: 'TimeSheet' }); const FooterTimeSheet: React.FC = ({ fullWidth }) => { return ( @@ -154,7 +175,8 @@ const ViewToggleButton: React.FC = ({ mode, active, icon, - onClick + onClick, + t }) => ( ); diff --git a/apps/web/app/[locale]/timesheet/components/TimesheetFilter.tsx b/apps/web/app/[locale]/timesheet/components/TimesheetFilter.tsx deleted file mode 100644 index 9249a9036..000000000 --- a/apps/web/app/[locale]/timesheet/components/TimesheetFilter.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { FilterWithStatus } from './FilterWithStatus'; -import { FilterTaskActionMenu, FrequencySelect } from '.'; -import { Button } from 'lib/components'; -import { TimeSheetFilterPopover } from './time-sheet-filter-popover'; -import { Cross2Icon } from '@radix-ui/react-icons'; - -export function TimesheetFilter() { - return ( - <> - -
-
- { - // TODO: Implement filter toggle handler - }} - /> -
-
-
- -
- - -
- - -
-
-
- - - ) -} diff --git a/apps/web/app/[locale]/timesheet/components/TimesheetView.tsx b/apps/web/app/[locale]/timesheet/components/TimesheetView.tsx deleted file mode 100644 index 3d29bb856..000000000 --- a/apps/web/app/[locale]/timesheet/components/TimesheetView.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { DataTableTimeSheet } from 'lib/features/integrations/calendar' - -export function TimesheetView() { - return ( -
- -
- ) -} diff --git a/apps/web/app/helpers/date.ts b/apps/web/app/helpers/date.ts index 5bc4349fa..436b6c5c4 100644 --- a/apps/web/app/helpers/date.ts +++ b/apps/web/app/helpers/date.ts @@ -1,5 +1,6 @@ import moment from 'moment'; import * as momentTimezone from 'moment-timezone'; +import { TranslationHooks } from 'next-intl'; const months: { [key: string]: string } = { '01': 'January', @@ -198,3 +199,29 @@ export function formatTimeString(timeString: string): string { return result.length ? result : '0h 00m'; } + +export const getGreeting = (t: TranslationHooks) => { + 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 t('pages.timesheet.GREETINGS.GOOD_MORNING'); + } else if (currentHour >= GREETING_TIMES.AFTERNOON_START && currentHour < GREETING_TIMES.EVENING_START) { + return t('pages.timesheet.GREETINGS.GOOD_AFTERNOON'); + } else { + return t('pages.timesheet.GREETINGS.GOOD_EVENING'); + } +} + +export const formatDate = (dateStr: string | Date): string => { + try { + return moment(dateStr).format('ddd DD MMM YYYY'); + } catch (error) { + console.error('Invalid date format:', error); + return ''; + } +} 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 +347,6 @@ export function SelectFilter({ selectedStatus }: { selectedStatus?: string }) { default: return "text-gray-500 border-gray-200"; } - - }; @@ -409,11 +420,11 @@ const TaskActionMenu = ({ idTasks }: { idTasks: any }) => { const TaskDetails = ({ description, name }: { description: string; name: string }) => { return ( -
-
- ever +
+
+ ever
- + {name}
{description}
@@ -422,23 +433,45 @@ const TaskDetails = ({ description, name }: { description: string; name: string }; export const StatusTask = () => { + const t = useTranslations(); return ( - - - Status - - - - {statusOptions?.map((status, index) => ( - + <> + + + Change status + + + + {statusOptions?.map((status, index) => ( + +
+
+ {status.label} +
+
+ ))} +
+
+
+ + + Billable + + + +
-
- {status.label} + {t('pages.timesheet.BILLABLE.YES')}
- ))} -
-
-
+ +
+ {t('pages.timesheet.BILLABLE.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 */} diff --git a/apps/web/locales/ar.json b/apps/web/locales/ar.json index bdec23370..83d083624 100644 --- a/apps/web/locales/ar.json +++ b/apps/web/locales/ar.json @@ -549,6 +549,29 @@ "maintenance": { "HEADING_TITLE": "نحن تحت الصيانة", "HEADING_DESCRIPTION": "نقوم حاليًا بتحديث موقعنا الإلكتروني لخدمتك بشكل أفضل. يرجى التحقق مرة أخرى في وقت لاحق." + }, + "timesheet": { + "TIMESHEET_TITLE": "سجل الساعات", + "TIMESHEET_VIEW_DETAILS": "عرض التفاصيل", + "TIMESHEET_ACTION_APPROVE_SELECTED": "الموافقة على المحدد", + "TIMESHEET_ACTION_REJECT_SELECTED": "رفض المحدد", + "TIMESHEET_ACTION_DELETE_SELECTED": "حذف المحدد", + "HEADING_DESCRIPTION": "هذا هو لوحة المعلومات الشخصية الخاصة بك، تظهر لك ما يحتاج إلى انتباهك الآن.", + "GREETINGS": { + "GOOD_MORNING": "صباح الخير", + "GOOD_AFTERNOON": "مساء الخير", + "GOOD_EVENING": "مساء الخير" + }, + "VIEWS": { + "LIST": "عرض القائمة", + "CALENDAR": "عرض التقويم" + }, + "BILLABLE": { + "YES": "نعم", + "NO": "لا" + }, + "LOADING": "جارٍ تحميل بيانات سجل الزمن...", + "NO_ENTRIES_FOUND": "لم يتم العثور على إدخالات سجل الزمن" } }, "timer": { diff --git a/apps/web/locales/bg.json b/apps/web/locales/bg.json index 212bbb4f6..691dedbf5 100644 --- a/apps/web/locales/bg.json +++ b/apps/web/locales/bg.json @@ -549,6 +549,29 @@ "maintenance": { "HEADING_TITLE": "Ние сме в процес на поддръжка", "HEADING_DESCRIPTION": "В момента актуализираме нашия уебсайт, за да ви служим по-добре. Моля, проверете отново по-късно." + }, + "timesheet": { + "TIMESHEET_TITLE": "Таблица на часовете", + "TIMESHEET_VIEW_DETAILS": "Преглед на детайлите", + "TIMESHEET_ACTION_APPROVE_SELECTED": "Одобрете избраното", + "TIMESHEET_ACTION_REJECT_SELECTED": "Отхвърлете избраното", + "TIMESHEET_ACTION_DELETE_SELECTED": "Изтрийте избраното", + "HEADING_DESCRIPTION": "Това е вашата лична табло на часовете, показваща какво изисква вашето внимание сега.", + "GREETINGS": { + "GOOD_MORNING": "Добро утро", + "GOOD_AFTERNOON": "Добър следобед", + "GOOD_EVENING": "Добър вечер" + }, + "VIEWS": { + "LIST": "Списъчен изглед", + "CALENDAR": "Календарен изглед" + }, + "BILLABLE": { + "YES": "Да", + "NO": "Не" + }, + "LOADING": "Зареждане на данни за таблицата на работното време...", + "NO_ENTRIES_FOUND": "Няма намерени записи за таблицата на работното време" } }, "timer": { diff --git a/apps/web/locales/de.json b/apps/web/locales/de.json index f8a4ee4ed..a0e5e703a 100644 --- a/apps/web/locales/de.json +++ b/apps/web/locales/de.json @@ -547,8 +547,31 @@ "HEADING_DESCRIPTION": "If the problem persists, send a distress signal to our support team." }, "maintenance": { - "HEADING_TITLE": "We zijn in onderhoud ", - "HEADING_DESCRIPTION": "Momenteel zijn wij onze website aan het vernieuwen om u nog beter van dienst te kunnen zijn. Kom later nog eens terug." + "HEADING_TITLE": "Wir führen Wartungsarbeiten durch", + "HEADING_DESCRIPTION": "Wir aktualisieren derzeit unsere Website, um Ihnen einen noch besseren Service bieten zu können. Bitte versuchen Sie es später erneut." + }, + "timesheet": { + "TIMESHEET_TITLE": "Zeiterfassung", + "TIMESHEET_VIEW_DETAILS": "Details anzeigen", + "TIMESHEET_ACTION_APPROVE_SELECTED": "Ausgewählte genehmigen", + "TIMESHEET_ACTION_REJECT_SELECTED": "Ausgewählte ablehnen", + "TIMESHEET_ACTION_DELETE_SELECTED": "Ausgewählte löschen", + "HEADING_DESCRIPTION": "Dies ist Ihr persönliches Zeiterfassungs-Dashboard, das Ihnen zeigt, was jetzt Ihre Aufmerksamkeit erfordert.", + "GREETINGS": { + "GOOD_MORNING": "Guten Morgen", + "GOOD_AFTERNOON": "Guten Nachmittag", + "GOOD_EVENING": "Guten Abend" + }, + "VIEWS": { + "LIST": "Listenansicht", + "CALENDAR": "Kalenderansicht" + }, + "BILLABLE": { + "YES": "Ja", + "NO": "Nein" + }, + "LOADING": "Lade Zeiterfassungsdaten...", + "NO_ENTRIES_FOUND": "Keine Zeiterfassungseinträge gefunden" } }, "timer": { diff --git a/apps/web/locales/en.json b/apps/web/locales/en.json index 6a6a5eb34..dfb46581c 100644 --- a/apps/web/locales/en.json +++ b/apps/web/locales/en.json @@ -549,6 +549,29 @@ "maintenance": { "HEADING_TITLE": "We are Under Maintenance", "HEADING_DESCRIPTION": "We are updating our website to serve you better. Please check back later." + }, + "timesheet": { + "TIMESHEET_TITLE": "Timesheet", + "TIMESHEET_VIEW_DETAILS": "View Details", + "TIMESHEET_ACTION_APPROVE_SELECTED": "Approve selected", + "TIMESHEET_ACTION_REJECT_SELECTED": "Reject selected", + "TIMESHEET_ACTION_DELETE_SELECTED": "Delete selected", + "HEADING_DESCRIPTION": "This is your personal timesheet dashboard, showing you what needs your attention now.", + "GREETINGS": { + "GOOD_MORNING": "Good morning", + "GOOD_AFTERNOON": "Good afternoon", + "GOOD_EVENING": "Good evening" + }, + "VIEWS": { + "LIST": "List View", + "CALENDAR": "Calendar View" + }, + "BILLABLE": { + "YES": "Yes", + "NO": "No" + }, + "LOADING": "Loading timesheet data...", + "NO_ENTRIES_FOUND": "No timesheet entries found" } }, "timer": { diff --git a/apps/web/locales/es.json b/apps/web/locales/es.json index 0eaea9f01..5502d47b5 100644 --- a/apps/web/locales/es.json +++ b/apps/web/locales/es.json @@ -549,6 +549,29 @@ "maintenance": { "HEADING_TITLE": "Estamos en Mantenimiento", "HEADING_DESCRIPTION": "Actualmente estamos actualizando nuestro sitio web para brindarle un mejor servicio. Por favor, vuelva más tarde." + }, + "timesheet": { + "TIMESHEET_TITLE": "Hoja de horas", + "TIMESHEET_VIEW_DETAILS": "Ver detalles", + "TIMESHEET_ACTION_APPROVE_SELECTED": "Aprobar seleccionados", + "TIMESHEET_ACTION_REJECT_SELECTED": "Rechazar seleccionados", + "TIMESHEET_ACTION_DELETE_SELECTED": "Eliminar seleccionados", + "HEADING_DESCRIPTION": "Este es tu panel personal de hoja de horas, que muestra lo que necesita tu atención ahora.", + "GREETINGS": { + "GOOD_MORNING": "Buenos días", + "GOOD_AFTERNOON": "Buenas tardes", + "GOOD_EVENING": "Buenas noches" + }, + "VIEWS": { + "LIST": "Vista de lista", + "CALENDAR": "Vista de calendario" + }, + "BILLABLE": { + "YES": "Sí", + "NO": "No" + }, + "LOADING": "Cargando datos del registro de horas...", + "NO_ENTRIES_FOUND": "No se encontraron entradas en el registro de horas" } }, "timer": { diff --git a/apps/web/locales/fr.json b/apps/web/locales/fr.json index a3e544ac3..ffbd13c0a 100644 --- a/apps/web/locales/fr.json +++ b/apps/web/locales/fr.json @@ -549,6 +549,29 @@ "maintenance": { "HEADING_TITLE": "Nous sommes en cours de maintenance", "HEADING_DESCRIPTION": "Nous mettons actuellement à jour notre site Web pour mieux vous servir. Veuillez revenir plus tard." + }, + "timesheet": { + "TIMESHEET_TITLE": "Feuille de temps", + "TIMESHEET_VIEW_DETAILS": "Voir les détails", + "TIMESHEET_ACTION_APPROVE_SELECTED": "Approuver sélectionné", + "TIMESHEET_ACTION_REJECT_SELECTED": "Rejeter sélectionné", + "TIMESHEET_ACTION_DELETE_SELECTED": "Supprimer sélectionné", + "HEADING_DESCRIPTION": "Ceci est votre tableau de bord de feuille de temps personnel, montrant ce qui nécessite votre attention maintenant.", + "GREETINGS": { + "GOOD_MORNING": "Bonjour", + "GOOD_AFTERNOON": "Bon après-midi", + "GOOD_EVENING": "Bonsoir" + }, + "VIEWS": { + "LIST": "Vue en liste", + "CALENDAR": "Vue calendrier" + }, + "BILLABLE": { + "YES": "Oui", + "NO": "Non" + }, + "LOADING": "Chargement des données de la feuille de temps...", + "NO_ENTRIES_FOUND": "Aucune entrée de feuille de temps trouvée" } }, "timer": { diff --git a/apps/web/locales/he.json b/apps/web/locales/he.json index 244cb1a47..c66276ce6 100644 --- a/apps/web/locales/he.json +++ b/apps/web/locales/he.json @@ -549,6 +549,29 @@ "maintenance": { "HEADING_TITLE": "אנחנו בשלבי תחזוקה ", "HEADING_DESCRIPTION": "אנו מעדכנים כעת את האתר שלנו כדי לשרת אותך טוב יותר. אנא בדוק שוב מאוחר יותר." + }, + "timesheet": { + "TIMESHEET_TITLE": "דוח שעות", + "TIMESHEET_VIEW_DETAILS": "ראה פרטים", + "TIMESHEET_ACTION_APPROVE_SELECTED": "אשר נבחרים", + "TIMESHEET_ACTION_REJECT_SELECTED": "דחה נבחרים", + "TIMESHEET_ACTION_DELETE_SELECTED": "מחק נבחרים", + "HEADING_DESCRIPTION": "זהו לוח הבקרה האישי שלך לדוח שעות, שמראה לך מה דורש את תשומת הלב שלך עכשיו.", + "GREETINGS": { + "GOOD_MORNING": "בוקר טוב", + "GOOD_AFTERNOON": "אחר הצהריים טובים", + "GOOD_EVENING": "ערב טוב" + }, + "VIEWS": { + "LIST": "תצוגת רשימה", + "CALENDAR": "תצוגת לוח שנה" + }, + "BILLABLE": { + "YES": "כן", + "NO": "לא" + }, + "LOADING": "טוען נתוני רשומת זמן...", + "NO_ENTRIES_FOUND": "לא נמצאו רשומות זמן" } }, "timer": { diff --git a/apps/web/locales/it.json b/apps/web/locales/it.json index 1967352cb..f33c63449 100644 --- a/apps/web/locales/it.json +++ b/apps/web/locales/it.json @@ -549,6 +549,29 @@ "maintenance": { "HEADING_TITLE": "Siamo in manutenzione", "HEADING_DESCRIPTION": "Stiamo attualmente aggiornando il nostro sito web per servirti meglio. Per favore controllare più tardi." + }, + "timesheet": { + "TIMESHEET_TITLE": "Foglio presenze", + "TIMESHEET_VIEW_DETAILS": "Visualizza dettagli", + "TIMESHEET_ACTION_APPROVE_SELECTED": "Approva selezionati", + "TIMESHEET_ACTION_REJECT_SELECTED": "Rifiuta selezionati", + "TIMESHEET_ACTION_DELETE_SELECTED": "Elimina selezionati", + "HEADING_DESCRIPTION": "Questo è il tuo cruscotto personale del foglio presenze, che mostra cosa richiede la tua attenzione adesso.", + "GREETINGS": { + "GOOD_MORNING": "Buongiorno", + "GOOD_AFTERNOON": "Buon pomeriggio", + "GOOD_EVENING": "Buona sera" + }, + "VIEWS": { + "LIST": "Visualizzazione elenco", + "CALENDAR": "Visualizzazione calendario" + }, + "BILLABLE": { + "YES": "Sì", + "NO": "No" + }, + "LOADING": "Caricamento dati della registrazione ore...", + "NO_ENTRIES_FOUND": "Nessuna voce di registrazione ore trovata" } }, "timer": { diff --git a/apps/web/locales/nl.json b/apps/web/locales/nl.json index dbd56de8c..8ea73e7ce 100644 --- a/apps/web/locales/nl.json +++ b/apps/web/locales/nl.json @@ -549,6 +549,29 @@ "maintenance": { "HEADING_TITLE": "Wij zijn in onderhoud", "HEADING_DESCRIPTION": "Momenteel zijn wij onze website aan het vernieuwen om u nog beter van dienst te kunnen zijn. Kom later nog eens terug." + }, + "timesheet": { + "TIMESHEET_TITLE": "Urenregistratie", + "TIMESHEET_VIEW_DETAILS": "Bekijk details", + "TIMESHEET_ACTION_APPROVE_SELECTED": "Goedkeuren geselecteerde", + "TIMESHEET_ACTION_REJECT_SELECTED": "Afwijzen geselecteerde", + "TIMESHEET_ACTION_DELETE_SELECTED": "Verwijder geselecteerde", + "HEADING_DESCRIPTION": "Dit is jouw persoonlijke urenregistratie-dashboard, dat laat zien wat jouw aandacht nu vereist.", + "GREETINGS": { + "GOOD_MORNING": "Goedemorgen", + "GOOD_AFTERNOON": "Goedemiddag", + "GOOD_EVENING": "Goedenavond" + }, + "VIEWS": { + "LIST": "Lijstweergave", + "CALENDAR": "Kalenderweergave" + }, + "BILLABLE": { + "YES": "Ja", + "NO": "Nee" + }, + "LOADING": "Tijdregistratiegegevens laden...", + "NO_ENTRIES_FOUND": "Geen tijdregistratie-invoeren gevonden" } }, "timer": { diff --git a/apps/web/locales/pl.json b/apps/web/locales/pl.json index c63478c43..4dbbaa5a1 100644 --- a/apps/web/locales/pl.json +++ b/apps/web/locales/pl.json @@ -549,6 +549,29 @@ "maintenance": { "HEADING_TITLE": "Jesteśmy w trakcie konserwacji", "HEADING_DESCRIPTION": "Obecnie aktualizujemy naszą stronę internetową, aby lepiej Ci służyć. Sprawdź ponownie później." + }, + "timesheet": { + "TIMESHEET_TITLE": "Arkusz czasu", + "TIMESHEET_VIEW_DETAILS": "Zobacz szczegóły", + "TIMESHEET_ACTION_APPROVE_SELECTED": "Zatwierdź zaznaczone", + "TIMESHEET_ACTION_REJECT_SELECTED": "Odrzuć zaznaczone", + "TIMESHEET_ACTION_DELETE_SELECTED": "Usuń zaznaczone", + "HEADING_DESCRIPTION": "To jest Twoje osobiste dashboard arkusza czasu, pokazujące, co wymaga Twojej uwagi teraz.", + "GREETINGS": { + "GOOD_MORNING": "Dzień dobry", + "GOOD_AFTERNOON": "Dobry wieczór", + "GOOD_EVENING": "Dobry wieczór" + }, + "VIEWS": { + "LIST": "Widok listy", + "CALENDAR": "Widok kalendarza" + }, + "BILLABLE": { + "YES": "Tak", + "NO": "Nie" + }, + "LOADING": "Ładowanie danych rejestru czasu...", + "NO_ENTRIES_FOUND": "Nie znaleziono żadnych wpisów w rejestrze czasu" } }, "timer": { diff --git a/apps/web/locales/pt.json b/apps/web/locales/pt.json index 91ed9959b..504c398d7 100644 --- a/apps/web/locales/pt.json +++ b/apps/web/locales/pt.json @@ -549,6 +549,29 @@ "maintenance": { "HEADING_TITLE": "Estamos em manutenção", "HEADING_DESCRIPTION": "Estamos atualizando nosso site para melhor atendê-lo. Por favor, volte mais tarde." + }, + "timesheet": { + "TIMESHEET_TITLE": "Folha de ponto", + "TIMESHEET_VIEW_DETAILS": "Ver detalhes", + "TIMESHEET_ACTION_APPROVE_SELECTED": "Aprovar selecionados", + "TIMESHEET_ACTION_REJECT_SELECTED": "Rejeitar selecionados", + "TIMESHEET_ACTION_DELETE_SELECTED": "Excluir selecionados", + "HEADING_DESCRIPTION": "Este é o seu painel de controle pessoal de folha de ponto, mostrando o que precisa da sua atenção agora.", + "GREETINGS": { + "GOOD_MORNING": "Bom dia", + "GOOD_AFTERNOON": "Boa tarde", + "GOOD_EVENING": "Boa noite" + }, + "VIEWS": { + "LIST": "Visualização em lista", + "CALENDAR": "Visualização em calendário" + }, + "BILLABLE": { + "YES": "Sim", + "NO": "Não" + }, + "LOADING": "Загрузка данных учета рабочего времени...", + "NO_ENTRIES_FOUND": "Записи учета рабочего времени не найдены" } }, "timer": { diff --git a/apps/web/locales/ru.json b/apps/web/locales/ru.json index fe3e0d40b..a4f68ed9f 100644 --- a/apps/web/locales/ru.json +++ b/apps/web/locales/ru.json @@ -549,6 +549,29 @@ "maintenance": { "HEADING_TITLE": "Мы на обслуживании ", "HEADING_DESCRIPTION": "В настоящее время мы обновляем наш веб-сайт, чтобы лучше обслуживать вас. Пожалуйста, зайдите позже." + }, + "timesheet": { + "TIMESHEET_TITLE": "Учёт рабочего времени", + "TIMESHEET_VIEW_DETAILS": "Просмотреть детали", + "TIMESHEET_ACTION_APPROVE_SELECTED": "Одобрить выбранные", + "TIMESHEET_ACTION_REJECT_SELECTED": "Отклонить выбранные", + "TIMESHEET_ACTION_DELETE_SELECTED": "Удалить выбранные", + "HEADING_DESCRIPTION": "Это ваша личная панель учёта рабочего времени, показывающая, что требует вашего внимания сейчас.", + "GREETINGS": { + "GOOD_MORNING": "Доброе утро", + "GOOD_AFTERNOON": "Добрый день", + "GOOD_EVENING": "Добрый вечер" + }, + "VIEWS": { + "LIST": "Список", + "CALENDAR": "Календарь" + }, + "BILLABLE": { + "YES": "Да", + "NO": "Нет" + }, + "LOADING": "Загрузка данных учета времени...", + "NO_ENTRIES_FOUND": "Записи учета времени не найдены" } }, "timer": { diff --git a/apps/web/locales/zh.json b/apps/web/locales/zh.json index 6861f64ce..b3e8d1cdc 100644 --- a/apps/web/locales/zh.json +++ b/apps/web/locales/zh.json @@ -549,6 +549,29 @@ "maintenance": { "HEADING_TITLE": "我們正在維護中", "HEADING_DESCRIPTION": "目前,我們正在更新我們的網站,以便更好地為您服務。請稍後再回來查看。" + }, + "timesheet": { + "TIMESHEET_TITLE": "工时表", + "TIMESHEET_VIEW_DETAILS": "查看详情", + "TIMESHEET_ACTION_APPROVE_SELECTED": "批准选定的", + "TIMESHEET_ACTION_REJECT_SELECTED": "拒绝选定的", + "TIMESHEET_ACTION_DELETE_SELECTED": "删除选定的", + "HEADING_DESCRIPTION": "这是您的个人工时表仪表板,显示需要您注意的事项。", + "GREETINGS": { + "GOOD_MORNING": "早上好", + "GOOD_AFTERNOON": "下午好", + "GOOD_EVENING": "晚上好" + }, + "VIEWS": { + "LIST": "列表视图", + "CALENDAR": "日历视图" + }, + "BILLABLE": { + "YES": "是", + "NO": "否" + }, + "LOADING": "Cargando datos de registro de horas...", + "NO_ENTRIES_FOUND": "No se encontraron entradas de registro de horas" } }, "timer": {