From e76fd64a3bc1c4f02df051e5c36f721a182291dc Mon Sep 17 00:00:00 2001 From: CREDO23 Date: Mon, 30 Sep 2024 22:53:58 +0200 Subject: [PATCH 1/2] feat: user can add tasks for today / tomorrow plan from 'See plan' modal --- .../add-task-estimation-hours-modal.tsx | 262 ++++++++++-------- .../features/daily-plan/all-plans-modal.tsx | 82 +++--- 2 files changed, 198 insertions(+), 146 deletions(-) diff --git a/apps/web/lib/features/daily-plan/add-task-estimation-hours-modal.tsx b/apps/web/lib/features/daily-plan/add-task-estimation-hours-modal.tsx index d67a373fa..e4099dc63 100644 --- a/apps/web/lib/features/daily-plan/add-task-estimation-hours-modal.tsx +++ b/apps/web/lib/features/daily-plan/add-task-estimation-hours-modal.tsx @@ -33,19 +33,21 @@ import moment from 'moment'; * @param {IDailyPlan} props.plan - The selected plan * @param {ITeamTask[]} props.tasks - The list of planned tasks * @param {boolean} props.isRenderedInSoftFlow - If true use the soft flow logic. + * @param {Date} props.selectedDate - A date on which the user can create the plan * * @returns {JSX.Element} The modal element */ interface IAddTasksEstimationHoursModalProps { closeModal: () => void; isOpen: boolean; - plan: IDailyPlan; + plan?: IDailyPlan; tasks: ITeamTask[]; isRenderedInSoftFlow?: boolean; + selectedDate?: Date; } export function AddTasksEstimationHoursModal(props: IAddTasksEstimationHoursModalProps) { - const { isOpen, closeModal, plan, tasks, isRenderedInSoftFlow = true } = props; + const { isOpen, closeModal, plan, tasks, isRenderedInSoftFlow = true, selectedDate } = props; const { isOpen: isActiveTaskHandlerModalOpen, closeModal: closeActiveTaskHandlerModal, @@ -57,25 +59,30 @@ export function AddTasksEstimationHoursModal(props: IAddTasksEstimationHoursModa const { startTimer, timerStatus } = useTimerView(); const { activeTeam, activeTeamTask, setActiveTask } = useTeamTasks(); const [showSearchInput, setShowSearchInput] = useState(false); - const [workTimePlanned, setWorkTimePlanned] = useState(plan.workTimePlanned); + const [workTimePlanned, setWorkTimePlanned] = useState(plan?.workTimePlanned ?? 0); const currentDate = useMemo(() => new Date().toISOString().split('T')[0], []); const requirePlan = useMemo(() => activeTeam?.requirePlanToTrack, [activeTeam?.requirePlanToTrack]); - const tasksEstimationTimes = useMemo(() => estimatedTotalTime(plan.tasks).timesEstimated / 3600, [plan.tasks]); + const tasksEstimationTimes = useMemo( + () => (plan && plan.tasks ? estimatedTotalTime(plan.tasks).timesEstimated / 3600 : 0), + [plan] + ); const totalWorkedTime = useMemo( () => - plan.tasks?.reduce((acc, cur) => { - const totalWorkedTime = cur.totalWorkedTime ?? 0; + plan && plan.tasks + ? plan.tasks?.reduce((acc, cur) => { + const totalWorkedTime = cur.totalWorkedTime ?? 0; - return acc + totalWorkedTime; - }, 0), + return acc + totalWorkedTime; + }, 0) + : 0, [plan] ); const [warning, setWarning] = useState(''); const [loading, setLoading] = useState(false); const [defaultTask, setDefaultTask] = useState(null); const isActiveTaskPlanned = useMemo( - () => plan.tasks?.some((task) => task.id == activeTeamTask?.id), - [activeTeamTask?.id, plan.tasks] + () => plan && plan.tasks && plan.tasks?.some((task) => task.id == activeTeamTask?.id), + [activeTeamTask?.id, plan] ); const [isWorkingTimeInputFocused, setWorkingTimeInputFocused] = useState(false); const [planEditState, setPlanEditState] = useState<{ draft: boolean; saved: boolean }>({ @@ -84,18 +91,19 @@ export function AddTasksEstimationHoursModal(props: IAddTasksEstimationHoursModa }); const isTomorrowPlan = useMemo( () => + plan && new Date(moment().add(1, 'days').toDate()).toLocaleDateString('en') == - new Date(plan.date).toLocaleDateString('en'), - [plan.date] + new Date(plan.date).toLocaleDateString('en'), + [plan] ); const canStartWorking = useMemo(() => { const isTodayPlan = - new Date(Date.now()).toLocaleDateString('en') == new Date(plan.date).toLocaleDateString('en'); + plan && new Date(Date.now()).toLocaleDateString('en') == new Date(plan.date).toLocaleDateString('en'); return isTodayPlan; // Can add others conditions - }, [plan.date]); + }, [plan]); const handleCloseModal = useCallback(() => { if (canStartWorking) { @@ -149,7 +157,9 @@ export function AddTasksEstimationHoursModal(props: IAddTasksEstimationHoursModa setLoading(true); // Update the plan work time only if the user changed it - plan.workTimePlanned !== workTimePlanned && (await updateDailyPlan({ workTimePlanned }, plan.id ?? '')); + plan && + plan.workTimePlanned !== workTimePlanned && + (await updateDailyPlan({ workTimePlanned }, plan.id ?? '')); setPlanEditState({ draft: false, saved: true }); @@ -166,8 +176,7 @@ export function AddTasksEstimationHoursModal(props: IAddTasksEstimationHoursModa setLoading(false); } }, [ - plan.workTimePlanned, - plan.id, + plan, workTimePlanned, updateDailyPlan, canStartWorking, @@ -198,7 +207,7 @@ export function AddTasksEstimationHoursModal(props: IAddTasksEstimationHoursModa useEffect(() => { if (!workTimePlanned || workTimePlanned <= 0) { setWarning(t('dailyPlan.planned_tasks_popup.warning.PLANNED_TIME')); - } else if (plan.tasks?.find((task) => !task.estimate)) { + } else if (plan?.tasks?.find((task) => !task.estimate)) { setWarning(t('dailyPlan.planned_tasks_popup.warning.TASKS_ESTIMATION')); } else if (Math.abs(workTimePlanned - tasksEstimationTimes) > 1) { checkPlannedAndEstimateTimeDiff(); @@ -206,7 +215,7 @@ export function AddTasksEstimationHoursModal(props: IAddTasksEstimationHoursModa setWarning(''); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [workTimePlanned, tasksEstimationTimes, plan.tasks, myDailyPlans]); + }, [workTimePlanned, tasksEstimationTimes, plan?.tasks, myDailyPlans]); // Put tasks without estimates at the top of the list const sortedTasks = useMemo( @@ -245,8 +254,8 @@ export function AddTasksEstimationHoursModal(props: IAddTasksEstimationHoursModa // Update the working planned time useEffect(() => { - setWorkTimePlanned(plan.workTimePlanned); - }, [plan.id, plan.workTimePlanned]); + setWorkTimePlanned(plan?.workTimePlanned ?? 0); + }, [plan?.id, plan?.workTimePlanned]); const StartWorkingButton = ( + {timerStatus?.running && !planEditState.draft ? ( + + {StartWorkingButton} + + ) : ( +
{StartWorkingButton}
)} - - -
- - {timerStatus?.running ? ( - - {StartWorkingButton} - - ) : ( -
{StartWorkingButton}
- )} -
+ + ) : null} ); @@ -478,10 +497,11 @@ export function AddTasksEstimationHoursModal(props: IAddTasksEstimationHoursModa */ interface ISearchTaskInputProps { - selectedPlan: IDailyPlan; + selectedPlan?: IDailyPlan; setShowSearchInput: Dispatch>; setDefaultTask: Dispatch>; defaultTask: ITeamTask | null; + selectedDate?: Date; } /** @@ -492,11 +512,12 @@ interface ISearchTaskInputProps { * @param {Dispatch>} props.setShowSearchInput - A setter for (showing / hiding) the input * @param {Dispatch>} props.setDefaultTask - A function that sets default planned task * @param {ITeamTask} props.defaultTask - The default planned task + * @param {Date} props.selectedDate - A date on which the user can create the plan * * @returns The Search input component */ export function SearchTaskInput(props: ISearchTaskInputProps) { - const { selectedPlan, setShowSearchInput, defaultTask, setDefaultTask } = props; + const { selectedPlan, setShowSearchInput, defaultTask, setDefaultTask, selectedDate } = props; const { tasks: teamTasks, createTask } = useTeamTasks(); const { taskStatus } = useTaskStatus(); const [taskName, setTaskName] = useState(''); @@ -510,9 +531,9 @@ export function SearchTaskInput(props: ISearchTaskInputProps) { const isTaskPlanned = useCallback( (taskId: string) => { - return selectedPlan?.tasks?.some((task) => task.id == taskId); + return selectedPlan && selectedPlan?.tasks?.some((task) => task.id == taskId); }, - [selectedPlan.tasks] + [selectedPlan] ); useEffect(() => { @@ -530,7 +551,7 @@ export function SearchTaskInput(props: ISearchTaskInputProps) { } }) ); - }, [isTaskPlanned, selectedPlan.tasks, taskName, teamTasks]); + }, [isTaskPlanned, selectedPlan?.tasks, taskName, teamTasks]); const handleCreateTask = useCallback(async () => { try { @@ -605,6 +626,7 @@ export function SearchTaskInput(props: ISearchTaskInputProps) { plan={selectedPlan} setDefaultTask={setDefaultTask} isDefaultTask={task.id == defaultTask?.id} + selectedDate={selectedDate} /> ))} @@ -638,18 +660,19 @@ interface ITaskCardProps { task: ITeamTask; setDefaultTask: Dispatch>; isDefaultTask: boolean; - plan: IDailyPlan; + plan?: IDailyPlan; viewListMode?: 'planned' | 'searched'; + selectedDate?: Date; } function TaskCard(props: ITaskCardProps) { - const { task, plan, viewListMode = 'planned', isDefaultTask, setDefaultTask } = props; + const { task, plan, viewListMode = 'planned', isDefaultTask, setDefaultTask, selectedDate } = props; const { getTaskById } = useTeamTasks(); const { addTaskToPlan, createDailyPlan } = useDailyPlan(); const { user } = useAuthenticateUser(); const [addToPlanLoading, setAddToPlanLoading] = useState(false); const isTaskRenderedInTodayPlan = - new Date(Date.now()).toLocaleDateString('en') == new Date(plan.date).toLocaleDateString('en'); + plan && new Date(Date.now()).toLocaleDateString('en') == new Date(plan.date).toLocaleDateString('en'); const { isOpen: isTaskDetailsModalOpen, closeModal: closeTaskDetailsModal, @@ -678,20 +701,30 @@ function TaskCard(props: ITaskCardProps) { try { setAddToPlanLoading(true); - console.log(plan); - - if (plan.id) { + if (plan && plan.id) { await addTaskToPlan({ taskId: task.id }, plan.id); } else { - await createDailyPlan({ - workTimePlanned: 0, - taskId: task.id, - date: moment(plan.date).toDate(), - status: DailyPlanStatusEnum.OPEN, - tenantId: user?.tenantId ?? '', - employeeId: user?.employee.id, - organizationId: user?.employee.organizationId - }); + if (plan) { + await createDailyPlan({ + workTimePlanned: 0, + taskId: task.id, + date: new Date(moment(plan.date).format('YYYY-MM-DD')), + status: DailyPlanStatusEnum.OPEN, + tenantId: user?.tenantId ?? '', + employeeId: user?.employee.id, + organizationId: user?.employee.organizationId + }); + } else if (selectedDate) { + await createDailyPlan({ + workTimePlanned: 0, + taskId: task.id, + date: new Date(moment(selectedDate).format('YYYY-MM-DD')), + status: DailyPlanStatusEnum.OPEN, + tenantId: user?.tenantId ?? '', + employeeId: user?.employee.id, + organizationId: user?.employee.organizationId + }); + } } } catch (error) { console.log(error); @@ -702,6 +735,7 @@ function TaskCard(props: ITaskCardProps) { addTaskToPlan, createDailyPlan, plan, + selectedDate, task.id, user?.employee.id, user?.employee.organizationId, @@ -733,7 +767,7 @@ function TaskCard(props: ITaskCardProps) { - ) : ( + ) : plan ? ( <>
{checkPastDate(plan.date) ? ( @@ -761,10 +795,10 @@ function TaskCard(props: ITaskCardProps) { /> - )} + ) : null}
- {activeTeamTask && ( + {plan && activeTeamTask && ( (); + const [customDate, setCustomDate] = useState(moment().toDate()); const { myDailyPlans, pastPlans } = useDailyPlan(); // Utility function for checking if two dates are the same - const isSameDate = useCallback( - (date1: Date, date2: Date) => - new Date(date1).toLocaleDateString('en') === new Date(date2).toLocaleDateString('en'), - [] - ); + const isSameDate = useCallback((date1: Date | number | string, date2: Date | number | string) => { + return moment(date1).toISOString().split('T')[0] === moment(date2).toISOString().split('T')[0]; + }, []); // Memoize today, tomorrow, and future plans const todayPlan = useMemo( @@ -55,8 +53,12 @@ export const AllPlansModal = memo(function AllPlansModal(props: IAllPlansModal) ); const selectedPlan = useMemo( - () => customDate && myDailyPlans.items.find((plan) => isSameDate(plan.date, customDate)), - [isSameDate, myDailyPlans.items, customDate] + () => + customDate && + myDailyPlans.items.find((plan) => { + return isSameDate(plan.date.toString().split('T')[0], customDate.setHours(0, 0, 0, 0)); + }), + [customDate, myDailyPlans.items, isSameDate] ); // Handle modal close @@ -72,6 +74,11 @@ export const AllPlansModal = memo(function AllPlansModal(props: IAllPlansModal) // Handle tab switching const handleTabClick = (tab: CalendarTab) => { + if (tab === 'Today') { + setCustomDate(moment().toDate()); + } else if (tab === 'Tomorrow') { + setCustomDate(moment().add(1, 'days').toDate()); + } setSelectedTab(tab); setShowCalendar(tab === 'Calendar'); setShowCustomPlan(false); @@ -97,27 +104,24 @@ export const AllPlansModal = memo(function AllPlansModal(props: IAllPlansModal) // Set the related tab for today and tomorrow dates const handleCalendarSelect = useCallback(() => { if (customDate) { - if ( - new Date(customDate).toLocaleDateString('en') === new Date(moment().toDate()).toLocaleDateString('en') - ) { + if (isSameDate(customDate, moment().startOf('day').toDate())) { setSelectedTab('Today'); - } else if ( - new Date(customDate).toLocaleDateString('en') === - new Date(moment().add(1, 'days').toDate()).toLocaleDateString('en') - ) { + setCustomDate(moment.utc().toDate()); + } else if (isSameDate(customDate, moment().add(1, 'days').startOf('day').toDate())) { setSelectedTab('Tomorrow'); + setCustomDate(moment().add(1, 'days').toDate()); } else { setShowCalendar(false); setShowCustomPlan(true); } } - }, [customDate]); + }, [customDate, isSameDate]); const createEmptyPlan = useCallback(async () => { try { await createDailyPlan({ workTimePlanned: 0, - date: moment(customDate).toDate(), + date: new Date(moment(customDate).format('YYYY-MM-DD')), status: DailyPlanStatusEnum.OPEN, tenantId: user?.tenantId ?? '', employeeId: user?.employee.id, @@ -173,7 +177,7 @@ export const AllPlansModal = memo(function AllPlansModal(props: IAllPlansModal) -
+
{selectedTab === 'Calendar' && showCalendar ? (
@@ -194,7 +198,7 @@ export const AllPlansModal = memo(function AllPlansModal(props: IAllPlansModal)
) : ( <> - {plan ? ( + {selectedPlan ? ( + + ) : customDate ? ( ) : (
@@ -247,7 +263,7 @@ export const AllPlansModal = memo(function AllPlansModal(props: IAllPlansModal) */ interface ICalendarProps { - setSelectedPlan: Dispatch>; + setSelectedPlan: Dispatch>; selectedPlan: Date | undefined; plans: IDailyPlan[]; pastPlans: IDailyPlan[]; @@ -257,7 +273,7 @@ interface ICalendarProps { * The component that handles the selection of a plan * * @param {Object} props - The props object - * @param {Dispatch>} props.setSelectedFuturePlan - A function that set the selected plan + * @param {Dispatch>} props.setSelectedPlan - A function that set the selected plan * @param {IDailyPlan} props.selectedPlan - The selected plan * @param {IDailyPlan[]} props.plans - Available plans * @param {IDailyPlan[]} props.pastPlans - Past plans @@ -285,10 +301,12 @@ const FuturePlansCalendar = memo(function FuturePlansCalendar(props: ICalendarPr const isDateUnplanned = useCallback( (dateToCheck: Date) => { return !plans - .map((plan) => new Date(plan.date)) - .some( - (date) => new Date(date).toLocaleDateString('en') == new Date(dateToCheck).toLocaleDateString('en') - ); + .map((plan) => { + return moment(plan.date.toString().split('T')[0]).toISOString().split('T')[0]; + }) + .some((date) => { + return date === moment(dateToCheck).toISOString().split('T')[0]; + }); }, [plans] ); @@ -297,10 +315,10 @@ const FuturePlansCalendar = memo(function FuturePlansCalendar(props: ICalendarPr { if (date) { - setSelectedPlan(date); + setSelectedPlan(moment(date).toDate()); } }} initialFocus @@ -308,8 +326,8 @@ const FuturePlansCalendar = memo(function FuturePlansCalendar(props: ICalendarPr return checkPastDate(date) && isDateUnplanned(date); }} modifiers={{ - booked: sortedPlans?.map((plan) => new Date(plan.date)), - pastDay: pastPlans?.map((plan) => new Date(plan.date)) + booked: sortedPlans?.map((plan) => moment.utc(plan.date.toString().split('T')[0]).toDate()), + pastDay: pastPlans?.map((plan) => moment.utc(plan.date.toString().split('T')[0]).toDate()) }} modifiersClassNames={{ booked: clsxm( From 366136e8b94515695b7a303de736f51bfec8e496 Mon Sep 17 00:00:00 2001 From: CREDO23 Date: Tue, 1 Oct 2024 01:52:37 +0200 Subject: [PATCH 2/2] use i18 --- .../add-task-estimation-hours-modal.tsx | 14 ++++---- .../features/daily-plan/all-plans-modal.tsx | 35 ++++++++++++------- .../team/user-team-card/task-skeleton.tsx | 2 +- .../user-team-card/user-team-card-menu.tsx | 2 +- apps/web/locales/ar.json | 19 +++++++++- apps/web/locales/bg.json | 19 +++++++++- apps/web/locales/de.json | 19 +++++++++- apps/web/locales/en.json | 19 +++++++++- apps/web/locales/es.json | 19 +++++++++- apps/web/locales/fr.json | 19 +++++++++- apps/web/locales/he.json | 19 +++++++++- apps/web/locales/it.json | 19 +++++++++- apps/web/locales/nl.json | 19 +++++++++- apps/web/locales/pl.json | 19 +++++++++- apps/web/locales/pt.json | 19 +++++++++- apps/web/locales/ru.json | 19 +++++++++- apps/web/locales/zh.json | 19 +++++++++- 17 files changed, 265 insertions(+), 35 deletions(-) diff --git a/apps/web/lib/features/daily-plan/add-task-estimation-hours-modal.tsx b/apps/web/lib/features/daily-plan/add-task-estimation-hours-modal.tsx index e4099dc63..8914ae272 100644 --- a/apps/web/lib/features/daily-plan/add-task-estimation-hours-modal.tsx +++ b/apps/web/lib/features/daily-plan/add-task-estimation-hours-modal.tsx @@ -69,7 +69,7 @@ export function AddTasksEstimationHoursModal(props: IAddTasksEstimationHoursModa const totalWorkedTime = useMemo( () => plan && plan.tasks - ? plan.tasks?.reduce((acc, cur) => { + ? plan.tasks.reduce((acc, cur) => { const totalWorkedTime = cur.totalWorkedTime ?? 0; return acc + totalWorkedTime; @@ -81,7 +81,7 @@ export function AddTasksEstimationHoursModal(props: IAddTasksEstimationHoursModa const [loading, setLoading] = useState(false); const [defaultTask, setDefaultTask] = useState(null); const isActiveTaskPlanned = useMemo( - () => plan && plan.tasks && plan.tasks?.some((task) => task.id == activeTeamTask?.id), + () => plan && plan.tasks && plan.tasks.some((task) => task.id == activeTeamTask?.id), [activeTeamTask?.id, plan] ); const [isWorkingTimeInputFocused, setWorkingTimeInputFocused] = useState(false); @@ -278,12 +278,12 @@ export function AddTasksEstimationHoursModal(props: IAddTasksEstimationHoursModa ) : canStartWorking ? ( timerStatus?.running && planEditState.draft ? ( - 'Save Changes' + t('common.SAVE_CHANGES') ) : ( t('timer.todayPlanSettings.START_WORKING_BUTTON') ) ) : ( - 'Edit plan' + t('common.plan.EDIT_PLAN') )} ); @@ -381,7 +381,7 @@ export function AddTasksEstimationHoursModal(props: IAddTasksEstimationHoursModa
{checkPastDate(plan?.date ?? selectedDate) && (
- Tracked time + {t('common.plan.TRACKED_TIME')}
{formatIntegerToHour(totalWorkedTime ?? 0)}
@@ -449,11 +449,11 @@ export function AddTasksEstimationHoursModal(props: IAddTasksEstimationHoursModa {isRenderedInSoftFlow ? t('common.SKIP_ADD_LATER') : t('common.CANCEL')} {timerStatus?.running && !planEditState.draft ? ( - + {StartWorkingButton} ) : ( -
{StartWorkingButton}
+
{StartWorkingButton}
)}
diff --git a/apps/web/lib/features/daily-plan/all-plans-modal.tsx b/apps/web/lib/features/daily-plan/all-plans-modal.tsx index 43888f3b8..1550263c3 100644 --- a/apps/web/lib/features/daily-plan/all-plans-modal.tsx +++ b/apps/web/lib/features/daily-plan/all-plans-modal.tsx @@ -11,6 +11,7 @@ import { DailyPlanStatusEnum, IDailyPlan } from '@app/interfaces'; import moment from 'moment'; import { ValueNoneIcon } from '@radix-ui/react-icons'; import { checkPastDate } from 'lib/utils'; +import { useTranslations } from 'next-intl'; interface IAllPlansModal { closeModal: () => void; @@ -35,6 +36,7 @@ export const AllPlansModal = memo(function AllPlansModal(props: IAllPlansModal) const [showCustomPlan, setShowCustomPlan] = useState(false); const [customDate, setCustomDate] = useState(moment().toDate()); const { myDailyPlans, pastPlans } = useDailyPlan(); + const t = useTranslations(); // Utility function for checking if two dates are the same const isSameDate = useCallback((date1: Date | number | string, date2: Date | number | string) => { @@ -106,7 +108,7 @@ export const AllPlansModal = memo(function AllPlansModal(props: IAllPlansModal) if (customDate) { if (isSameDate(customDate, moment().startOf('day').toDate())) { setSelectedTab('Today'); - setCustomDate(moment.utc().toDate()); + setCustomDate(moment().toDate()); } else if (isSameDate(customDate, moment().add(1, 'days').startOf('day').toDate())) { setSelectedTab('Tomorrow'); setCustomDate(moment().add(1, 'days').toDate()); @@ -149,7 +151,7 @@ export const AllPlansModal = memo(function AllPlansModal(props: IAllPlansModal) - Back + {t('common.BACK')} )} @@ -157,9 +159,11 @@ export const AllPlansModal = memo(function AllPlansModal(props: IAllPlansModal) {selectedTab == 'Calendar' ? showCustomPlan && selectedPlan - ? `PLAN FOR ${new Date(selectedPlan.date).toLocaleDateString('en-GB')}` - : `PLANS` - : `${selectedTab}'S PLAN`} + ? t('common.plan.FOR_DATE', { + date: new Date(selectedPlan.date).toLocaleDateString('en-GB') + }) + : t('common.plan.PLURAL') + : `${selectedTab === 'Today' ? t('common.plan.FOR_TODAY') : selectedTab === 'Tomorrow' ? t('common.plan.FOR_TOMORROW') : ''}`}
@@ -170,7 +174,13 @@ export const AllPlansModal = memo(function AllPlansModal(props: IAllPlansModal) className={`flex justify-center gap-4 items-center hover:text-primary cursor-pointer ${selectedTab === tab ? 'text-primary font-medium' : ''}`} onClick={() => handleTabClick(tab)} > - {tab} + + {tab === 'Today' + ? t('common.TODAY') + : tab === 'Tomorrow' + ? t('common.TOMORROW') + : t('common.CALENDAR')} + {index + 1 < tabs.length && } ))} @@ -182,7 +192,7 @@ export const AllPlansModal = memo(function AllPlansModal(props: IAllPlansModal)
-

Select a date to be able to see a plan

+

{t('common.plan.CHOOSE_DATE')}

- Cancel + {t('common.CANCEL')}
@@ -235,8 +245,7 @@ export const AllPlansModal = memo(function AllPlansModal(props: IAllPlansModal) /> ) : customDate ? ( ) : (
- } text="Plan not found " /> + } text={t('common.plan.PLAN_NOT_FOUND')} />
)} diff --git a/apps/web/lib/features/team/user-team-card/task-skeleton.tsx b/apps/web/lib/features/team/user-team-card/task-skeleton.tsx index e23538c55..7212cee4e 100644 --- a/apps/web/lib/features/team/user-team-card/task-skeleton.tsx +++ b/apps/web/lib/features/team/user-team-card/task-skeleton.tsx @@ -59,7 +59,7 @@ export function UserTeamCardHeader() {
-
+
{t('dailyPlan.TASK_TIME')} diff --git a/apps/web/lib/features/team/user-team-card/user-team-card-menu.tsx b/apps/web/lib/features/team/user-team-card/user-team-card-menu.tsx index 0e331efcd..ff074df9b 100644 --- a/apps/web/lib/features/team/user-team-card/user-team-card-menu.tsx +++ b/apps/web/lib/features/team/user-team-card/user-team-card-menu.tsx @@ -194,7 +194,7 @@ function DropdownMenu({ edition, memberInfo }: Props) { 'font-normal whitespace-nowrap text-sm hover:font-semibold hover:transition-all' )} > - See Plan + {t('common.plan.SEE_PLANS')} diff --git a/apps/web/locales/ar.json b/apps/web/locales/ar.json index 366a8a383..20d3f0635 100644 --- a/apps/web/locales/ar.json +++ b/apps/web/locales/ar.json @@ -202,7 +202,23 @@ "SKIP_ADD_LATER": "أضف لاحقًا", "DAILYPLAN": "مخطط", "INVITATION_SENT": "تم إرسال دعوة بنجاح", - "INVITATION_SENT_TO_USER": "تم إرسال دعوة فريق إلى {email}." + "INVITATION_SENT_TO_USER": "تم إرسال دعوة فريق إلى {email}.", + "CALENDAR": "تقويم", + "SELECT": "اختر", + "SAVE_CHANGES": "حفظ التغييرات", + "plan": { + "SINGULAR": "خطة", + "PLURAL": "خطط", + "CHOOSE_DATE": "اختر تاريخًا لتتمكن من رؤية خطة", + "PLAN_NOT_FOUND": "لم يتم العثور على خطة", + "FOR_DATE": "خطة لِـ {date}", + "FOR_TODAY": "خطة اليوم", + "FOR_TOMORROW": "خطة الغد", + "EDIT_PLAN": "تعديل الخطة", + "TRACKED_TIME": "الوقت المتعقب", + "SEE_PLANS": "عرض الخطط", + "ADD_PLAN": "إضافة خطة" + } }, "hotkeys": { "HELP": "مساعدة", @@ -537,6 +553,7 @@ "WORK_TIME_PLANNED_PLACEHOLDER": "وقت العمل المخطط له اليوم", "TASKS_WITH_NO_ESTIMATIONS": "تاكس مع عدم وجود تقديرات زمنية", "START_WORKING_BUTTON": "ابدأ العمل", + "TIMER_RUNNING": "المؤقت قيد التشغيل بالفعل", "WARNING_PLAN_ESTIMATION": "رجى تصحيح ساعات العمل المخطط لها أو إعادة تقدير المهمة (المهام)" } }, diff --git a/apps/web/locales/bg.json b/apps/web/locales/bg.json index 578d64818..22a7213a7 100644 --- a/apps/web/locales/bg.json +++ b/apps/web/locales/bg.json @@ -202,7 +202,23 @@ "SKIP_ADD_LATER": "Добави по-късно", "DAILYPLAN": "Планирано", "INVITATION_SENT": "Покана е изпратена успешно", - "INVITATION_SENT_TO_USER": "Покана е изпратена на {email}." + "INVITATION_SENT_TO_USER": "Покана е изпратена на {email}.", + "CALENDAR": "Календар", + "SELECT": "Изберете", + "SAVE_CHANGES": "Запази промените", + "plan": { + "SINGULAR": "План", + "PLURAL": "Планове", + "CHOOSE_DATE": "Изберете дата, за да видите план", + "PLAN_NOT_FOUND": "Не е намерен план", + "FOR_DATE": "ПЛАН ЗА {date}", + "FOR_TODAY": "Днешният план", + "FOR_TOMORROW": "Утрешният план", + "EDIT_PLAN": "Редактиране на план", + "TRACKED_TIME": "Проследено време", + "SEE_PLANS": "Виж планове", + "ADD_PLAN": "Добави план" + } }, "hotkeys": { "HELP": "Помощ", @@ -537,6 +553,7 @@ "WORK_TIME_PLANNED_PLACEHOLDER": "Планирано работно време за днес", "TASKS_WITH_NO_ESTIMATIONS": "Такси без оценки на времето", "START_WORKING_BUTTON": "Започнете работа", + "TIMER_RUNNING": "Таймерът вече работи", "WARNING_PLAN_ESTIMATION": "Моля, коригирайте планираните работни часове или преоценете задачата(ите) " } }, diff --git a/apps/web/locales/de.json b/apps/web/locales/de.json index 43e1088b2..2a991ad2c 100644 --- a/apps/web/locales/de.json +++ b/apps/web/locales/de.json @@ -202,7 +202,23 @@ "SKIP_ADD_LATER": "Später hinzufügen", "DAILYPLAN": "Plan dzienny", "INVITATION_SENT": "Einladung erfolgreich gesendet", - "INVITATION_SENT_TO_USER": "Eine Teameinladung wurde an {email} gesendet." + "INVITATION_SENT_TO_USER": "Eine Teameinladung wurde an {email} gesendet.", + "CALENDAR": "Kalender", + "SELECT": "Auswählen", + "SAVE_CHANGES": "Änderungen speichern", + "plan": { + "SINGULAR": "Plan", + "PLURAL": "Pläne", + "CHOOSE_DATE": "Wählen Sie ein Datum, um einen Plan zu sehen", + "PLAN_NOT_FOUND": "Plan nicht gefunden", + "FOR_DATE": "PLAN FÜR {date}", + "FOR_TODAY": "Heutiger Plan", + "FOR_TOMORROW": "Morgenplan", + "EDIT_PLAN": "Plan bearbeiten", + "TRACKED_TIME": "Verfolgte Zeit", + "SEE_PLANS": "Pläne anzeigen", + "ADD_PLAN": "Plan hinzufügen" + } }, "hotkeys": { "HELP": "Hilfe", @@ -537,6 +553,7 @@ "WORK_TIME_PLANNED_PLACEHOLDER": "Für heute geplante Arbeitszeit", "TASKS_WITH_NO_ESTIMATIONS": "Taks ohne Zeitvorgaben", "START_WORKING_BUTTON": "Mit der Arbeit beginnen", + "TIMER_RUNNING": "Der Timer läuft bereits", "WARNING_PLAN_ESTIMATION": "Bitte korrigieren Sie die geplanten Arbeitsstunden oder schätzen Sie die Aufgabe(n) neu ein." } }, diff --git a/apps/web/locales/en.json b/apps/web/locales/en.json index 2febfb13e..1d899b517 100644 --- a/apps/web/locales/en.json +++ b/apps/web/locales/en.json @@ -202,7 +202,23 @@ "SKIP_ADD_LATER": "Add later", "DAILYPLAN": "Planned", "INVITATION_SENT": "Invitation Sent Successfully", - "INVITATION_SENT_TO_USER": "A team invitation has been sent to {email}." + "INVITATION_SENT_TO_USER": "A team invitation has been sent to {email}.", + "CALENDAR": "Calendar", + "SELECT": "Select", + "SAVE_CHANGES": "Save changes", + "plan": { + "SINGULAR": "Plan", + "PLURAL": "Plans", + "CHOOSE_DATE": "Select a date to be able to see a plan", + "PLAN_NOT_FOUND": "Plan not found", + "FOR_DATE": "PLAN FOR {date}", + "FOR_TODAY": "Today's plan", + "FOR_TOMORROW": "Tomorrow's plan", + "EDIT_PLAN": "Edit Plan", + "TRACKED_TIME": "Tracked time", + "SEE_PLANS": "See plans", + "ADD_PLAN": "Add Plan" + } }, "hotkeys": { "HELP": "Help", @@ -537,6 +553,7 @@ "WORK_TIME_PLANNED_PLACEHOLDER": "Working time planned for today", "TASKS_WITH_NO_ESTIMATIONS": "Tasks with no time estimations", "START_WORKING_BUTTON": "Start working", + "TIMER_RUNNING": "The timer is already running", "WARNING_PLAN_ESTIMATION": "Please correct planned work hours or re-estimate task(s)" } }, diff --git a/apps/web/locales/es.json b/apps/web/locales/es.json index fa97289f2..180217121 100644 --- a/apps/web/locales/es.json +++ b/apps/web/locales/es.json @@ -202,7 +202,23 @@ "SKIP_ADD_LATER": "Agregar más tarde", "DAILYPLAN": "Planificado", "INVITATION_SENT": "Invitación enviada con éxito", - "INVITATION_SENT_TO_USER": "Se ha enviado una invitación de equipo a {email}." + "INVITATION_SENT_TO_USER": "Se ha enviado una invitación de equipo a {email}.", + "CALENDAR": "Calendario", + "SELECT": "Seleccionar", + "SAVE_CHANGES": "Guardar cambios", + "plan": { + "SINGULAR": "Plan", + "PLURAL": "Planes", + "CHOOSE_DATE": "Seleccione una fecha para poder ver un plan", + "PLAN_NOT_FOUND": "Plan no encontrado", + "FOR_DATE": "PLAN PARA {date}", + "FOR_TODAY": "Plan de hoy", + "EDIT_PLAN": "Editar Plan", + "ADD_PLAN": "Agregar Plan", + "TRACKED_TIME": "Tiempo registrado", + "SEE_PLANS": "Ver planes", + "FOR_TOMORROW": "Plan de mañana" + } }, "hotkeys": { "HELP": "Ayuda", @@ -537,6 +553,7 @@ "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", + "TIMER_RUNNING": "El temporizador ya está en ejecución", "WARNING_PLAN_ESTIMATION": "Por favor, corrija las horas de trabajo previstas o reevalúe la(s) tarea(s)" } }, diff --git a/apps/web/locales/fr.json b/apps/web/locales/fr.json index b422827f3..810c18895 100644 --- a/apps/web/locales/fr.json +++ b/apps/web/locales/fr.json @@ -202,7 +202,23 @@ "SKIP_ADD_LATER": "Ajouter plus tard", "DAILYPLAN": "Planifié", "INVITATION_SENT": "Invitation envoyée avec succès", - "INVITATION_SENT_TO_USER": "Une invitation a été envoyée à {email}." + "INVITATION_SENT_TO_USER": "Une invitation a été envoyée à {email}.", + "CALENDAR": "Calendrier", + "SELECT": "Sélectionner", + "SAVE_CHANGES": "Enregistrer les modifications", + "plan": { + "SINGULAR": "Plan", + "PLURAL": "Plans", + "CHOOSE_DATE": "Sélectionnez une date pour pouvoir voir un plan", + "PLAN_NOT_FOUND": "Plan non trouvé", + "FOR_DATE": "PLAN POUR {date}", + "FOR_TODAY": "Le plan d'aujourd'hui", + "FOR_TOMORROW": "Le plan de demain", + "EDIT_PLAN": "Modifier le plan", + "TRACKED_TIME": "Temps suivi", + "SEE_PLANS": "Voir les plans", + "ADD_PLAN": "Ajouter un plan" + } }, "hotkeys": { "HELP": "Aide", @@ -520,6 +536,7 @@ "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", + "TIMER_RUNNING": "Le minuteur fonctionne déjà", "WARNING_PLAN_ESTIMATION": "Veuillez corriger les heures de travail prévues ou réévaluer la/les tâche(s)" }, "TIME_ACTIVITY": "Activité", diff --git a/apps/web/locales/he.json b/apps/web/locales/he.json index 36c0a130c..9da22459d 100644 --- a/apps/web/locales/he.json +++ b/apps/web/locales/he.json @@ -202,7 +202,23 @@ "SKIP_ADD_LATER": "הוסף מאוחר יותר", "DAILYPLAN": "מְתוּכנָן", "INVITATION_SENT": "ההזמנה נשלחה בהצלחה", - "INVITATION_SENT_TO_USER": "ההזמנה נשלחה ל{email}." + "INVITATION_SENT_TO_USER": "ההזמנה נשלחה ל{email}.", + "CALENDAR": "לוח שנה", + "SELECT": "בחר", + "SAVE_CHANGES": "שמור שינויים", + "plan": { + "SINGULAR": "תכנית", + "PLURAL": "תכניות", + "CHOOSE_DATE": "בחר תאריך כדי לראות תוכנית", + "PLAN_NOT_FOUND": "התוכנית לא נמצאה", + "FOR_DATE": "תכנית ל-{date}", + "FOR_TODAY": "תכנית להיום", + "FOR_TOMORROW": "תכנית למחר", + "EDIT_PLAN": "ערוך תוכנית", + "TRACKED_TIME": "זמן מעקב", + "SEE_PLANS": "ראה תוכניות", + "ADD_PLAN": "הוסף תוכנית" + } }, "hotkeys": { "HELP": "עזרה", @@ -537,6 +553,7 @@ "WORK_TIME_PLANNED_PLACEHOLDER": "זמן עבודה מתוכנן להיום", "TASKS_WITH_NO_ESTIMATIONS": "משימות בלי הערכת זמן", "START_WORKING_BUTTON": "התחל לעבוד", + "TIMER_RUNNING": "הטיימר כבר פועל", "WARNING_PLAN_ESTIMATION": "נא לתקן את שעות העבודה המתוכננות או להעריך מחדש את המשימות" } }, diff --git a/apps/web/locales/it.json b/apps/web/locales/it.json index 09de582a1..02c5dc5a8 100644 --- a/apps/web/locales/it.json +++ b/apps/web/locales/it.json @@ -202,7 +202,23 @@ "SKIP_ADD_LATER": "Aggiungi dopo", "DAILYPLAN": "Pianificato", "INVITATION_SENT": "Invito inviato con successo", - "INVITATION_SENT_TO_USER": "Un invito alla squadra è stato inviato a {email}." + "INVITATION_SENT_TO_USER": "Un invito alla squadra è stato inviato a {email}.", + "CALENDAR": "Calendario", + "SELECT": "Seleziona", + "SAVE_CHANGES": "Salva modifiche", + "plan": { + "SINGULAR": "Piano", + "PLURAL": "Piani", + "CHOOSE_DATE": "Seleziona una data per poter vedere un piano", + "PLAN_NOT_FOUND": "Piano non trovato", + "FOR_DATE": "PIANO PER {date}", + "FOR_TODAY": "Piano di oggi", + "FOR_TOMORROW": "Piano di domani", + "EDIT_PLAN": "Modifica Piano", + "TRACKED_TIME": "Tempo tracciato", + "SEE_PLANS": "Vedi piani", + "ADD_PLAN": "Aggiungi Piano" + } }, "hotkeys": { "HELP": "Aiuto", @@ -520,6 +536,7 @@ "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", + "TIMER_RUNNING": "Il timer è già in esecuzione", "WARNING_PLAN_ESTIMATION": "Correggere le ore di lavoro previste o rivalutare il/i compito/i." }, "TIME_ACTIVITY": "Attività", diff --git a/apps/web/locales/nl.json b/apps/web/locales/nl.json index d529bc994..0b7680e1b 100644 --- a/apps/web/locales/nl.json +++ b/apps/web/locales/nl.json @@ -202,7 +202,23 @@ "SKIP_ADD_LATER": "Later toevoegen", "DAILYPLAN": "Gepland", "INVITATION_SENT": "Uitnodiging verzonden", - "INVITATION_SENT_TO_USER": "Een teamuitnodiging is verzonden naar {email}." + "INVITATION_SENT_TO_USER": "Een teamuitnodiging is verzonden naar {email}.", + "CALENDAR": "Kalender", + "SELECT": "Selecteren", + "SAVE_CHANGES": "Wijzigingen opslaan", + "plan": { + "SINGULAR": "Plan", + "PLURAL": "Plannen", + "CHOOSE_DATE": "Selecteer een datum om een plan te kunnen zien", + "PLAN_NOT_FOUND": "Plan niet gevonden", + "FOR_DATE": "PLAN VOOR {date}", + "FOR_TODAY": "Vandaag's plan", + "FOR_TOMORROW": "Morgen's plan", + "EDIT_PLAN": "Plan bewerken", + "TRACKED_TIME": "Gegeneraliseerde tijd", + "SEE_PLANS": "Plannen bekijken", + "ADD_PLAN": "Plan toevoegen" + } }, "hotkeys": { "HELP": "Help", @@ -537,6 +553,7 @@ "WORK_TIME_PLANNED_PLACEHOLDER": "Geplande werktijd voor vandaag", "TASKS_WITH_NO_ESTIMATIONS": "Taken zonder tijdschattingen", "START_WORKING_BUTTON": "Begin met werken", + "TIMER_RUNNING": "De timer loopt al", "WARNING_PLAN_ESTIMATION": "Corrigeer de geplande werkuren of schat de taak(en) opnieuw in" } }, diff --git a/apps/web/locales/pl.json b/apps/web/locales/pl.json index b3c753449..f22554646 100644 --- a/apps/web/locales/pl.json +++ b/apps/web/locales/pl.json @@ -202,7 +202,23 @@ "SKIP_ADD_LATER": "Dodaj później", "DAILYPLAN": "Planowane", "INVITATION_SENT": "Zaproszenie wysłane", - "INVITATION_SENT_TO_USER": "Zaproszenie zespołu zostało wysłane do {email}." + "INVITATION_SENT_TO_USER": "Zaproszenie zespołu zostało wysłane do {email}.", + "CALENDAR": "Kalendarz", + "SELECT": "Wybierz", + "SAVE_CHANGES": "Zapisz zmiany", + "plan": { + "SINGULAR": "Plan", + "PLURAL": "Plany", + "CHOOSE_DATE": "Wybierz datę, aby móc zobaczyć plan", + "PLAN_NOT_FOUND": "Plan nie znaleziony", + "FOR_DATE": "PLAN NA {date}", + "FOR_TODAY": "Dzienny plan", + "FOR_TOMORROW": "Jutro plan", + "EDIT_PLAN": "Edytuj plan", + "TRACKED_TIME": "Śledzony czas", + "SEE_PLANS": "Zobacz plany", + "ADD_PLAN": "Dodaj plan" + } }, "hotkeys": { "HELP": "Pomoc", @@ -520,6 +536,7 @@ "WORK_TIME_PLANNED_PLACEHOLDER": "Zaplanowany czas pracy na dziś", "TASKS_WITH_NO_ESTIMATIONS": "Zadania bez oszacowania czasu", "START_WORKING_BUTTON": "Rozpocznij pracę", + "TIMER_RUNNING": "Timer już działa", "WARNING_PLAN_ESTIMATION": "Popraw planowane godziny pracy lub ponownie oszacuj zadania" }, "TIME_ACTIVITY": "Aktywność", diff --git a/apps/web/locales/pt.json b/apps/web/locales/pt.json index efcbf1bc8..906719445 100644 --- a/apps/web/locales/pt.json +++ b/apps/web/locales/pt.json @@ -202,7 +202,23 @@ "SKIP_ADD_LATER": "Adicionar depois", "DAILYPLAN": "Planeado", "INVITATION_SENT": "Convite enviado com sucesso", - "INVITATION_SENT_TO_USER": "Um convite de equipe foi enviado para {email}." + "INVITATION_SENT_TO_USER": "Um convite de equipe foi enviado para {email}.", + "CALENDAR": "Calendário", + "SELECT": "Selecionar", + "SAVE_CHANGES": "Salvar alterações", + "plan": { + "SINGULAR": "Plano", + "PLURAL": "Planos", + "CHOOSE_DATE": "Selecione uma data para poder ver um plano", + "PLAN_NOT_FOUND": "Plano não encontrado", + "FOR_DATE": "PLANO PARA {date}", + "FOR_TODAY": "Plano de hoje", + "FOR_TOMORROW": "Plano de amanhã", + "EDIT_PLAN": "Editar Plano", + "TRACKED_TIME": "Tempo rastreado", + "SEE_PLANS": "Ver planos", + "ADD_PLAN": "Adicionar Plano" + } }, "hotkeys": { "HELP": "Ajuda", @@ -520,6 +536,7 @@ "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", + "TIMER_RUNNING": "O temporizador já está em execução", "WARNING_PLAN_ESTIMATION": "Corrigir as horas de trabalho planeadas ou fazer uma nova estimativa da(s) tarefa(s)" }, "TIME_ACTIVITY": "Atividade", diff --git a/apps/web/locales/ru.json b/apps/web/locales/ru.json index defbb101c..dc9e61b3d 100644 --- a/apps/web/locales/ru.json +++ b/apps/web/locales/ru.json @@ -202,7 +202,23 @@ "SKIP_ADD_LATER": "Добавить позже", "DAILYPLAN": "Планируется", "INVITATION_SENT": "Приглашение отправлено успешно", - "INVITATION_SENT_TO_USER": "Приглашение к команде было отправлено на {email}." + "INVITATION_SENT_TO_USER": "Приглашение к команде было отправлено на {email}.", + "CALENDAR": "Календарь", + "SELECT": "Выбрать", + "SAVE_CHANGES": "Сохранить изменения", + "plan": { + "SINGULAR": "План", + "PLURAL": "Планы", + "CHOOSE_DATE": "Выберите дату, чтобы увидеть план", + "PLAN_NOT_FOUND": "План не найден", + "FOR_DATE": "ПЛАН НА {date}", + "FOR_TODAY": "Сегодняшний план", + "FOR_TOMORROW": "Завтрашний план", + "EDIT_PLAN": "Редактировать план", + "TRACKED_TIME": "Отслеживаемое время", + "SEE_PLANS": "Посмотреть планы", + "ADD_PLAN": "Agregar Plan" + } }, "hotkeys": { "HELP": "Помощь", @@ -520,6 +536,7 @@ "WORK_TIME_PLANNED_PLACEHOLDER": "Запланированное время работы на сегодня", "TASKS_WITH_NO_ESTIMATIONS": "Задачи без оценки времени", "START_WORKING_BUTTON": "Начать работу", + "TIMER_RUNNING": "Таймер уже запущен", "WARNING_PLAN_ESTIMATION": "Пожалуйста, исправьте запланированные часы работы или пересчитайте задание(я)" }, "TIME_ACTIVITY": "Активность", diff --git a/apps/web/locales/zh.json b/apps/web/locales/zh.json index d60241854..1c0d0153c 100644 --- a/apps/web/locales/zh.json +++ b/apps/web/locales/zh.json @@ -202,7 +202,23 @@ "SKIP_ADD_LATER": "稍后添加", "DAILYPLAN": "計劃中", "INVITATION_SENT": "邀请已发送", - "INVITATION_SENT_TO_USER": "团队邀请已发送给 {email}。" + "INVITATION_SENT_TO_USER": "团队邀请已发送给 {email}。", + "CALENDAR": "日历", + "SELECT": "Select", + "SAVE_CHANGES": "保存更改", + "plan": { + "SINGULAR": "计划", + "PLURAL": "计划", + "CHOOSE_DATE": "选择一个日期以查看计划", + "PLAN_NOT_FOUND": "未找到计划", + "FOR_DATE": "针对日期 {date}", + "FOR_TODAY": "今天的计划", + "FOR_TOMORROW": "明天的计划", + "EDIT_PLAN": "编辑计划", + "TRACKED_TIME": "跟踪时间", + "SEE_PLANS": "查看计划", + "ADD_PLAN": "添加计划" + } }, "hotkeys": { "HELP": "帮助", @@ -537,6 +553,7 @@ "WORK_TIME_PLANNED_PLACEHOLDER": "今天计划的工作时间", "TASKS_WITH_NO_ESTIMATIONS": "没有时间估算的任务", "START_WORKING_BUTTON": "开始工作", + "TIMER_RUNNING": "计时器已经在运行", "WARNING_PLAN_ESTIMATION": "请更正计划工时或重新估算任务工时" } },