diff --git a/apps/web/app/[locale]/timesheet/[memberId]/components/CalendarView.tsx b/apps/web/app/[locale]/timesheet/[memberId]/components/CalendarView.tsx index 584cf19df..360aced88 100644 --- a/apps/web/app/[locale]/timesheet/[memberId]/components/CalendarView.tsx +++ b/apps/web/app/[locale]/timesheet/[memberId]/components/CalendarView.tsx @@ -1,22 +1,47 @@ import { GroupedTimesheet, useTimesheet } from "@/app/hooks/features/useTimesheet"; -import { clsxm } from "@/app/utils"; import { statusColor } from "@/lib/components"; import { DisplayTimeForTimesheet, TaskNameInfoDisplay, TotalDurationByDate, TotalTimeDisplay } from "@/lib/features"; -import { AccordionContent, AccordionItem, AccordionTrigger } from "@components/ui/accordion"; -import { Accordion } from "@radix-ui/react-accordion"; +import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@components/ui/accordion"; import { TranslationHooks, useTranslations } from "next-intl"; import React from "react"; -import { EmployeeAvatar } from "./CompactTimesheetComponent"; +import { EmployeeAvatar, ProjectLogo } from "./CompactTimesheetComponent"; import { formatDate } from "@/app/helpers"; -import { ClockIcon } from "lucide-react"; +import { ClockIcon, CodeSquareIcon } from "lucide-react"; +import { cn } from "@/lib/utils"; +import MonthlyTimesheetCalendar from "./MonthlyTimesheetCalendar"; +import { useTimelogFilterOptions } from "@/app/hooks"; +import WeeklyTimesheetCalendar from "./WeeklyTimesheetCalendar"; +interface BaseCalendarDataViewProps { + data: GroupedTimesheet[]; + daysLabels?: string[]; + CalendarComponent: typeof MonthlyTimesheetCalendar | typeof WeeklyTimesheetCalendar; +} export function CalendarView({ data, loading }: { data?: GroupedTimesheet[], loading: boolean }) { const t = useTranslations(); + const { timesheetGroupByDays } = useTimelogFilterOptions(); + const defaultDaysLabels = [ + t("common.DAYS.sun"), + t("common.DAYS.mon"), + t("common.DAYS.tue"), + t("common.DAYS.wed"), + t("common.DAYS.thu"), + t("common.DAYS.fri"), + t("common.DAYS.sat") + ]; return ( -
+
{data ? ( data.length > 0 ? ( - + <> + {timesheetGroupByDays === 'Monthly' ? ( + + ) : timesheetGroupByDays === 'Weekly' ? ( + + ) : ( + + )} + ) : (

{t('pages.timesheet.NO_ENTRIES_FOUND')}

@@ -40,7 +65,7 @@ const CalendarDataView = ({ data, t }: { data?: GroupedTimesheet[], t: Translati {data?.map((plan, index) => { return
0 && status && + className="p-1 rounded" > + )}>
-
+
{status === 'DENIED' ? 'REJECTED' : status} @@ -97,10 +120,9 @@ const CalendarDataView = ({ data, t }: { data?: GroupedTimesheet[], t: Translati borderLeftColor: statusColor(status).border }} - className={clsxm( + className={cn( 'border-l-4 rounded-l flex flex-col p-2 gap-2 items-start space-x-4 h-[100px]', - )} - > + )}>
-
+
+ {task.project && } {task.project && task.project.name}
@@ -142,3 +165,107 @@ const CalendarDataView = ({ data, t }: { data?: GroupedTimesheet[], t: Translati
) } + +const BaseCalendarDataView = ({ data, daysLabels, CalendarComponent }: BaseCalendarDataViewProps) => { + const { getStatusTimesheet } = useTimesheet({}); + return ( + { + return <> + {plan ? ( + + {Object.entries(getStatusTimesheet(plan.tasks)).map(([status, rows]) => ( + rows.length > 0 && status && + +
+
+
+
+ + {status === 'DENIED' ? 'REJECTED' : status} + + ({rows.length}) +
+
+
+ + +
+
+
+ + {rows.map((task) => ( +
+
+
+ + {task.employee.fullName} +
+ +
+ +
+ {task.project && } + {task.project && task.project.name} +
+
+ ))} +
+
+ ))} +
+ ) : ( +
+ + No Data +
+ )} + + }} + /> + ); +}; + +const MonthlyCalendarDataView = (props: { data: GroupedTimesheet[], daysLabels?: string[] }) => ( + +); + +const WeeklyCalendarDataView = (props: { data: GroupedTimesheet[], daysLabels?: string[] }) => ( + +); diff --git a/apps/web/app/[locale]/timesheet/[memberId]/components/CompactTimesheetComponent.tsx b/apps/web/app/[locale]/timesheet/[memberId]/components/CompactTimesheetComponent.tsx index 03f80d818..4a4f7c527 100644 --- a/apps/web/app/[locale]/timesheet/[memberId]/components/CompactTimesheetComponent.tsx +++ b/apps/web/app/[locale]/timesheet/[memberId]/components/CompactTimesheetComponent.tsx @@ -1,27 +1,5 @@ import React from "react"; -export const EmployeeAvatar = ({ imageUrl }: { imageUrl: string }) => { - const [isLoading, setIsLoading] = React.useState(true); - - return ( -
- {isLoading && ( -
- -
- )} - Employee setIsLoading(false)} - onError={() => setIsLoading(false)} - /> -
- ); -}; - - const LoadingSpinner = ({ className }: { className?: string }) => ( ( > ); + +const ImageWithLoader = ({ imageUrl, alt, className = "w-6 h-6 rounded-full" }: + { imageUrl: string; alt: string; className?: string }) => { + const [isLoading, setIsLoading] = React.useState(true); + return ( +
+ {isLoading && ( +
+ +
+ )} + {alt} setIsLoading(false)} + onError={() => setIsLoading(false)} + /> +
+ ); +}; + +export const EmployeeAvatar = ({ imageUrl }: { imageUrl: string }) => ( + +); + + +export const ProjectLogo = ({ imageUrl }: { imageUrl: string }) => ( + +); diff --git a/apps/web/app/[locale]/timesheet/[memberId]/components/EditTaskModal.tsx b/apps/web/app/[locale]/timesheet/[memberId]/components/EditTaskModal.tsx index 3daa25980..10a66b369 100644 --- a/apps/web/app/[locale]/timesheet/[memberId]/components/EditTaskModal.tsx +++ b/apps/web/app/[locale]/timesheet/[memberId]/components/EditTaskModal.tsx @@ -117,7 +117,7 @@ export function EditTaskModal({ isOpen, closeModal, dataTimesheet }: IEditTaskMo valueKey: 'id', displayKey: 'name', element: 'Project', - defaultValue: dataTimesheet.project.name + defaultValue: 'name' }, ]; diff --git a/apps/web/app/[locale]/timesheet/[memberId]/components/MonthlyTimesheetCalendar.tsx b/apps/web/app/[locale]/timesheet/[memberId]/components/MonthlyTimesheetCalendar.tsx new file mode 100644 index 000000000..55f6daad5 --- /dev/null +++ b/apps/web/app/[locale]/timesheet/[memberId]/components/MonthlyTimesheetCalendar.tsx @@ -0,0 +1,147 @@ +import React, { useMemo, useState, useCallback } from "react"; +import { format, addMonths, eachDayOfInterval, startOfMonth, endOfMonth, addDays, Locale } from "date-fns"; +import { GroupedTimesheet } from "@/app/hooks/features/useTimesheet"; +import { enGB } from 'date-fns/locale'; +import { cn } from "@/lib/utils"; +import { TotalDurationByDate } from "@/lib/features"; +import { formatDate } from "@/app/helpers"; + +type MonthlyCalendarDataViewProps = { + data?: GroupedTimesheet[]; + onDateClick?: (date: Date) => void; + renderDayContent?: (date: Date, plan?: GroupedTimesheet) => React.ReactNode; + locale?: Locale; + daysLabels?: string[]; + noDataText?: string; + classNames?: { + container?: string; + header?: string; + grid?: string; + day?: string; + noData?: string; + }; +}; + +const defaultDaysLabels = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; + +const generateFullCalendar = (currentMonth: Date) => { + const monthStart = startOfMonth(currentMonth); + const monthEnd = endOfMonth(currentMonth); + const startDate = addDays(monthStart, -monthStart.getDay()); + const endDate = addDays(monthEnd, 6 - monthEnd.getDay()); + return eachDayOfInterval({ start: startDate, end: endDate }); +}; + + +const MonthlyTimesheetCalendar: React.FC = ({ + data = [], + onDateClick, + renderDayContent, + locale = enGB, + daysLabels = defaultDaysLabels, + noDataText = "No Data", + classNames = {} +}) => { + const [currentMonth, setCurrentMonth] = useState(new Date()); + const calendarDates = useMemo(() => generateFullCalendar(currentMonth), [currentMonth]); + const groupedData = useMemo( + () => new Map(data.map((plan) => [format(new Date(plan.date), "yyyy-MM-dd"), plan])), + [data] + ); + + const handlePreviousMonth = useCallback(() => setCurrentMonth((prev) => addMonths(prev, -1)), []); + const handleNextMonth = useCallback(() => setCurrentMonth((prev) => addMonths(prev, 1)), []); + + return ( +
+ {/* Header */} +
+ +

+ {format(currentMonth, "MMMM yyyy", { locale: locale })} +

+ +
+ + {/* Grid */} +
+ {daysLabels.map((day) => ( +
{day}
+ ))} +
+ +
+ {calendarDates.map((date) => { + const formattedDate = format(date, "yyyy-MM-dd"); + const plan = groupedData.get(formattedDate); + return ( +
onDateClick?.(date)} + onKeyDown={(e) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + onDateClick?.(date); + } + }} + > +
+ + {format(date, "dd MMM yyyy")} + +
+ Total{" : "} + {plan && } +
+
+ {renderDayContent ? ( + renderDayContent(date, plan) + ) : plan ? ( +
+ {plan.tasks.map((task) => ( +
+ {task.task?.title} +
+ ))} +
+ ) : ( +
+ {noDataText} +
+ )} +
+ ); + })} +
+
+ ); +}; + +export default MonthlyTimesheetCalendar; diff --git a/apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetView.tsx b/apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetView.tsx index ee72a1f79..18606f719 100644 --- a/apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetView.tsx +++ b/apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetView.tsx @@ -18,7 +18,7 @@ export function TimesheetView({ data, loading }: { data?: GroupedTimesheet[]; lo if (data.length === 0) { return ( -
+

{t('pages.timesheet.NO_ENTRIES_FOUND')}

); diff --git a/apps/web/app/[locale]/timesheet/[memberId]/components/WeeklyTimesheetCalendar.tsx b/apps/web/app/[locale]/timesheet/[memberId]/components/WeeklyTimesheetCalendar.tsx new file mode 100644 index 000000000..db2805f0b --- /dev/null +++ b/apps/web/app/[locale]/timesheet/[memberId]/components/WeeklyTimesheetCalendar.tsx @@ -0,0 +1,150 @@ +import React, { useMemo, useState, useCallback } from "react"; +import { format, addDays, startOfWeek, endOfWeek, eachDayOfInterval, Locale } from "date-fns"; +import { enGB } from "date-fns/locale"; +import { cn } from "@/lib/utils"; +import { GroupedTimesheet } from "@/app/hooks/features/useTimesheet"; +import { TotalDurationByDate } from "@/lib/features"; +import { formatDate } from "@/app/helpers"; + +type WeeklyCalendarProps = { + data?: GroupedTimesheet[]; + onDateClick?: (date: Date) => void; + renderDayContent?: (date: Date, plan?: GroupedTimesheet) => React.ReactNode; + locale?: Locale; + daysLabels?: string[]; + noDataText?: string; + classNames?: { + container?: string; + header?: string; + grid?: string; + day?: string; + noData?: string; + }; +}; + +const defaultDaysLabels = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; + +const generateWeek = (currentDate: Date) => { + const weekStart = startOfWeek(currentDate, { weekStartsOn: 0 }); + const weekEnd = endOfWeek(currentDate, { weekStartsOn: 0 }); + return eachDayOfInterval({ start: weekStart, end: weekEnd }); +}; + +const WeeklyTimesheetCalendar: React.FC = ({ + data = [], + onDateClick, + renderDayContent, + locale = enGB, + daysLabels = defaultDaysLabels, + noDataText = "No Data", + classNames = {}, +}) => { + const [currentDate, setCurrentDate] = useState(new Date()); + + // Calculate the current week based on `currentDate` + const weekDates = useMemo(() => generateWeek(currentDate), [currentDate]); + + // Map data to the respective dates + const groupedData = useMemo( + () => new Map(data.map((plan) => [format(new Date(plan.date), "yyyy-MM-dd"), plan])), + [data] + ); + + // Handlers for navigation + const handlePreviousWeek = useCallback(() => setCurrentDate((prev) => addDays(prev, -7)), []); + const handleNextWeek = useCallback(() => setCurrentDate((prev) => addDays(prev, 7)), []); + + return ( +
+
+ +

+ {`Week of ${format(weekDates[0], "MMM d", { locale })} - ${format( + weekDates[6], + "MMM d, yyyy", + { locale } + )}`} +

+ +
+ +
+ {daysLabels.map((day) => ( +
{day}
+ ))} +
+ +
+ {weekDates.map((date) => { + const formattedDate = format(date, "yyyy-MM-dd"); + const plan = groupedData.get(formattedDate); + + return ( +
onDateClick?.(date)} + onKeyDown={(e) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + onDateClick?.(date); + } + }} + > +
+ + {format(date, "dd MMM yyyy")} + +
+ Total{" : "} + {plan && ( + + )} +
+
+ {renderDayContent ? ( + renderDayContent(date, plan) + ) : plan ? ( +
+ {plan.tasks.map((task) => ( +
+ {task.task?.title} +
+ ))} +
+ ) : ( +
+ {noDataText} +
+ )} +
+ ); + })} +
+
+ ); +}; + +export default WeeklyTimesheetCalendar; diff --git a/apps/web/app/[locale]/timesheet/[memberId]/page.tsx b/apps/web/app/[locale]/timesheet/[memberId]/page.tsx index 3eecb7d5f..ade889e9b 100644 --- a/apps/web/app/[locale]/timesheet/[memberId]/page.tsx +++ b/apps/web/app/[locale]/timesheet/[memberId]/page.tsx @@ -39,6 +39,10 @@ const TimeSheet = React.memo(function TimeSheetPage({ params }: { params: { memb const { user } = useAuthenticateUser(); const [search, setSearch] = useState(''); const [filterStatus, setFilterStatus] = useLocalStorageState('timesheet-filter-status', 'All Tasks'); + const [timesheetNavigator, setTimesheetNavigator] = useLocalStorageState( + 'timesheet-viewMode', + 'ListView' + ); const [dateRange, setDateRange] = React.useState<{ from: Date | null; to: Date | null }>({ from: startOfDay(new Date()), @@ -46,7 +50,8 @@ const TimeSheet = React.memo(function TimeSheetPage({ params }: { params: { memb }); const { timesheet, statusTimesheet, loadingTimesheet } = useTimesheet({ startDate: dateRange.from ?? '', - endDate: dateRange.to ?? '' + endDate: dateRange.to ?? '', + timesheetViewMode: timesheetNavigator }); @@ -83,10 +88,7 @@ const TimeSheet = React.memo(function TimeSheetPage({ params }: { params: { memb const username = user?.name || user?.firstName || user?.lastName || user?.username; - const [timesheetNavigator, setTimesheetNavigator] = useLocalStorageState( - 'timesheet-viewMode', - 'ListView' - ); + const fullWidth = useAtomValue(fullWidthState); const { isTrackingEnabled, activeTeam } = useOrganizationTeams(); diff --git a/apps/web/app/hooks/features/useTimesheet.ts b/apps/web/app/hooks/features/useTimesheet.ts index 91e320c53..9add0836d 100644 --- a/apps/web/app/hooks/features/useTimesheet.ts +++ b/apps/web/app/hooks/features/useTimesheet.ts @@ -11,6 +11,7 @@ import { useTimelogFilterOptions } from './useTimelogFilterOptions'; interface TimesheetParams { startDate?: Date | string; endDate?: Date | string; + timesheetViewMode?: 'ListView' | 'CalendarView' } export interface GroupedTimesheet { @@ -90,6 +91,7 @@ const groupByMonth = createGroupingFunction(date => export function useTimesheet({ startDate, endDate, + timesheetViewMode }: TimesheetParams) { const { user } = useAuthenticateUser(); const [timesheet, setTimesheet] = useAtom(timesheetRapportState); @@ -262,14 +264,17 @@ export function useTimesheet({ const timesheetElementGroup = useMemo(() => { - if (timesheetGroupByDays === 'Daily') { - return groupByDate(timesheet); - } - if (timesheetGroupByDays === 'Weekly') { - return groupByWeek(timesheet); + if (timesheetViewMode === 'ListView') { + if (timesheetGroupByDays === 'Daily') { + return groupByDate(timesheet); + } + if (timesheetGroupByDays === 'Weekly') { + return groupByWeek(timesheet); + } + return groupByMonth(timesheet); } - return groupByMonth(timesheet); - }, [timesheetGroupByDays, timesheet]); + return groupByDate(timesheet); + }, [timesheetGroupByDays, timesheetViewMode, timesheet]); useEffect(() => { diff --git a/apps/web/lib/features/integrations/calendar/table-time-sheet.tsx b/apps/web/lib/features/integrations/calendar/table-time-sheet.tsx index 2ee67b72e..117d90d43 100644 --- a/apps/web/lib/features/integrations/calendar/table-time-sheet.tsx +++ b/apps/web/lib/features/integrations/calendar/table-time-sheet.tsx @@ -56,7 +56,8 @@ import { StatusType, EmployeeAvatar, getTimesheetButtons, - statusTable + statusTable, + ProjectLogo } from '@/app/[locale]/timesheet/[memberId]/components'; import { useTranslations } from 'next-intl'; import { formatDate } from '@/app/helpers'; @@ -342,7 +343,10 @@ export function DataTableTimeSheet({ data }: { data?: GroupedTimesheet[] }) { taskNumberClassName="text-sm" />
- {task.project && task.project.name} +
+ {task.project?.imageUrl && } + {task.project?.name} +
{ const targetDateISO = new Date(createdAt).toISOString(); + const filteredLogs = timesheetLog.filter( (item) => formatDate(item.timesheet.createdAt) === formatDate(targetDateISO)); const totalDurationInSeconds = filteredLogs.reduce( diff --git a/apps/web/locales/ar.json b/apps/web/locales/ar.json index cec448f14..c94dd66a5 100644 --- a/apps/web/locales/ar.json +++ b/apps/web/locales/ar.json @@ -240,6 +240,15 @@ "SINGULAR": "ورقة الحضور", "PLURAL": "ورقات الحضور" }, + "DAYS": { + "sun": "الأحد", + "mon": "الإثنين", + "tue": "الثلاثاء", + "wed": "الأربعاء", + "thu": "الخميس", + "fri": "الجمعة", + "sat": "السبت" + }, "COPY_ISSUE_LINK": "نسخ رابط المشكلة", "MAKE_A_COPY": "إنشاء نسخة", "ASSIGNEE": "المسند إليه", diff --git a/apps/web/locales/bg.json b/apps/web/locales/bg.json index ce2a85668..19cc6cc07 100644 --- a/apps/web/locales/bg.json +++ b/apps/web/locales/bg.json @@ -258,6 +258,15 @@ "SINGULAR": "Работен лист", "PLURAL": "Работни листове" }, + "DAYS": { + "sun": "Нед", + "mon": "Пон", + "tue": "Вто", + "wed": "Сря", + "thu": "Чет", + "fri": "Пет", + "sat": "Съб" + }, "COPY_ISSUE_LINK": "Копирай връзката на проблема", "MAKE_A_COPY": "Направете копие", "ASSIGNEE": "Назначен", diff --git a/apps/web/locales/de.json b/apps/web/locales/de.json index 38a13ed56..fa9e07c55 100644 --- a/apps/web/locales/de.json +++ b/apps/web/locales/de.json @@ -258,6 +258,15 @@ "SINGULAR": "Stundenzettel", "PLURAL": "Stundenzettel" }, + "DAYS": { + "sun": "So", + "mon": "Mo", + "tue": "Di", + "wed": "Mi", + "thu": "Do", + "fri": "Fr", + "sat": "Sa" + }, "COPY_ISSUE_LINK": "Problemlink kopieren", "MAKE_A_COPY": "Eine Kopie erstellen", "ASSIGNEE": "Zessionar", diff --git a/apps/web/locales/en.json b/apps/web/locales/en.json index 180cfd86b..978ff6969 100644 --- a/apps/web/locales/en.json +++ b/apps/web/locales/en.json @@ -258,6 +258,15 @@ "SINGULAR": "Timesheet", "PLURAL": "Timesheets" }, + "DAYS": { + "sun": "Sun", + "mon": "Mon", + "tue": "Tue", + "wed": "Wed", + "thu": "Thu", + "fri": "Fri", + "sat": "Sat" + }, "COPY_ISSUE_LINK": "Copy issue link", "MAKE_A_COPY": "Make a copy", "ASSIGNEE": "Assignee", diff --git a/apps/web/locales/es.json b/apps/web/locales/es.json index 78196ca87..5a1b3a1c0 100644 --- a/apps/web/locales/es.json +++ b/apps/web/locales/es.json @@ -258,6 +258,15 @@ "SINGULAR": "Hoja de horas", "PLURAL": "Hojas de horas" }, + "DAYS": { + "sun": "Dom", + "mon": "Lun", + "tue": "Mar", + "wed": "Mié", + "thu": "Jue", + "fri": "Vie", + "sat": "Sáb" + }, "COPY_ISSUE_LINK": "Copiar enlace del problema", "MAKE_A_COPY": "Hacer una copia", "ASSIGNEE": "Cesionario", diff --git a/apps/web/locales/fr.json b/apps/web/locales/fr.json index f603ed553..88e51f215 100644 --- a/apps/web/locales/fr.json +++ b/apps/web/locales/fr.json @@ -258,6 +258,15 @@ "SINGULAR": "Feuille de temps", "PLURAL": "Feuilles de temps" }, + "DAYS": { + "sun": "Dim", + "mon": "Lun", + "tue": "Mar", + "wed": "Mer", + "thu": "Jeu", + "fri": "Ven", + "sat": "Sam" + }, "COPY_ISSUE_LINK": "Copier le lien du problème", "MAKE_A_COPY": "Faire une copie", "ASSIGNEE": "Cessionnaire", diff --git a/apps/web/locales/he.json b/apps/web/locales/he.json index a1221c365..0177769f8 100644 --- a/apps/web/locales/he.json +++ b/apps/web/locales/he.json @@ -258,6 +258,15 @@ "SINGULAR": "דוח שעות", "PLURAL": "דוחות שעות" }, + "DAYS": { + "sun": "יום א׳", + "mon": "יום ב׳", + "tue": "יום ג׳", + "wed": "יום ד׳", + "thu": "יום ה׳", + "fri": "יום ו׳", + "sat": "שבת" + }, "COPY_ISSUE_LINK": "העתק קישור לבעיה", "MAKE_A_COPY": "בצע עותק", "ASSIGNEE": "נמען", diff --git a/apps/web/locales/it.json b/apps/web/locales/it.json index e7d7ab32c..b8e80cd98 100644 --- a/apps/web/locales/it.json +++ b/apps/web/locales/it.json @@ -241,6 +241,15 @@ "SINGULAR": "Scheda attività", "PLURAL": "Schede attività" }, + "DAYS": { + "sun": "Dom", + "mon": "Lun", + "tue": "Mar", + "wed": "Mer", + "thu": "Gio", + "fri": "Ven", + "sat": "Sab" + }, "CALENDAR": "Calendario", "SELECT": "Seleziona", "SAVE_CHANGES": "Salva modifiche", diff --git a/apps/web/locales/nl.json b/apps/web/locales/nl.json index 5bc5d834c..8768d926f 100644 --- a/apps/web/locales/nl.json +++ b/apps/web/locales/nl.json @@ -241,6 +241,15 @@ "SINGULAR": "Urenstaat", "PLURAL": "Urenstaten" }, + "DAYS": { + "sun": "Zon", + "mon": "Maa", + "tue": "Din", + "wed": "Woe", + "thu": "Don", + "fri": "Vri", + "sat": "Zat" + }, "CALENDAR": "Kalender", "SELECT": "Selecteren", "SAVE_CHANGES": "Wijzigingen opslaan", diff --git a/apps/web/locales/pl.json b/apps/web/locales/pl.json index ce7d15b24..4b98a4d8b 100644 --- a/apps/web/locales/pl.json +++ b/apps/web/locales/pl.json @@ -241,6 +241,15 @@ "SINGULAR": "Karta pracy", "PLURAL": "Karty pracy" }, + "DAYS": { + "sun": "Nie", + "mon": "Pon", + "tue": "Wto", + "wed": "Śro", + "thu": "Czw", + "fri": "Pią", + "sat": "Sob" + }, "CALENDAR": "Kalendarz", "SELECT": "Wybierz", "SAVE_CHANGES": "Zapisz zmiany", diff --git a/apps/web/locales/pt.json b/apps/web/locales/pt.json index bacf7d021..a587193be 100644 --- a/apps/web/locales/pt.json +++ b/apps/web/locales/pt.json @@ -242,6 +242,15 @@ "SINGULAR": "Folha de ponto", "PLURAL": "Folhas de ponto" }, + "DAYS": { + "sun": "Dom", + "mon": "Seg", + "tue": "Ter", + "wed": "Qua", + "thu": "Qui", + "fri": "Sex", + "sat": "Sáb" + }, "CALENDAR": "Calendário", "SELECT": "Selecionar", "SAVE_CHANGES": "Salvar alterações", diff --git a/apps/web/locales/ru.json b/apps/web/locales/ru.json index 1819cc5f6..0e7dab1af 100644 --- a/apps/web/locales/ru.json +++ b/apps/web/locales/ru.json @@ -241,6 +241,15 @@ "SINGULAR": "Табель", "PLURAL": "Табели" }, + "DAYS": { + "sun": "Вс", + "mon": "Пн", + "tue": "Вт", + "wed": "Ср", + "thu": "Чт", + "fri": "Пт", + "sat": "Сб" + }, "CALENDAR": "Календарь", "SELECT": "Выбрать", "SAVE_CHANGES": "Сохранить изменения", diff --git a/apps/web/locales/zh.json b/apps/web/locales/zh.json index 2b4f4b63a..f53aeb649 100644 --- a/apps/web/locales/zh.json +++ b/apps/web/locales/zh.json @@ -241,6 +241,15 @@ "SINGULAR": "时间表", "PLURAL": "时间表" }, + "DAYS": { + "sun": "日", + "mon": "一", + "tue": "二", + "wed": "三", + "thu": "四", + "fri": "五", + "sat": "六" + }, "CALENDAR": "日历", "SELECT": "Select", "SAVE_CHANGES": "保存更改",