diff --git a/apps/web/.env b/apps/web/.env index 0637cfe20..cd31a1457 100644 --- a/apps/web/.env +++ b/apps/web/.env @@ -8,6 +8,29 @@ NEXT_PUBLIC_GAUZY_API_SERVER_URL=https://api.ever.team NEXT_PUBLIC_GA_MEASUREMENT_ID= +# Next Auth configs +AUTH_SECRET= + +# Google OAuth configuration +NEXT_PUBLIC_GOOGLE_APP_NAME=ever-google +GOOGLE_CLIENT_ID= +GOOGLE_CLIENT_SECRET= + +# Github OAuth configuration +NEXT_PUBLIC_GITHUB_APP_NAME=ever-github +GITHUB_CLIENT_ID= +GITHUB_CLIENT_SECRET= + +# Facebook OAuth configuration +NEXT_PUBLIC_FACEBOOK_APP_NAME=ever-facebook +FACEBOOK_CLIENT_ID= +FACEBOOK_CLIENT_SECRET= + +# Twitter OAuth configuration +NEXT_PUBLIC_TWITTER_APP_NAME=ever-twitter +TWITTER_CLIENT_ID= +TWITTER_CLIENT_SECRET= + # CAPTCHA Settings NEXT_PUBLIC_CAPTCHA_SITE_KEY= CAPTCHA_SECRET_KEY= diff --git a/apps/web/app/hooks/features/useTimer.ts b/apps/web/app/hooks/features/useTimer.ts index 3ae129013..c87d48021 100644 --- a/apps/web/app/hooks/features/useTimer.ts +++ b/apps/web/app/hooks/features/useTimer.ts @@ -185,20 +185,32 @@ export function useTimer() { const lastActiveTeamId = useRef(null); const lastActiveTaskId = useRef(null); + // Find if the connected user has a today plan. Help to know if he can track time when require daily plan is set to true const hasPlan = myDailyPlans.items.find( (plan) => plan.date?.toString()?.startsWith(new Date()?.toISOString().split('T')[0]) && plan.tasks && plan.tasks?.length > 0 ); + + // Team setting that tells if each member must have a today plan for allowing tracking time const requirePlan = activeTeam?.requirePlanToTrack; + // If require plan setting is activated but user don't have plan, block time tracking until a today plan will be added let canTrack = true; if (requirePlan) { if (!hasPlan) canTrack = false; } + // If require plan setting is activated, + // check if the today plan has working time planned and all the tasks into the plan are estimated + let isPlanVerified = true; + if (requirePlan) { + isPlanVerified = + !!hasPlan?.workTimePlanned && !!hasPlan?.tasks?.every((task) => task.estimate && task.estimate > 0); + } + const canRunTimer = user?.isEmailVerified && ((!!activeTeamTask && activeTeamTask.status !== 'closed') || @@ -395,8 +407,10 @@ export function useTimer() { firstLoadTimerData, startTimer, stopTimer, + hasPlan, canRunTimer, canTrack, + isPlanVerified, firstLoad, toggleTimer, timerSeconds, @@ -433,8 +447,10 @@ export function useTimerView() { timerStatusFetching, startTimer, stopTimer, + hasPlan, canRunTimer, canTrack, + isPlanVerified, timerSeconds, activeTeamTask, syncTimerLoading @@ -462,8 +478,10 @@ export function useTimerView() { timerStatusFetching, timerStatus, activeTeamTask, + hasPlan, disabled: !canRunTimer, canTrack, + isPlanVerified, startTimer, stopTimer, syncTimerLoading diff --git a/apps/web/components/shared/timer/timer-card.tsx b/apps/web/components/shared/timer/timer-card.tsx index 8943796d5..3511902db 100644 --- a/apps/web/components/shared/timer/timer-card.tsx +++ b/apps/web/components/shared/timer/timer-card.tsx @@ -1,9 +1,11 @@ import { pad } from '@app/helpers/number'; +import { useModal } from '@app/hooks'; import { useTaskStatistics } from '@app/hooks/features/useTaskStatistics'; import { useTimer } from '@app/hooks/features/useTimer'; import { ProgressBar } from '@components/ui/progress-bar'; import { PauseIcon } from '@components/ui/svgs/pause-icon'; import { PlayIcon } from '@components/ui/svgs/play-icon'; +import { AddWorkTimeAndEstimatesToPlan } from 'lib/features/daily-plan/plans-work-time-and-estimate'; import { useTranslations } from 'next-intl'; const Timer = () => { @@ -15,17 +17,25 @@ const Timer = () => { startTimer, stopTimer, canRunTimer, + isPlanVerified, + hasPlan, timerSeconds } = useTimer(); const { activeTaskEstimation } = useTaskStatistics(timerSeconds); + const { closeModal, isOpen, openModal } = useModal(); + const timerHanlder = () => { if (timerStatusFetching || !canRunTimer) return; if (timerStatus?.running) { stopTimer(); } else { - startTimer(); + if (!isPlanVerified) { + openModal(); + } else { + startTimer(); + } } }; @@ -45,6 +55,12 @@ const Timer = () => { > {timerStatus?.running ? : } + ); }; diff --git a/apps/web/lib/features/daily-plan/plans-work-time-and-estimate.tsx b/apps/web/lib/features/daily-plan/plans-work-time-and-estimate.tsx new file mode 100644 index 000000000..885d0698a --- /dev/null +++ b/apps/web/lib/features/daily-plan/plans-work-time-and-estimate.tsx @@ -0,0 +1,148 @@ +import { useEffect, useState } from 'react'; +import { PiWarningCircleFill } from 'react-icons/pi'; +import { IDailyPlan, ITeamTask } from '@app/interfaces'; +import { Card, InputField, Modal, Text, VerticalSeparator } from 'lib/components'; +import { useTranslations } from 'use-intl'; +import { TaskNameInfoDisplay } from '../task/task-displays'; +import { Button } from '@components/ui/button'; +import { TaskEstimate } from '../task/task-estimate'; +import { useDailyPlan, useTeamTasks } from '@app/hooks'; + +export function AddWorkTimeAndEstimatesToPlan({ + open, + closeModal, + plan, + startTimer + // employee +}: { + open: boolean; + closeModal: () => void; + startTimer: () => void; + plan?: IDailyPlan; + // employee?: OT_Member; +}) { + const t = useTranslations(); + const [workTimePlanned, setworkTimePlanned] = useState(plan?.workTimePlanned); + + useEffect(() => { + if (typeof workTimePlanned === 'string') setworkTimePlanned(parseFloat(workTimePlanned)); + }, [workTimePlanned]); + + const { updateDailyPlan } = useDailyPlan(); + + const { tasks: $tasks } = useTeamTasks(); + + const tasks = $tasks.filter((task) => + plan?.tasks?.some((t) => task?.id === t.id && typeof task?.estimate === 'number' && task?.estimate <= 0) + ); + + const handleSubmit = () => { + if (workTimePlanned === 0 || typeof workTimePlanned !== 'number') return; + if (tasks.some((task) => task.estimate === 0)) return; + + updateDailyPlan({ workTimePlanned }, plan?.id ?? ''); + startTimer(); + closeModal(); + }; + + return ( + + +
+
+ + {t('timer.todayPlanSettings.TITLE')} + +
+
+ + {t('timer.todayPlanSettings.WORK_TIME_PLANNED')} * + + setworkTimePlanned(parseFloat(e.target.value))} + required + defaultValue={plan?.workTimePlanned ?? 0} + /> +
+ + {tasks.length > 0 && ( +
+ + +
+ +

{t('timer.todayPlanSettings.WARNING_PLAN_ESTIMATION')}

+
+
+ )} + +
+ + +
+
+
+
+ ); +} + +function UnEstimatedTasks({ dailyPlan }: { dailyPlan?: IDailyPlan }) { + const t = useTranslations(); + + const { tasks: $tasks } = useTeamTasks(); + + const tasks = $tasks.filter((task) => + dailyPlan?.tasks?.some((t) => task?.id === t.id && typeof task?.estimate === 'number' && task?.estimate <= 0) + ); + + return ( +
+ {tasks?.length > 0 && ( +
+ + {t('timer.todayPlanSettings.TASKS_WITH_NO_ESTIMATIONS')} * + +
+ {tasks && tasks?.map((task) => )} +
+
+ )} +
+ ); +} + +export function UnEstimatedTask({ task }: { task: ITeamTask }) { + return ( + + ); +} diff --git a/apps/web/lib/features/task/daily-plan/index.ts b/apps/web/lib/features/task/daily-plan/index.ts index cbcface80..e15cd0924 100644 --- a/apps/web/lib/features/task/daily-plan/index.ts +++ b/apps/web/lib/features/task/daily-plan/index.ts @@ -1,2 +1,3 @@ export * from './outstanding'; export * from './past-tasks'; +export * from './future-tasks'; diff --git a/apps/web/lib/features/task/task-card.tsx b/apps/web/lib/features/task/task-card.tsx index b9dc8a8de..0f093fce5 100644 --- a/apps/web/lib/features/task/task-card.tsx +++ b/apps/web/lib/features/task/task-card.tsx @@ -52,6 +52,7 @@ import { useTranslations } from 'next-intl'; import { SixSquareGridIcon, ThreeCircleOutlineVerticalIcon } from 'assets/svg'; import { CreateDailyPlanFormModal } from '../daily-plan/create-daily-plan-form-modal'; import { AddTaskToPlan } from '../daily-plan/add-task-to-plan'; +import { AddWorkTimeAndEstimatesToPlan } from '../daily-plan/plans-work-time-and-estimate'; type Props = { active?: boolean; @@ -329,7 +330,20 @@ function TimerButtonCall({ }) { const [loading, setLoading] = useState(false); const { updateOrganizationTeamEmployee } = useOrganizationEmployeeTeams(); - const { canTrack, disabled, timerHanlder, timerStatus, activeTeamTask, startTimer, stopTimer } = useTimerView(); + const { closeModal, isOpen, openModal } = useModal(); + + const { + canTrack, + disabled, + canRunTimer, + timerStatusFetching, + timerStatus, + activeTeamTask, + startTimer, + stopTimer, + isPlanVerified, + hasPlan + } = useTimerView(); const { setActiveTask } = useTeamTasks(); @@ -371,15 +385,36 @@ function TimerButtonCall({ updateOrganizationTeamEmployee ]); + const timerHanlderStartStop = useCallback(() => { + if (timerStatusFetching || !canRunTimer) return; + if (timerStatus?.running) { + stopTimer(); + } else { + if (!isPlanVerified) { + openModal(); + } else { + startTimer(); + } + } + }, [canRunTimer, isPlanVerified, openModal, startTimer, stopTimer, timerStatus, timerStatusFetching]); + return loading ? ( ) : ( - + <> + + + ); } diff --git a/apps/web/lib/features/team/user-team-card/task-estimate.tsx b/apps/web/lib/features/team/user-team-card/task-estimate.tsx index 93d3126db..3fee804ca 100644 --- a/apps/web/lib/features/team/user-team-card/task-estimate.tsx +++ b/apps/web/lib/features/team/user-team-card/task-estimate.tsx @@ -36,7 +36,7 @@ export function TaskEstimateInfo({ className, activeAuthTask, showTime = true, r ); } -function TaskEstimateInput({ memberInfo, edition }: Omit) { +export function TaskEstimateInput({ memberInfo, edition }: Omit) { const t = useTranslations(); const loadingRef = useRef(false); const task = edition.task || memberInfo.memberTask; diff --git a/apps/web/lib/features/timer/timer.tsx b/apps/web/lib/features/timer/timer.tsx index 861a6eaf3..d6245f893 100644 --- a/apps/web/lib/features/timer/timer.tsx +++ b/apps/web/lib/features/timer/timer.tsx @@ -1,5 +1,5 @@ import { pad } from '@app/helpers'; -import { HostKeys, useDetectOS, useHotkeys, useTimerView } from '@app/hooks'; +import { HostKeys, useDetectOS, useHotkeys, useModal, useTimerView } from '@app/hooks'; import { IClassName, TimerSource } from '@app/interfaces'; import { clsxm } from '@app/utils'; import { ProgressBar, Text, Tooltip, VerticalSeparator } from 'lib/components'; @@ -15,11 +15,40 @@ import { } from '@heroicons/react/24/outline'; import { HotkeysEvent } from 'hotkeys-js'; import { useCallback, useMemo } from 'react'; +import { AddWorkTimeAndEstimatesToPlan } from '../daily-plan/plans-work-time-and-estimate'; export function Timer({ className }: IClassName) { const t = useTranslations(); - const { hours, minutes, seconds, activeTaskEstimation, ms_p, canRunTimer, timerHanlder, timerStatus, disabled } = - useTimerView(); + const { closeModal, isOpen, openModal } = useModal(); + const { + hours, + minutes, + seconds, + activeTaskEstimation, + ms_p, + canRunTimer, + timerStatusFetching, + timerHanlder, + timerStatus, + disabled, + startTimer, + stopTimer, + isPlanVerified, + hasPlan + } = useTimerView(); + + const timerHanlderStartStop = useCallback(() => { + if (timerStatusFetching || !canRunTimer) return; + if (timerStatus?.running) { + stopTimer(); + } else { + if (!isPlanVerified) { + openModal(); + } else { + startTimer(); + } + } + }, [canRunTimer, isPlanVerified, openModal, startTimer, stopTimer, timerStatus, timerStatusFetching]); const { os } = useDetectOS(); const osSpecificTimerTooltipLabel = useMemo(() => { @@ -112,7 +141,7 @@ export function Timer({ className }: IClassName) { // } > + ); diff --git a/apps/web/locales/ar.json b/apps/web/locales/ar.json index 69ba9526f..6cb46bbf5 100644 --- a/apps/web/locales/ar.json +++ b/apps/web/locales/ar.json @@ -511,7 +511,15 @@ { "title": "14 يوم" } - ] + ], + "todayPlanSettings": { + "TITLE": "خطة اليوم", + "WORK_TIME_PLANNED": "إضافة ساعات العمل المخطط لها", + "WORK_TIME_PLANNED_PLACEHOLDER": "وقت العمل المخطط له اليوم", + "TASKS_WITH_NO_ESTIMATIONS": "تاكس مع عدم وجود تقديرات زمنية", + "START_WORKING_BUTTON": "ابدأ العمل", + "WARNING_PLAN_ESTIMATION": "رجى تصحيح ساعات العمل المخطط لها أو إعادة تقدير المهمة (المهام)" + } }, "task": { "TITLE": "المهمة", diff --git a/apps/web/locales/bg.json b/apps/web/locales/bg.json index 7543f593e..e4f3be4d2 100644 --- a/apps/web/locales/bg.json +++ b/apps/web/locales/bg.json @@ -511,7 +511,15 @@ { "title": "14 дни" } - ] + ], + "todayPlanSettings": { + "TITLE": "ДНЕШЕН ПЛАН", + "WORK_TIME_PLANNED": "Добавяне на планирани работни часове", + "WORK_TIME_PLANNED_PLACEHOLDER": "Планирано работно време за днес", + "TASKS_WITH_NO_ESTIMATIONS": "Такси без оценки на времето", + "START_WORKING_BUTTON": "Започнете работа", + "WARNING_PLAN_ESTIMATION": "Моля, коригирайте планираните работни часове или преоценете задачата(ите) " + } }, "task": { "TITLE": "Задача", diff --git a/apps/web/locales/de.json b/apps/web/locales/de.json index 8482a7733..90d7c90e0 100644 --- a/apps/web/locales/de.json +++ b/apps/web/locales/de.json @@ -511,7 +511,15 @@ { "title": "14 Tage" } - ] + ], + "todayPlanSettings": { + "TITLE": "PLAN VON HEUTE", + "WORK_TIME_PLANNED": "Geplante Arbeitsstunden hinzufügen", + "WORK_TIME_PLANNED_PLACEHOLDER": "Für heute geplante Arbeitszeit", + "TASKS_WITH_NO_ESTIMATIONS": "Taks ohne Zeitvorgaben", + "START_WORKING_BUTTON": "Mit der Arbeit beginnen", + "WARNING_PLAN_ESTIMATION": "Bitte korrigieren Sie die geplanten Arbeitsstunden oder schätzen Sie die Aufgabe(n) neu ein." + } }, "task": { "TITLE": "Aufgabe", diff --git a/apps/web/locales/en.json b/apps/web/locales/en.json index 44820da67..dd701989b 100644 --- a/apps/web/locales/en.json +++ b/apps/web/locales/en.json @@ -511,7 +511,15 @@ "ACTIVE": "Active", "INACTIVE": "Inactive", "ARCHIVED": "Archived", - "NOT_ARCHIVED": "Not archived" + "NOT_ARCHIVED": "Not archived", + "todayPlanSettings": { + "TITLE": "TODAY'S PLAN", + "WORK_TIME_PLANNED": "Add planned working hours", + "WORK_TIME_PLANNED_PLACEHOLDER": "Working time planned for today", + "TASKS_WITH_NO_ESTIMATIONS": "Taks with no time estimations", + "START_WORKING_BUTTON": "Start working", + "WARNING_PLAN_ESTIMATION": "Please correct planned work hours or re-estimate task(s)" + } }, "task": { "TITLE": "Task", diff --git a/apps/web/locales/es.json b/apps/web/locales/es.json index 603906303..f5af900c8 100644 --- a/apps/web/locales/es.json +++ b/apps/web/locales/es.json @@ -511,7 +511,15 @@ "TIME_SPENT_IN_HOURS": "Tiempo gastado (Horas)", "TIMES": "Veces", "TOTAL_HOURS": "Horas totales", - "VISITED_DATES": "Fechas visitadas" + "VISITED_DATES": "Fechas visitadas", + "todayPlanSettings": { + "TITLE": "PLAN DE HOY", + "WORK_TIME_PLANNED": "Añadir horas de trabajo previstas", + "WORK_TIME_PLANNED_PLACEHOLDER": "Tiempo de trabajo previsto para hoy", + "TASKS_WITH_NO_ESTIMATIONS": "Tarea sin estimación de tiempo", + "START_WORKING_BUTTON": "Empezar a trabajar", + "WARNING_PLAN_ESTIMATION": "Por favor, corrija las horas de trabajo previstas o reevalúe la(s) tarea(s)" + } }, "task": { "TITLE": "Tarea", diff --git a/apps/web/locales/fr.json b/apps/web/locales/fr.json index 0064393cd..0699a5e3c 100644 --- a/apps/web/locales/fr.json +++ b/apps/web/locales/fr.json @@ -495,6 +495,14 @@ "title": "14 jours" } ], + "todayPlanSettings": { + "TITLE": "PLAN DU JOUR", + "WORK_TIME_PLANNED": "Ajouter les heures de travail prévues", + "WORK_TIME_PLANNED_PLACEHOLDER": "Temps de travail prévu pour aujourd'hui", + "TASKS_WITH_NO_ESTIMATIONS": "Tâches sans estimations de temps", + "START_WORKING_BUTTON": "Commencer à travailler", + "WARNING_PLAN_ESTIMATION": "Veuillez corriger les heures de travail prévues ou réévaluer la/les tâche(s)" + }, "TIME_ACTIVITY": "Activité", "TOTAL_HOURS": "Total des heures", "NO_SCREENSHOOT": "Aucune capture d'écran", diff --git a/apps/web/locales/he.json b/apps/web/locales/he.json index 382cf3239..57b4adb9d 100644 --- a/apps/web/locales/he.json +++ b/apps/web/locales/he.json @@ -511,7 +511,15 @@ { "title": "14 ימים" } - ] + ], + "todayPlanSettings": { + "TITLE": "תכנית היום", + "WORK_TIME_PLANNED": "הוסף שעות עבודה מתוכננות", + "WORK_TIME_PLANNED_PLACEHOLDER": "זמן עבודה מתוכנן להיום", + "TASKS_WITH_NO_ESTIMATIONS": "משימות בלי הערכת זמן", + "START_WORKING_BUTTON": "התחל לעבוד", + "WARNING_PLAN_ESTIMATION": "נא לתקן את שעות העבודה המתוכננות או להעריך מחדש את המשימות" + } }, "task": { "TITLE": "משימה", diff --git a/apps/web/locales/it.json b/apps/web/locales/it.json index 1c563b0a7..7f3a694bc 100644 --- a/apps/web/locales/it.json +++ b/apps/web/locales/it.json @@ -495,6 +495,14 @@ "title": "14 days" } ], + "todayPlanSettings": { + "TITLE": "PIANO DEL GIORNO", + "WORK_TIME_PLANNED": "Aggiungi ore di lavoro pianificate", + "WORK_TIME_PLANNED_PLACEHOLDER": "Tempo di lavoro pianificato per oggi", + "TASKS_WITH_NO_ESTIMATIONS": "Compiti senza stime di tempo", + "START_WORKING_BUTTON": "Inizia a lavorare", + "WARNING_PLAN_ESTIMATION": "Correggere le ore di lavoro previste o rivalutare il/i compito/i." + }, "TIME_ACTIVITY": "Attività", "TOTAL_HOURS": "Ore Totali", "NO_SCREENSHOOT": "Nessuna Schermata", diff --git a/apps/web/locales/nl.json b/apps/web/locales/nl.json index e692e597d..7edc65081 100644 --- a/apps/web/locales/nl.json +++ b/apps/web/locales/nl.json @@ -511,7 +511,15 @@ { "title": "14 dagen" } - ] + ], + "todayPlanSettings": { + "TITLE": "PLAN VAN VANDAAG", + "WORK_TIME_PLANNED": "Geplande werkuren toevoegen", + "WORK_TIME_PLANNED_PLACEHOLDER": "Geplande werktijd voor vandaag", + "TASKS_WITH_NO_ESTIMATIONS": "Taken zonder tijdschattingen", + "START_WORKING_BUTTON": "Begin met werken", + "WARNING_PLAN_ESTIMATION": "Corrigeer de geplande werkuren of schat de taak(en) opnieuw in" + } }, "task": { "TITLE": "Taak", diff --git a/apps/web/locales/pl.json b/apps/web/locales/pl.json index 5d16302a5..52ffa643c 100644 --- a/apps/web/locales/pl.json +++ b/apps/web/locales/pl.json @@ -495,6 +495,14 @@ "title": "14 dni" } ], + "todayPlanSettings": { + "TITLE": "PLAN DNIA", + "WORK_TIME_PLANNED": "Dodaj zaplanowane godziny pracy", + "WORK_TIME_PLANNED_PLACEHOLDER": "Zaplanowany czas pracy na dziś", + "TASKS_WITH_NO_ESTIMATIONS": "Zadania bez oszacowania czasu", + "START_WORKING_BUTTON": "Rozpocznij pracę", + "WARNING_PLAN_ESTIMATION": "Popraw planowane godziny pracy lub ponownie oszacuj zadania" + }, "TIME_ACTIVITY": "Aktywność", "TOTAL_HOURS": "Całkowita liczba godzin", "NO_SCREENSHOOT": "Brak zrzutów ekranu", diff --git a/apps/web/locales/pt.json b/apps/web/locales/pt.json index d97b02c80..17b6d4537 100644 --- a/apps/web/locales/pt.json +++ b/apps/web/locales/pt.json @@ -495,6 +495,14 @@ "title": "14 dias" } ], + "todayPlanSettings": { + "TITLE": "PLANO DO DIA", + "WORK_TIME_PLANNED": "Adicionar horas de trabalho planejadas", + "WORK_TIME_PLANNED_PLACEHOLDER": "Tempo de trabalho planejado para hoje", + "TASKS_WITH_NO_ESTIMATIONS": "Tarefas sem estimativas de tempo", + "START_WORKING_BUTTON": "Começar a trabalhar", + "WARNING_PLAN_ESTIMATION": "Corrigir as horas de trabalho planeadas ou fazer uma nova estimativa da(s) tarefa(s)" + }, "TIME_ACTIVITY": "Atividade", "TOTAL_HOURS": "Total de Horas", "NO_SCREENSHOOT": "Sem Capturas de Tela", diff --git a/apps/web/locales/ru.json b/apps/web/locales/ru.json index 4b0e636f7..79b18e7f9 100644 --- a/apps/web/locales/ru.json +++ b/apps/web/locales/ru.json @@ -495,6 +495,14 @@ "title": "14 дней" } ], + "todayPlanSettings": { + "TITLE": "ПЛАН НА СЕГОДНЯ", + "WORK_TIME_PLANNED": "Добавить запланированные часы работы", + "WORK_TIME_PLANNED_PLACEHOLDER": "Запланированное время работы на сегодня", + "TASKS_WITH_NO_ESTIMATIONS": "Задачи без оценки времени", + "START_WORKING_BUTTON": "Начать работу", + "WARNING_PLAN_ESTIMATION": "Пожалуйста, исправьте запланированные часы работы или пересчитайте задание(я)" + }, "TIME_ACTIVITY": "Активность", "TOTAL_HOURS": "Всего часов", "NO_SCREENSHOOT": "Нет снимков экрана", diff --git a/apps/web/locales/zh.json b/apps/web/locales/zh.json index fdd86396e..3431ba67c 100644 --- a/apps/web/locales/zh.json +++ b/apps/web/locales/zh.json @@ -511,7 +511,15 @@ { "title": "14天" } - ] + ], + "todayPlanSettings": { + "TITLE": "今日计划", + "WORK_TIME_PLANNED": "添加计划工作时间", + "WORK_TIME_PLANNED_PLACEHOLDER": "今天计划的工作时间", + "TASKS_WITH_NO_ESTIMATIONS": "没有时间估算的任务", + "START_WORKING_BUTTON": "开始工作", + "WARNING_PLAN_ESTIMATION": "请更正计划工时或重新估算任务工时" + } }, "task": { "TITLE": "任务",