From f815aaced6a68885fded0210a20172624c83d5e0 Mon Sep 17 00:00:00 2001 From: GloireMutaliko21 Date: Tue, 30 Apr 2024 11:00:37 +0200 Subject: [PATCH 01/21] style: init Daily Plan tab --- apps/web/app/hooks/features/useAuthTeamTasks.ts | 10 +++++++++- .../task/details-section/blocks/task-progress.tsx | 10 +++++----- apps/web/lib/features/activity/screenshoots.tsx | 4 +++- apps/web/lib/features/task/task-filters.tsx | 11 +++++++++-- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/apps/web/app/hooks/features/useAuthTeamTasks.ts b/apps/web/app/hooks/features/useAuthTeamTasks.ts index c6853703a..025166418 100644 --- a/apps/web/app/hooks/features/useAuthTeamTasks.ts +++ b/apps/web/app/hooks/features/useAuthTeamTasks.ts @@ -24,6 +24,13 @@ export function useAuthTeamTasks(user: IUser | undefined) { }); }, [tasks, user]); + const dailyplan = useMemo(() => { + if (!user) return []; + return tasks.filter((task) => { + return !task?.members.some((m) => m.userId === user.id); + }); + }, [tasks, user]); + const totalTodayTasks = useMemo( () => currentMember?.totalTodayTasks && currentMember?.totalTodayTasks.length @@ -41,6 +48,7 @@ export function useAuthTeamTasks(user: IUser | undefined) { return { assignedTasks, unassignedTasks, - workedTasks + workedTasks, + dailyplan }; } diff --git a/apps/web/components/pages/task/details-section/blocks/task-progress.tsx b/apps/web/components/pages/task/details-section/blocks/task-progress.tsx index 3281e335e..ff739b44b 100644 --- a/apps/web/components/pages/task/details-section/blocks/task-progress.tsx +++ b/apps/web/components/pages/task/details-section/blocks/task-progress.tsx @@ -70,8 +70,8 @@ const TaskProgress = () => { }, [userTotalTimeOnTaskToday]); useEffect(() => { - const matchingMembers: OT_Member[] | undefined = activeTeam?.members.filter( - (member) => task?.members.some((taskMember) => taskMember.id === member.employeeId) + const matchingMembers: OT_Member[] | undefined = activeTeam?.members.filter((member) => + task?.members.some((taskMember) => taskMember.id === member.employeeId) ); const usersTaskArray: ITasksTimesheet[] | undefined = matchingMembers @@ -181,12 +181,12 @@ const IndividualMembersTotalTime = ({ numMembersToShow }: { numMembersToShow: nu const [task] = useRecoilState(detailedTaskState); const { activeTeam } = useOrganizationTeams(); - const matchingMembers: OT_Member[] | undefined = activeTeam?.members.filter( - (member) => task?.members.some((taskMember) => taskMember.id === member.employeeId) + const matchingMembers: OT_Member[] | undefined = activeTeam?.members.filter((member) => + task?.members.some((taskMember) => taskMember.id === member.employeeId) ); const findUserTotalWorked = (user: OT_Member, id: string | undefined) => { - return user?.totalWorkedTasks.find((task: any) => task?.id === id)?.duration || 0; + return user?.totalWorkedTasks?.find((task: any) => task?.id === id)?.duration || 0; }; return ( diff --git a/apps/web/lib/features/activity/screenshoots.tsx b/apps/web/lib/features/activity/screenshoots.tsx index 6a1984030..6cae32e83 100644 --- a/apps/web/lib/features/activity/screenshoots.tsx +++ b/apps/web/lib/features/activity/screenshoots.tsx @@ -21,7 +21,9 @@ export function ScreenshootTab() { {/* Stats cards */}
{t('timer.TIME_ACTIVITY')} -

{activityPercent.toFixed(2)} %

+

+ {isNaN(parseFloat(activityPercent.toFixed(2))) ? '00' : activityPercent.toFixed(2)} % +

diff --git a/apps/web/lib/features/task/task-filters.tsx b/apps/web/lib/features/task/task-filters.tsx index a94d77ebd..e104590fb 100644 --- a/apps/web/lib/features/task/task-filters.tsx +++ b/apps/web/lib/features/task/task-filters.tsx @@ -14,7 +14,7 @@ import { TaskLabelsDropdown, TaskPropertiesDropdown, TaskSizesDropdown, TaskStat import { useTranslations } from 'next-intl'; import { SettingFilterIcon } from 'assets/svg'; -type ITab = 'worked' | 'assigned' | 'unassigned'; +type ITab = 'worked' | 'assigned' | 'unassigned' | 'dailyplan'; type ITabs = { tab: ITab; name: string; @@ -49,7 +49,8 @@ export function useTaskFilter(profile: I_UserProfilePage) { const tasksFiltered: { [x in ITab]: ITeamTask[] } = { unassigned: profile.tasksGrouped.unassignedTasks, assigned: profile.tasksGrouped.assignedTasks, - worked: profile.tasksGrouped.workedTasks + worked: profile.tasksGrouped.workedTasks, + dailyplan: profile.tasksGrouped.dailyplan }; const tasks = tasksFiltered[tab]; @@ -83,6 +84,12 @@ export function useTaskFilter(profile: I_UserProfilePage) { name: t('common.UNASSIGNED'), description: t('task.tabFilter.UNASSIGNED_DESCRIPTION'), count: profile.tasksGrouped.unassignedTasks.length + }, + { + tab: 'dailyplan', + name: 'Daily Plan', + description: 'This tab shows all yours tasks planned', + count: profile.tasksGrouped.dailyplan.length } ]; From 6243ba3a098eb9a5ac75de5dc3378f6a4b45693d Mon Sep 17 00:00:00 2001 From: GedeonTS Date: Tue, 30 Apr 2024 20:42:02 +0200 Subject: [PATCH 02/21] [Improvement] Add translations to the empty messages of the team-members-block-view --- apps/web/lib/features/team-members-block-view.tsx | 6 +++--- apps/web/messages/ar.json | 5 ++++- apps/web/messages/bg.json | 5 ++++- apps/web/messages/de.json | 5 ++++- apps/web/messages/en.json | 5 ++++- apps/web/messages/es.json | 5 ++++- apps/web/messages/fr.json | 5 ++++- apps/web/messages/he.json | 5 ++++- apps/web/messages/it.json | 5 ++++- apps/web/messages/nl.json | 5 ++++- apps/web/messages/pl.json | 5 ++++- apps/web/messages/pt.json | 6 ++++-- apps/web/messages/ru.json | 5 ++++- apps/web/messages/zh.json | 5 ++++- apps/web/public/locales/ar/common.json | 5 ++++- apps/web/public/locales/bg/common.json | 5 ++++- apps/web/public/locales/de/common.json | 5 ++++- apps/web/public/locales/en/common.json | 5 ++++- apps/web/public/locales/es/common.json | 5 ++++- apps/web/public/locales/fr/common.json | 5 ++++- apps/web/public/locales/he/common.json | 5 ++++- apps/web/public/locales/it/common.json | 5 ++++- apps/web/public/locales/nl/common.json | 5 ++++- apps/web/public/locales/pl/common.json | 5 ++++- apps/web/public/locales/pt/common.json | 5 ++++- apps/web/public/locales/ru/common.json | 5 ++++- apps/web/public/locales/zh/common.json | 5 ++++- 27 files changed, 107 insertions(+), 30 deletions(-) diff --git a/apps/web/lib/features/team-members-block-view.tsx b/apps/web/lib/features/team-members-block-view.tsx index bfe771765..fe3daa636 100644 --- a/apps/web/lib/features/team-members-block-view.tsx +++ b/apps/web/lib/features/team-members-block-view.tsx @@ -30,13 +30,13 @@ const TeamMembersBlockView: React.FC = ({ emptyMessage = t('common.NO_USERS_ONLINE'); break; case 'running': - emptyMessage = 'No users are currently working.'; + emptyMessage = t('common.NO_USERS_WORKING'); break; case 'pause': - emptyMessage = 'No users are paused work at the moment.'; + emptyMessage = t('common.NO_USERS_PAUSED_wORK'); break; case 'idle': - emptyMessage = 'No users are idle right now.'; + emptyMessage = t('common.NO_USERS_IDLE'); break; } diff --git a/apps/web/messages/ar.json b/apps/web/messages/ar.json index 59d7c47e6..1009ff441 100644 --- a/apps/web/messages/ar.json +++ b/apps/web/messages/ar.json @@ -183,7 +183,10 @@ "GITHUB_AUTO_SYNC_LABEL": "اختر تسمية التزامن التلقائي", "GITHUB_INTEGRATION_SUBTITLE_TEXT": "قم بتفعيل تكامل GitHub لمزامنة المشروع والمستودع", "THERE_IS_NO_TASK_ASSIGNED": "لا توجد مهام معينة", - "NO_USERS_ONLINE": "لا يوجد مستخدمين على الانترنت" + "NO_USERS_ONLINE": "لا يوجد مستخدمين على الانترنت", + "NO_USERS_WORKING": "لا يوجد مستخدمين يعملون حاليا", + "NO_USERS_PAUSED_wORK": "لم يتم إيقاف أي مستخدم مؤقتًا عن العمل في الوقت الحالي", + "NO_USERS_IDLE": "لا يوجد مستخدمين خاملين في الوقت الحالي" }, "alerts": { "REAL_TIME_ON_WORKING": "نحن نعمل على المزامنة في الوقت الحقيقي في الوقت الحالي، يرجى التحقق من هذه الميزة لاحقًا", diff --git a/apps/web/messages/bg.json b/apps/web/messages/bg.json index f32f6b5cd..e0456f1f2 100644 --- a/apps/web/messages/bg.json +++ b/apps/web/messages/bg.json @@ -183,7 +183,10 @@ "GITHUB_INTEGRATION_LABEL_SYNC_TASK_TEXT": "Синхронизирайте задачите избирателно, като ги свържете с конкретен етикет.", "GITHUB_AUTO_SYNC_LABEL": "Изберете етикет за автоматична синхронизация", "THERE_IS_NO_TASK_ASSIGNED": "Няма възложени задачи", - "NO_USERS_ONLINE": "Няма потребители онлайн" + "NO_USERS_ONLINE": "Няма потребители онлайн", + "NO_USERS_WORKING":"В момента няма активни потребители", + "NO_USERS_PAUSED_wORK":"В момента няма потребители, които да са спрели работата си", + "NO_USERS_IDLE":"В момента няма неактивни потребители" }, "alerts": { "REAL_TIME_ON_WORKING": "В момента работим върху синхронизирането в реално време, моля, проверете тази функция по-късно.", diff --git a/apps/web/messages/de.json b/apps/web/messages/de.json index b3eebf7d4..105edc0d7 100644 --- a/apps/web/messages/de.json +++ b/apps/web/messages/de.json @@ -183,7 +183,10 @@ "GITHUB_INTEGRATION_LABEL_SYNC_TASK_TEXT": "Synchronisieren Sie Aufgaben selektiv, indem Sie sie mit einem bestimmten Label verknüpfen.", "GITHUB_AUTO_SYNC_LABEL": "Auto-Sync-Label auswählen", "THERE_IS_NO_TASK_ASSIGNED": "Es ist keine Aufgabe zugewiesen", - "NO_USERS_ONLINE": "Es sind keine Benutzer online" + "NO_USERS_ONLINE": "Es sind keine Benutzer online", + "NO_USERS_WORKING": "Derzeit gibt es keine aktiven Benutzer", + "NO_USERS_PAUSED_wORK": "Derzeit gibt es keine Benutzer, die ihre Arbeit eingestellt haben", + "NO_USERS_IDLE": "Derzeit gibt es keine inaktiven Benutzer." }, "alerts": { diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index 4b0fa979e..49397ae05 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -183,7 +183,10 @@ "GITHUB_INTEGRATION_LABEL_SYNC_TASK_TEXT": "Synchronize tasks selectively by associating them with specific label.", "GITHUB_AUTO_SYNC_LABEL": "Select Auto-Sync Label", "THERE_IS_NO_TASK_ASSIGNED": "There is no task assigned", - "NO_USERS_ONLINE": "There are no users online" + "NO_USERS_ONLINE": "There are no users online", + "NO_USERS_WORKING": "There are currently no active users", + "NO_USERS_PAUSED_wORK": "There are currently no users who have paused their work", + "NO_USERS_IDLE": "There are currently no inactive users" }, "alerts": { "REAL_TIME_ON_WORKING": "We are working on Real-Time Sync at the moment, please check on this feature later.", diff --git a/apps/web/messages/es.json b/apps/web/messages/es.json index 22d97aca7..9ba5ade9f 100644 --- a/apps/web/messages/es.json +++ b/apps/web/messages/es.json @@ -183,7 +183,10 @@ "GITHUB_AUTO_SYNC_LABEL": "Seleccionar etiqueta de sincronización automática", "GITHUB_INTEGRATION_SUBTITLE_TEXT": "Activa la integración de GitHub para la sincronización de proyectos y repositorios", "THERE_IS_NO_TASK_ASSIGNED": "No hay tareas asignadas", - "NO_USERS_ONLINE": "No hay usuarios en línea" + "NO_USERS_ONLINE": "No hay usuarios en línea", + "NO_USERS_WORKING": "Actualmente no hay usuarios activos", + "NO_USERS_PAUSED_wORK": "Actualmente no hay usuarios que hayan dejado de trabajar", + "NO_USERS_IDLE": "Actualmente no hay usuarios inactivos" }, "alerts": { "REAL_TIME_ON_WORKING": "Estamos trabajando en la sincronización en tiempo real en este momento; verifique esta función más adelante.", diff --git a/apps/web/messages/fr.json b/apps/web/messages/fr.json index 2c81353e3..21a8c80ae 100644 --- a/apps/web/messages/fr.json +++ b/apps/web/messages/fr.json @@ -183,7 +183,10 @@ "GITHUB_AUTO_SYNC_LABEL": "Sélectionner l'étiquette de synchronisation automatique", "GITHUB_INTEGRATION_SUBTITLE_TEXT": "Activez l'intégration GitHub pour la synchronisation des projets et des dépôts", "THERE_IS_NO_TASK_ASSIGNED": "Aucune tâche n'est assignée", - "NO_USERS_ONLINE": "Aucun utilisateur en ligne" + "NO_USERS_ONLINE": "Aucun utilisateur en ligne", + "NO_USERS_WORKING": "Il n'y a actuellement aucun utilisateur actif", + "NO_USERS_PAUSED_wORK": "Il n'y a actuellement aucun utilisateur qui a mis en pause son travail", + "NO_USERS_IDLE": "Il n'y a actuellement aucun utilisateur inactif" }, "alerts": { "REAL_TIME_ON_WORKING": "Nous travaillons actuellement sur la synchronisation en temps réel, veuillez vérifier cette fonctionnalité plus tard.", diff --git a/apps/web/messages/he.json b/apps/web/messages/he.json index 3a68279a5..04b072e37 100644 --- a/apps/web/messages/he.json +++ b/apps/web/messages/he.json @@ -183,7 +183,10 @@ "GITHUB_AUTO_SYNC_LABEL": "בחר תגית אוטומטית לסנכרון", "GITHUB_INTEGRATION_SUBTITLE_TEXT": "הפעל אינטגרציה של GitHub עבור סנכרון פרויקטים ומאגרים", "THERE_IS_NO_TASK_ASSIGNED": "אין משימות מוקצות", - "NO_USERS_ONLINE": "אין משתמשים מחוברים" + "NO_USERS_ONLINE": "אין משתמשים מחוברים", + "NO_USERS_WORKING": "כרגע אין משתמשים פעילים", + "NO_USERS_PAUSED_wORK": "כרגע אין משתמשים שהפסיקו את עבודתם", + "NO_USERS_IDLE": "כרגע אין משתמשים לא פעילים" }, "alerts": { "REAL_TIME_ON_WORKING": "אנחנו עובדים על סנכרון בזמן אמת כרגע, אנא בדוק את התכונה הזו מאוחר יותר.", diff --git a/apps/web/messages/it.json b/apps/web/messages/it.json index 516d97e27..801b7a504 100644 --- a/apps/web/messages/it.json +++ b/apps/web/messages/it.json @@ -183,7 +183,10 @@ "GITHUB_INTEGRATION_LABEL_SYNC_TASK_TEXT": "Sincronizza le attività in modo selettivo associandole a un'etichetta specifica.", "GITHUB_AUTO_SYNC_LABEL": "Seleziona etichetta di sincronizzazione automatica", "THERE_IS_NO_TASK_ASSIGNED": "Non è stato assegnato alcun compito", - "NO_USERS_ONLINE": "Nessun utente online" + "NO_USERS_ONLINE": "Nessun utente online", + "NO_USERS_WORKING": "Al momento non ci sono utenti attivi", + "NO_USERS_PAUSED_wORK": "Al momento non ci sono utenti che hanno interrotto il proprio lavoro", + "NO_USERS_IDLE": "Al momento non ci sono utenti inattivi" }, "alerts": { "REAL_TIME_ON_WORKING": "Stiamo lavorando alla sincronizzazione in tempo reale al momento, controlla questa funzionalità più tardi.", diff --git a/apps/web/messages/nl.json b/apps/web/messages/nl.json index 46d4af706..c81b404d5 100644 --- a/apps/web/messages/nl.json +++ b/apps/web/messages/nl.json @@ -183,7 +183,10 @@ "GITHUB_INTEGRATION_LABEL_SYNC_TASK_TEXT": "Synchroniseer taken selectief door ze te koppelen aan een specifiek label.", "GITHUB_AUTO_SYNC_LABEL": "Selecteer Auto-Sync-label", "THERE_IS_NO_TASK_ASSIGNED": "Er is geen taak toegewezen", - "NO_USERS_ONLINE": "Geen gebruiker online" + "NO_USERS_ONLINE": "Geen gebruiker online", + "NO_USERS_WORKING": "Er zijn momenteel geen actieve gebruikers", + "NO_USERS_PAUSED_wORK": "Er zijn momenteel geen gebruikers die hun werk hebben stopgezet", + "NO_USERS_IDLE": "Er zijn momenteel geen inactieve gebruikers" }, "alerts": { "REAL_TIME_ON_WORKING": "We werken momenteel aan Real-Time Sync. Bekijk deze functie later opnieuw.", diff --git a/apps/web/messages/pl.json b/apps/web/messages/pl.json index 42ed36052..1a38205d6 100644 --- a/apps/web/messages/pl.json +++ b/apps/web/messages/pl.json @@ -183,7 +183,10 @@ "GITHUB_INTEGRATION_LABEL_SYNC_TASK_TEXT": "Synchronizuj zadania selektywnie, łącząc je z konkretną etykietą.", "GITHUB_AUTO_SYNC_LABEL": "Wybierz etykietę automatycznej synchronizacji", "THERE_IS_NO_TASK_ASSIGNED": "Nie ma przypisanego zadania", - "NO_USERS_ONLINE": "Brak użytkowników online" + "NO_USERS_ONLINE": "Brak użytkowników online", + "NO_USERS_WORKING": "Obecnie nie ma aktywnych użytkowników", + "NO_USERS_PAUSED_wORK": "Obecnie nie ma użytkowników, którzy przerwali pracę", + "NO_USERS_IDLE": "Obecnie nie ma nieaktywnych użytkowników" }, "alerts": { "REAL_TIME_ON_WORKING": "W tej chwili pracujemy nad synchronizacją w czasie rzeczywistym. Sprawdź tę funkcję później.", diff --git a/apps/web/messages/pt.json b/apps/web/messages/pt.json index 8830aa48e..7033337f4 100644 --- a/apps/web/messages/pt.json +++ b/apps/web/messages/pt.json @@ -183,8 +183,10 @@ "GITHUB_INTEGRATION_LABEL_SYNC_TASK_TEXT": "Sincronize tarefas seletivamente associando-as a uma etiqueta específica.", "GITHUB_AUTO_SYNC_LABEL": "Selecionar rótulo de sincronização automática", "THERE_IS_NO_TASK_ASSIGNED": "Não há tarefas atribuídas", - "NO_USERS_ONLINE": "Nenhum usuário online" - + "NO_USERS_ONLINE": "Nenhum usuário online", + "NO_USERS_WORKING": "Atualmente não há usuários ativos", + "NO_USERS_PAUSED_wORK": "Atualmente não há usuários que interromperam seu trabalho", + "NO_USERS_IDLE": "Atualmente não há usuários inativos" }, "alerts": { "REAL_TIME_ON_WORKING": "Estamos trabalhando na sincronização em tempo real no momento. Verifique esse recurso mais tarde.", diff --git a/apps/web/messages/ru.json b/apps/web/messages/ru.json index 5e2591345..b9f120aea 100644 --- a/apps/web/messages/ru.json +++ b/apps/web/messages/ru.json @@ -183,7 +183,10 @@ "GITHUB_INTEGRATION_LABEL_SYNC_TASK_TEXT": "Синхронизация задач выборочно путем ассоциирования их с конкретной меткой.", "GITHUB_AUTO_SYNC_LABEL": "Выберите метку автосинхронизации", "THERE_IS_NO_TASK_ASSIGNED": "НЕТ ЗАДАЧИ НАЗНАЧЕНО", - "NO_USERS_ONLINE": "Нет пользователей онлайн" + "NO_USERS_ONLINE": "Нет пользователей онлайн", + "NO_USERS_WORKING": "На данный момент нет активных пользователей", + "NO_USERS_PAUSED_wORK": "На данный момент нет пользователей, прекративших свою работу", + "NO_USERS_IDLE": "На данный момент неактивных пользователей нет" }, "alerts": { "REAL_TIME_ON_WORKING": "В настоящее время мы работаем над синхронизацией в реальном времени, пожалуйста, проверьте эту функцию позже.", diff --git a/apps/web/messages/zh.json b/apps/web/messages/zh.json index 57d90158f..3444712d3 100644 --- a/apps/web/messages/zh.json +++ b/apps/web/messages/zh.json @@ -183,7 +183,10 @@ "GITHUB_INTEGRATION_LABEL_SYNC_TASK_TEXT": "通过将任务与特定标签关联,有选择地进行同步。", "GITHUB_AUTO_SYNC_LABEL": "选择自动同步标签", "THERE_IS_NO_TASK_ASSIGNED": "没有分配任务", - "NO_USERS_ONLINE": "没有在线用户" + "NO_USERS_ONLINE": "没有在线用户", + "NO_USERS_WORKING": "目前没有活跃用户", + "NO_USERS_PAUSED_wORK": "目前还没有用户停止工作", + "NO_USERS_IDLE": "目前没有不活跃用户" }, "alerts": { "REAL_TIME_ON_WORKING": "我們目前正在開發即時同步功能,請稍後查看此功能。", diff --git a/apps/web/public/locales/ar/common.json b/apps/web/public/locales/ar/common.json index 3070f1388..8eb581749 100644 --- a/apps/web/public/locales/ar/common.json +++ b/apps/web/public/locales/ar/common.json @@ -176,7 +176,10 @@ "GITHUB_INTEGRATION_LABEL_SYNC_TASK_TEXT": "تزامن المهام بشكل انتقائي عن طريق ربطها بتصنيف معين.", "GITHUB_AUTO_SYNC_LABEL": "اختر تسمية التزامن التلقائي", "THERE_IS_NO_TASK_ASSIGNED": "لا توجد مهام معينة", - "NO_USERS_ONLINE": "لا يوجد مستخدمين متصلين" + "NO_USERS_ONLINE": "لا يوجد مستخدمين متصلين", + "NO_USERS_WORKING": "لا يوجد مستخدمين يعملون حاليا", + "NO_USERS_PAUSED_wORK": "لم يتم إيقاف أي مستخدم مؤقتًا عن العمل في الوقت الحالي", + "NO_USERS_IDLE": "لا يوجد مستخدمين خاملين في الوقت الحالي" }, "alerts": { "REAL_TIME_ON_WORKING": "نحن نعمل على المزامنة في الوقت الحقيقي في الوقت الحالي، يرجى التحقق من هذه الميزة لاحقًا.", diff --git a/apps/web/public/locales/bg/common.json b/apps/web/public/locales/bg/common.json index 9469988b6..c37b63060 100644 --- a/apps/web/public/locales/bg/common.json +++ b/apps/web/public/locales/bg/common.json @@ -174,7 +174,10 @@ "GITHUB_INTEGRATION_LABEL_SYNC_TASK_TEXT": "Синхронизирайте задачите избирателно, като ги свържете с конкретен етикет.", "GITHUB_AUTO_SYNC_LABEL": "Изберете етикет за автоматична синхронизация", "THERE_IS_NO_TASK_ASSIGNED": "Няма възложени задачи", - "NO_USERS_ONLINE": "Няма потребители онлайн" + "NO_USERS_ONLINE": "Няма потребители онлайн", + "NO_USERS_WORKING":"В момента няма активни потребители", + "NO_USERS_PAUSED_wORK":"В момента няма потребители, които да са спрели работата си", + "NO_USERS_IDLE":"В момента няма неактивни потребители" }, "alerts": { "REAL_TIME_ON_WORKING": "В момента работим върху синхронизирането в реално време, моля, проверете тази функция по-късно.", diff --git a/apps/web/public/locales/de/common.json b/apps/web/public/locales/de/common.json index 255187e43..c9376d5ba 100644 --- a/apps/web/public/locales/de/common.json +++ b/apps/web/public/locales/de/common.json @@ -176,7 +176,10 @@ "GITHUB_INTEGRATION_LABEL_SYNC_TASK_TEXT": "Synchronisieren Sie Aufgaben selektiv, indem Sie sie mit einem bestimmten Label verknüpfen.", "GITHUB_AUTO_SYNC_LABEL": "Auto-Sync-Label auswählen", "THERE_IS_NO_TASK_ASSIGNED": "Es ist keine Aufgabe zugewiesen", - "NO_USERS_ONLINE": "Es sind keine Benutzer online" + "NO_USERS_ONLINE": "Es sind keine Benutzer online", + "NO_USERS_WORKING": "Derzeit gibt es keine aktiven Benutzer", + "NO_USERS_PAUSED_wORK": "Derzeit gibt es keine Benutzer, die ihre Arbeit eingestellt haben", + "NO_USERS_IDLE": "Derzeit gibt es keine inaktiven Benutzer" }, "alerts": { "REAL_TIME_ON_WORKING": "Wir arbeiten derzeit an der Echtzeitsynchronisierung. Bitte überprüfen Sie diese Funktion später.", diff --git a/apps/web/public/locales/en/common.json b/apps/web/public/locales/en/common.json index 26a28674a..d8702c80b 100644 --- a/apps/web/public/locales/en/common.json +++ b/apps/web/public/locales/en/common.json @@ -176,7 +176,10 @@ "GITHUB_INTEGRATION_LABEL_SYNC_TASK_TEXT": "Synchronize tasks selectively by associating them with specific label.", "GITHUB_AUTO_SYNC_LABEL": "Select Auto-Sync Label", "THERE_IS_NO_TASK_ASSIGNED": "There is no task assigned", - "NO_USERS_ONLINE": "There are no users online" + "NO_USERS_ONLINE": "There are no users online", + "NO_USERS_WORKING": "There are currently no active users", + "NO_USERS_PAUSED_wORK": "There are currently no users who have paused their work", + "NO_USERS_IDLE": "There are currently no inactive users" }, "alerts": { "REAL_TIME_ON_WORKING": "We are working on Real-Time Sync at the moment, please check on this feature later.", diff --git a/apps/web/public/locales/es/common.json b/apps/web/public/locales/es/common.json index 5cf539159..cb5c90870 100644 --- a/apps/web/public/locales/es/common.json +++ b/apps/web/public/locales/es/common.json @@ -173,7 +173,10 @@ "GITHUB_INTEGRATION_LABEL_SYNC_TASK_TEXT": "Sincronice tareas de manera selectiva asociándolas con una etiqueta específica.", "GITHUB_AUTO_SYNC_LABEL": "Seleccionar etiqueta de sincronización automática", "THERE_IS_NO_TASK_ASSIGNED": "No hay tareas asignadas", - "NO_USERS_ONLINE": "No hay usuarios en línea" + "NO_USERS_ONLINE": "No hay usuarios en línea", + "NO_USERS_WORKING": "Actualmente no hay usuarios activos", + "NO_USERS_PAUSED_wORK": "Actualmente no hay usuarios que hayan dejado de trabajar", + "NO_USERS_IDLE": "Actualmente no hay usuarios inactivos" }, "alerts": { "REAL_TIME_ON_WORKING": "Estamos trabajando en la sincronización en tiempo real en este momento; verifique esta función más adelante.", diff --git a/apps/web/public/locales/fr/common.json b/apps/web/public/locales/fr/common.json index 9ee1aeec2..3c547273f 100644 --- a/apps/web/public/locales/fr/common.json +++ b/apps/web/public/locales/fr/common.json @@ -174,7 +174,10 @@ "GITHUB_INTEGRATION_LABEL_SYNC_TASK_TEXT": "Synchronisez sélectivement les tâches en les associant à une étiquette spécifique.", "GITHUB_AUTO_SYNC_LABEL": "Sélectionner l'étiquette de synchronisation automatique", "THERE_IS_NO_TASK_ASSIGNED": "Il n'y a pas de tâche assignée", - "NO_USERS_ONLINE": "Aucun utilisateur en ligne" + "NO_USERS_ONLINE": "Aucun utilisateur en ligne", + "NO_USERS_WORKING": "Il n'y a actuellement aucun utilisateur actif", + "NO_USERS_PAUSED_wORK": "Il n'y a actuellement aucun utilisateur qui a mis en pause son travail", + "NO_USERS_IDLE": "Il n'y a actuellement aucun utilisateur inactif" }, "alerts": { "REAL_TIME_ON_WORKING": "Nous travaillons actuellement sur la synchronisation en temps réel, veuillez vérifier cette fonctionnalité plus tard.", diff --git a/apps/web/public/locales/he/common.json b/apps/web/public/locales/he/common.json index 638924063..2da2ae640 100644 --- a/apps/web/public/locales/he/common.json +++ b/apps/web/public/locales/he/common.json @@ -176,7 +176,10 @@ "GITHUB_INTEGRATION_LABEL_SYNC_TASK_TEXT": "סנכרן משימות באופן בררני על ידי הקשרתן לתג מסוים.", "GITHUB_AUTO_SYNC_LABEL": "בחר תגית אוטומטית לסנכרון", "THERE_IS_NO_TASK_ASSIGNED": "אין משימות מוקצות", - "NO_USERS_ONLINE": "אין משתמשים מחוברים" + "NO_USERS_ONLINE": "אין משתמשים מחוברים", + "NO_USERS_WORKING": "כרגע אין משתמשים פעילים", + "NO_USERS_PAUSED_wORK": "כרגע אין משתמשים שהפסיקו את עבודתם", + "NO_USERS_IDLE": "כרגע אין משתמשים לא פעילים" }, "alerts": { "REAL_TIME_ON_WORKING": "אנחנו עובדים על סנכרון בזמן אמת כרגע, אנא בדוק את התכונה הזו מאוחר יותר.", diff --git a/apps/web/public/locales/it/common.json b/apps/web/public/locales/it/common.json index eda01700a..7eeb4add4 100644 --- a/apps/web/public/locales/it/common.json +++ b/apps/web/public/locales/it/common.json @@ -178,7 +178,10 @@ "GITHUB_INTEGRATION_LABEL_SYNC_TASK_TEXT": "Sincronizza le attività in modo selettivo associandole a un'etichetta specifica.", "GITHUB_AUTO_SYNC_LABEL": "Seleziona etichetta di sincronizzazione automatica", "THERE_IS_NO_TASK_ASSIGNED": "Non è stato assegnato alcun compito", - "NO_USERS_ONLINE": "Nessun utente online" + "NO_USERS_ONLINE": "Nessun utente online", + "NO_USERS_WORKING": "Al momento non ci sono utenti attivi", + "NO_USERS_PAUSED_wORK": "Al momento non ci sono utenti che hanno interrotto il proprio lavoro", + "NO_USERS_IDLE": "Al momento non ci sono utenti inattivi" }, "alerts": { "REAL_TIME_ON_WORKING": "Stiamo lavorando alla sincronizzazione in tempo reale al momento, controlla questa funzionalità più tardi.", diff --git a/apps/web/public/locales/nl/common.json b/apps/web/public/locales/nl/common.json index 95f13db7f..31394f096 100644 --- a/apps/web/public/locales/nl/common.json +++ b/apps/web/public/locales/nl/common.json @@ -176,7 +176,10 @@ "GITHUB_INTEGRATION_LABEL_SYNC_TASK_TEXT": "Synchroniseer taken selectief door ze te koppelen aan een specifiek label.", "GITHUB_AUTO_SYNC_LABEL": "Selecteer Auto-Sync-label", "THERE_IS_NO_TASK_ASSIGNED": "Er is geen taak toegewezen", - "NO_USERS_ONLINE": "Er zijn geen gebruikers online" + "NO_USERS_ONLINE": "Er zijn geen gebruikers online", + "NO_USERS_WORKING": "Er zijn momenteel geen actieve gebruikers", + "NO_USERS_PAUSED_wORK": "Er zijn momenteel geen gebruikers die hun werk hebben stopgezet", + "NO_USERS_IDLE": "Er zijn momenteel geen inactieve gebruikers" }, "alerts": { "REAL_TIME_ON_WORKING": "We werken momenteel aan Real-Time Sync. Bekijk deze functie later opnieuw.", diff --git a/apps/web/public/locales/pl/common.json b/apps/web/public/locales/pl/common.json index 5c828065f..a0cbd46df 100644 --- a/apps/web/public/locales/pl/common.json +++ b/apps/web/public/locales/pl/common.json @@ -178,7 +178,10 @@ "GITHUB_INTEGRATION_LABEL_SYNC_TASK_TEXT": "Synchronizuj zadania selektywnie, łącząc je z konkretną etykietą.", "GITHUB_AUTO_SYNC_LABEL": "Wybierz etykietę automatycznej synchronizacji", "THERE_IS_NO_TASK_ASSIGNED": "Nie ma przypisanego zadania", - "NO_USERS_ONLINE": "Brak użytkowników online" + "NO_USERS_ONLINE": "Brak użytkowników online", + "NO_USERS_WORKING": "Obecnie nie ma aktywnych użytkowników", + "NO_USERS_PAUSED_wORK": "Obecnie nie ma użytkowników, którzy przerwali pracę", + "NO_USERS_IDLE": "Obecnie nie ma nieaktywnych użytkowników" }, "alerts": { "REAL_TIME_ON_WORKING": "W tej chwili pracujemy nad synchronizacją w czasie rzeczywistym. Sprawdź tę funkcję później.", diff --git a/apps/web/public/locales/pt/common.json b/apps/web/public/locales/pt/common.json index a2e2d144c..23fd721b5 100644 --- a/apps/web/public/locales/pt/common.json +++ b/apps/web/public/locales/pt/common.json @@ -178,7 +178,10 @@ "GITHUB_INTEGRATION_LABEL_SYNC_TASK_TEXT": "Sincronize tarefas seletivamente associando-as a uma etiqueta específica.", "GITHUB_AUTO_SYNC_LABEL": "Selecionar rótulo de sincronização automática", "THERE_IS_NO_TASK_ASSIGNED": "Não há tarefa atribuída", - "NO_USERS_ONLINE": "Não há usuários online" + "NO_USERS_ONLINE": "Não há usuários online", + "NO_USERS_WORKING": "Atualmente não há usuários ativos", + "NO_USERS_PAUSED_wORK": "Atualmente não há usuários que interromperam seu trabalho", + "NO_USERS_IDLE": "Atualmente não há usuários inativos" }, "alerts": { "REAL_TIME_ON_WORKING": "Estamos trabalhando na sincronização em tempo real no momento. Verifique esse recurso mais tarde.", diff --git a/apps/web/public/locales/ru/common.json b/apps/web/public/locales/ru/common.json index d4b0949ee..ad85f7602 100644 --- a/apps/web/public/locales/ru/common.json +++ b/apps/web/public/locales/ru/common.json @@ -177,7 +177,10 @@ "GITHUB_INTEGRATION_LABEL_SYNC_TASK_TEXT": "Синхронизация задач выборочно путем ассоциирования их с конкретной меткой.", "GITHUB_AUTO_SYNC_LABEL": "Выберите метку автосинхронизации", "THERE_IS_NO_TASK_ASSIGNED": "НЕТ ЗАДАЧИ НАЗНАЧЕНО", - "NO_USERS_ONLINE": "Пользователей онлайн нет" + "NO_USERS_ONLINE": "Пользователей онлайн нет", + "NO_USERS_WORKING": "На данный момент нет активных пользователей", + "NO_USERS_PAUSED_wORK": "На данный момент нет пользователей, прекративших свою работу", + "NO_USERS_IDLE": "На данный момент неактивных пользователей нет" }, "alerts": { "REAL_TIME_ON_WORKING": "В настоящее время мы работаем над синхронизацией в реальном времени, пожалуйста, проверьте эту функцию позже.", diff --git a/apps/web/public/locales/zh/common.json b/apps/web/public/locales/zh/common.json index 19ad537bc..aa0095067 100644 --- a/apps/web/public/locales/zh/common.json +++ b/apps/web/public/locales/zh/common.json @@ -176,7 +176,10 @@ "GITHUB_INTEGRATION_LABEL_SYNC_TASK_TEXT": "通过将任务与特定标签关联,有选择地进行同步。", "GITHUB_AUTO_SYNC_LABEL": "选择自动同步标签", "THERE_IS_NO_TASK_ASSIGNED": "没有分配任务", - "NO_USERS_ONLINE": "没有在线用户" + "NO_USERS_ONLINE": "没有在线用户", + "NO_USERS_WORKING": "目前没有活跃用户", + "NO_USERS_PAUSED_wORK": "目前还没有用户停止工作", + "NO_USERS_IDLE": "目前没有不活跃用户" }, "alerts": { "REAL_TIME_ON_WORKING": "我們目前正在開發即時同步功能,請稍後查看此功能。", From 7274aa3485c45355a1f65c2350fb0e261ca6cf0b Mon Sep 17 00:00:00 2001 From: GloireMutaliko21 Date: Tue, 30 Apr 2024 22:10:08 +0200 Subject: [PATCH 03/21] style: add plan buttons to assign menus --- apps/web/.env | 4 +- apps/web/app/interfaces/IDailyPlan.ts | 0 apps/web/lib/features/index.ts | 1 + apps/web/lib/features/task/task-card.tsx | 50 ++++++++++++++++++-- apps/web/lib/features/user-profile-plans.tsx | 18 +++++++ apps/web/lib/features/user-profile-tasks.tsx | 47 ++++++++++-------- 6 files changed, 93 insertions(+), 27 deletions(-) create mode 100644 apps/web/app/interfaces/IDailyPlan.ts create mode 100644 apps/web/lib/features/user-profile-plans.tsx diff --git a/apps/web/.env b/apps/web/.env index 2fe6875eb..038572acc 100644 --- a/apps/web/.env +++ b/apps/web/.env @@ -1,7 +1,7 @@ RECOIL_DUPLICATE_ATOM_KEY_CHECKING_ENABLED=false -GAUZY_API_SERVER_URL=https://api.ever.team # http://localhost:3000 -NEXT_PUBLIC_GAUZY_API_SERVER_URL=https://api.ever.team # http://localhost:3000 +GAUZY_API_SERVER_URL=http://localhost:3000 # https://api.ever.team +NEXT_PUBLIC_GAUZY_API_SERVER_URL=http://localhost:3000 # https://api.ever.team NEXT_PUBLIC_GA_MEASUREMENT_ID= # CAPTCHA Settings diff --git a/apps/web/app/interfaces/IDailyPlan.ts b/apps/web/app/interfaces/IDailyPlan.ts new file mode 100644 index 000000000..e69de29bb diff --git a/apps/web/lib/features/index.ts b/apps/web/lib/features/index.ts index 5fc67fb4d..688b0f985 100644 --- a/apps/web/lib/features/index.ts +++ b/apps/web/lib/features/index.ts @@ -29,6 +29,7 @@ export * from './team/user-team-card/task-skeleton'; export * from './auth-user-task-input'; export * from './user-nav-menu'; +export * from './user-profile-plans'; export * from './user-profile-tasks'; // custom exports diff --git a/apps/web/lib/features/task/task-card.tsx b/apps/web/lib/features/task/task-card.tsx index 73087c029..fc072ac20 100644 --- a/apps/web/lib/features/task/task-card.tsx +++ b/apps/web/lib/features/task/task-card.tsx @@ -18,6 +18,7 @@ import { clsxm } from '@app/utils'; import { Popover, Transition } from '@headlessui/react'; import { Card, + Divider, // ConfirmDropdown, SpinnerLoader, Text, @@ -43,7 +44,7 @@ type Props = { task?: Nullable; isAuthUser: boolean; activeAuthTask: boolean; - viewType?: 'default' | 'unassign'; + viewType?: 'default' | 'unassign' | 'dailyplan'; profile?: I_UserProfilePage; editTaskId?: string | null; setEditTaskId?: SetterOrUpdater; @@ -421,7 +422,7 @@ function TaskCardMenu({ task: ITeamTask; loading?: boolean; memberInfo?: I_TeamMemberCardHook; - viewType: 'default' | 'unassign'; + viewType: 'default' | 'unassign' | 'dailyplan'; }) { const t = useTranslations(); const handleAssignment = useCallback(() => { @@ -451,7 +452,7 @@ function TaskCardMenu({ {() => { return ( - +
  • -
  • +
  • + {viewType == 'default' && ( + <> + +
    +
  • + + Plan for today + +
  • +
  • + + Plan for tomorrow + +
  • +
  • + + Plan for some day + +
  • +
    + + )} + {/*
  • +
      +
    • + {/* */} +
    • +
    +
+ ); +} diff --git a/apps/web/lib/features/user-profile-tasks.tsx b/apps/web/lib/features/user-profile-tasks.tsx index 623afdc3e..ab5a17eb0 100644 --- a/apps/web/lib/features/user-profile-tasks.tsx +++ b/apps/web/lib/features/user-profile-tasks.tsx @@ -1,5 +1,6 @@ import { I_UserProfilePage, useLiveTimerStatus } from '@app/hooks'; import { Divider, Text } from 'lib/components'; +import { UserProfilePlans } from 'lib/features'; import { TaskCard } from './task/task-card'; import { I_TaskFilter } from './task/task-filters'; import { useTranslations } from 'next-intl'; @@ -71,6 +72,8 @@ export function UserProfileTask({ profile, tabFiltered }: Props) { /> )} + {tabFiltered.tab === 'dailyplan' && } + {tabFiltered.tab === 'worked' && otherTasks.length > 0 && (
@@ -80,27 +83,29 @@ export function UserProfileTask({ profile, tabFiltered }: Props) {
)} - + {!(tabFiltered.tab === 'dailyplan') && ( + + )} ); } From 25beb237ab50869860a3c4afec40514a354c59d7 Mon Sep 17 00:00:00 2001 From: GloireMutaliko21 Date: Tue, 30 Apr 2024 22:54:05 +0200 Subject: [PATCH 04/21] feat: init create daily plan service --- apps/web/app/api/daily-plan/route.ts | 17 ++++++++++ apps/web/app/interfaces/IDailyPlan.ts | 31 +++++++++++++++++++ .../services/server/requests/daily-plan.ts | 11 +++++++ 3 files changed, 59 insertions(+) create mode 100644 apps/web/app/api/daily-plan/route.ts create mode 100644 apps/web/app/services/server/requests/daily-plan.ts diff --git a/apps/web/app/api/daily-plan/route.ts b/apps/web/app/api/daily-plan/route.ts new file mode 100644 index 000000000..dfdce165d --- /dev/null +++ b/apps/web/app/api/daily-plan/route.ts @@ -0,0 +1,17 @@ +import { NextResponse } from 'next/server'; +import { authenticatedGuard } from '@app/services/server/guards/authenticated-guard-app'; +import { ICreateDailyPlan } from '@app/interfaces/IDailyPlan'; +import { createPlanRequest } from '@app/services/server/requests/daily-plan'; + +export async function POST(req: Request) { + const res = new NextResponse(); + const { $res, user, access_token } = await authenticatedGuard(req, res); + + if (!user) return $res('Unauthorized'); + + const body = (await req.json()) as unknown as ICreateDailyPlan; + + const response = await createPlanRequest({ data: body, bearer_token: access_token }); + + return $res(response.data); +} diff --git a/apps/web/app/interfaces/IDailyPlan.ts b/apps/web/app/interfaces/IDailyPlan.ts index e69de29bb..250c5af87 100644 --- a/apps/web/app/interfaces/IDailyPlan.ts +++ b/apps/web/app/interfaces/IDailyPlan.ts @@ -0,0 +1,31 @@ +import { IEmployee } from './IEmployee'; +import { IOrganization } from './IOrganization'; +import { ITeamTask } from './ITask'; + +export type IDailyPlan = { + id: string; + createdAt: string; + updatedAt: string; + date: Date; + workTimePlanned: number; + status: DailyPlanStatusEnum; + employee?: IEmployee; + employeeId?: IEmployee['id']; + organizationId?: IOrganization['id']; + organization?: IOrganization; + tasks?: ITeamTask[]; +}; + +export interface ICreateDailyPlan { + date: Date; + workTimePlanned: number; + status: DailyPlanStatusEnum; + employeeId?: IEmployee['id']; + taskId?: ITeamTask['id']; +} + +export declare enum DailyPlanStatusEnum { + OPEN = 'open', + IN_PROGRESS = 'in-progress', + COMPLETED = 'completed' +} diff --git a/apps/web/app/services/server/requests/daily-plan.ts b/apps/web/app/services/server/requests/daily-plan.ts new file mode 100644 index 000000000..e7abbba99 --- /dev/null +++ b/apps/web/app/services/server/requests/daily-plan.ts @@ -0,0 +1,11 @@ +import { ICreateDailyPlan, IDailyPlan } from '@app/interfaces/IDailyPlan'; +import { serverFetch } from '../fetch'; + +export function createPlanRequest({ data, bearer_token }: { data: ICreateDailyPlan; bearer_token: string }) { + return serverFetch({ + method: 'POST', + path: '/daily-plan', + body: data, + bearer_token + }); +} From af5b3a57a0c6b84e11c533b21a038a3eeabe6e34 Mon Sep 17 00:00:00 2001 From: GloireMutaliko21 Date: Wed, 1 May 2024 07:42:39 +0200 Subject: [PATCH 05/21] feat: add create Daily Plan request handler --- apps/web/app/api/daily-plan/route.ts | 4 +- apps/web/app/hooks/features/useDailyPlan.ts | 42 +++++++++++++++++++ apps/web/app/interfaces/IDailyPlan.ts | 2 + apps/web/app/interfaces/index.ts | 1 + .../web/app/services/client/api/daily-plan.ts | 8 ++++ apps/web/app/services/client/api/index.ts | 1 + .../services/server/requests/daily-plan.ts | 13 +++++- apps/web/app/stores/daily-plan.ts | 26 ++++++++++++ apps/web/app/stores/index.ts | 1 + 9 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 apps/web/app/hooks/features/useDailyPlan.ts create mode 100644 apps/web/app/services/client/api/daily-plan.ts create mode 100644 apps/web/app/stores/daily-plan.ts diff --git a/apps/web/app/api/daily-plan/route.ts b/apps/web/app/api/daily-plan/route.ts index dfdce165d..d4d96c1ed 100644 --- a/apps/web/app/api/daily-plan/route.ts +++ b/apps/web/app/api/daily-plan/route.ts @@ -5,13 +5,13 @@ import { createPlanRequest } from '@app/services/server/requests/daily-plan'; export async function POST(req: Request) { const res = new NextResponse(); - const { $res, user, access_token } = await authenticatedGuard(req, res); + const { $res, user, access_token: bearer_token, tenantId } = await authenticatedGuard(req, res); if (!user) return $res('Unauthorized'); const body = (await req.json()) as unknown as ICreateDailyPlan; - const response = await createPlanRequest({ data: body, bearer_token: access_token }); + const response = await createPlanRequest({ data: body, bearer_token, tenantId }); return $res(response.data); } diff --git a/apps/web/app/hooks/features/useDailyPlan.ts b/apps/web/app/hooks/features/useDailyPlan.ts new file mode 100644 index 000000000..d25b2340e --- /dev/null +++ b/apps/web/app/hooks/features/useDailyPlan.ts @@ -0,0 +1,42 @@ +'use client'; + +import { useRecoilState } from 'recoil'; +import { useCallback, useEffect } from 'react'; +import { useQuery } from '../useQuery'; +import { dailyPlanFetchingState, dailyPlanListState, userState } from '@app/stores'; +import { createDailyPlanAPI } from '@app/services/client/api'; +import { ICreateDailyPlan } from '@app/interfaces'; +import { useFirstLoad } from '../useFirstLoad'; + +export function useDailyPlan() { + const [user] = useRecoilState(userState); + + const { loading: createDailyPlanLoading, queryCall: createQueryCall } = useQuery(createDailyPlanAPI); + + const [dailyPlan, setDailyPlan] = useRecoilState(dailyPlanListState); + const [dailyPlanFetching, setDailyPlanFetching] = useRecoilState(dailyPlanFetchingState); + const { firstLoadData: firstLoadDailyPlanData, firstLoad } = useFirstLoad(); + + useEffect(() => { + if (firstLoad) { + setDailyPlanFetching(createDailyPlanLoading); // Change this after provided getDailyPlan handlers + } + }, [createDailyPlanLoading, firstLoad, setDailyPlanFetching]); // Update loading var after provided getDailyPlan handlers + + const createDailyPlan = useCallback( + async (data: ICreateDailyPlan) => { + const res = await createQueryCall(data, user?.tenantId || ''); + return res; + }, + [createQueryCall, user] + ); + + return { + dailyPlan, + setDailyPlan, + dailyPlanFetching, + firstLoadDailyPlanData, + createDailyPlan, + createDailyPlanLoading + }; +} diff --git a/apps/web/app/interfaces/IDailyPlan.ts b/apps/web/app/interfaces/IDailyPlan.ts index 250c5af87..d598de283 100644 --- a/apps/web/app/interfaces/IDailyPlan.ts +++ b/apps/web/app/interfaces/IDailyPlan.ts @@ -22,6 +22,8 @@ export interface ICreateDailyPlan { status: DailyPlanStatusEnum; employeeId?: IEmployee['id']; taskId?: ITeamTask['id']; + organizationId: string; + tenantId: string; } export declare enum DailyPlanStatusEnum { diff --git a/apps/web/app/interfaces/index.ts b/apps/web/app/interfaces/index.ts index f6ba725be..187fbd13a 100644 --- a/apps/web/app/interfaces/index.ts +++ b/apps/web/app/interfaces/index.ts @@ -16,6 +16,7 @@ export * from './ITaskSizes'; export * from './ITaskTimesheet'; export * from './ITaskLabels'; export * from './ITaskRelatedIssueType'; +export * from './IDailyPlan'; export * from './IColor'; export * from './hooks'; export * from './IIcon'; diff --git a/apps/web/app/services/client/api/daily-plan.ts b/apps/web/app/services/client/api/daily-plan.ts new file mode 100644 index 000000000..a849ad939 --- /dev/null +++ b/apps/web/app/services/client/api/daily-plan.ts @@ -0,0 +1,8 @@ +import { ICreateDailyPlan } from '@app/interfaces/IDailyPlan'; +import { post } from '../axios'; + +export function createDailyPlanAPI(data: ICreateDailyPlan, tenantId?: string) { + return post('/daily-plan', data, { + tenantId + }); +} diff --git a/apps/web/app/services/client/api/index.ts b/apps/web/app/services/client/api/index.ts index 7b8f36e10..a3fc188f9 100644 --- a/apps/web/app/services/client/api/index.ts +++ b/apps/web/app/services/client/api/index.ts @@ -14,6 +14,7 @@ export * from './task-sizes'; export * from './task-labels'; export * from './issue-type'; export * from './task-related-issue-type'; +export * from './daily-plan'; export * from './user'; export * from './request-to-join-team'; diff --git a/apps/web/app/services/server/requests/daily-plan.ts b/apps/web/app/services/server/requests/daily-plan.ts index e7abbba99..b30fd5e19 100644 --- a/apps/web/app/services/server/requests/daily-plan.ts +++ b/apps/web/app/services/server/requests/daily-plan.ts @@ -1,11 +1,20 @@ import { ICreateDailyPlan, IDailyPlan } from '@app/interfaces/IDailyPlan'; import { serverFetch } from '../fetch'; -export function createPlanRequest({ data, bearer_token }: { data: ICreateDailyPlan; bearer_token: string }) { +export function createPlanRequest({ + data, + bearer_token, + tenantId +}: { + data: ICreateDailyPlan; + bearer_token: string; + tenantId: string; +}) { return serverFetch({ method: 'POST', path: '/daily-plan', body: data, - bearer_token + bearer_token, + tenantId }); } diff --git a/apps/web/app/stores/daily-plan.ts b/apps/web/app/stores/daily-plan.ts new file mode 100644 index 000000000..540c31528 --- /dev/null +++ b/apps/web/app/stores/daily-plan.ts @@ -0,0 +1,26 @@ +import { atom, selector } from 'recoil'; +import { IDailyPlan } from '@app/interfaces/IDailyPlan'; + +export const dailyPlanListState = atom({ + key: 'dailyPlanListState', + default: [] +}); + +export const activeDailyPlanIdState = atom({ + key: 'activeDailyPlanIdService', + default: null +}); + +export const dailyPlanFetchingState = atom({ + key: 'dailyPlanFetchingState', + default: false +}); + +export const activeDailyPlanState = selector({ + key: 'activeDailyPlanState', + get: ({ get }) => { + const dailyPlans = get(dailyPlanListState); + const activeId = get(activeDailyPlanIdState); + return dailyPlans.find((plan) => plan.id === activeId) || dailyPlans[0] || null; + } +}); diff --git a/apps/web/app/stores/index.ts b/apps/web/app/stores/index.ts index 02fab4487..35f126481 100644 --- a/apps/web/app/stores/index.ts +++ b/apps/web/app/stores/index.ts @@ -16,6 +16,7 @@ export * from './task-sizes'; export * from './task-labels'; export * from './issue-type'; export * from './task-related-issue-type'; +export * from './daily-plan'; export * from './roles'; export * from './role-permissions'; From 86926e06dee74b0575058e41446435e64da3d285 Mon Sep 17 00:00:00 2001 From: GloireMutaliko21 Date: Wed, 1 May 2024 12:03:39 +0200 Subject: [PATCH 06/21] feat: create day plan --- apps/web/app/helpers/validations.ts | 2 +- .../app/hooks/auth/useAuthenticationTeam.ts | 1 + apps/web/app/hooks/index.ts | 3 + apps/web/app/interfaces/IDailyPlan.ts | 8 +- .../create-daily-plan-form-modal.tsx | 90 +++++++++++++++++++ apps/web/lib/features/task/task-card.tsx | 55 ++++++------ 6 files changed, 127 insertions(+), 32 deletions(-) create mode 100644 apps/web/lib/features/daily-plan/create-daily-plan-form-modal.tsx diff --git a/apps/web/app/helpers/validations.ts b/apps/web/app/helpers/validations.ts index d0db0fa89..f5a30caea 100644 --- a/apps/web/app/helpers/validations.ts +++ b/apps/web/app/helpers/validations.ts @@ -24,7 +24,7 @@ export const authFormValidate = (keys: (keyof IRegisterDataAPI)[], values: IRegi } break; case 'recaptcha': - if (RECAPTCHA_SITE_KEY) { + if (RECAPTCHA_SITE_KEY.value) { if (!values['recaptcha'] || values['recaptcha'].trim().length < 2) { err['recaptcha'] = 'Please check the ReCaptcha checkbox before continue'; } diff --git a/apps/web/app/hooks/auth/useAuthenticationTeam.ts b/apps/web/app/hooks/auth/useAuthenticationTeam.ts index d43ace7dc..72d017aa5 100644 --- a/apps/web/app/hooks/auth/useAuthenticationTeam.ts +++ b/apps/web/app/hooks/auth/useAuthenticationTeam.ts @@ -72,6 +72,7 @@ export function useAuthenticationTeam() { const { errors, valid } = authFormValidate(validationFields, formValues); if (!valid) { + console.log({ errors }); setErrors(errors as any); return; } diff --git a/apps/web/app/hooks/index.ts b/apps/web/app/hooks/index.ts index 1ca8c9f67..9083d2b8d 100644 --- a/apps/web/app/hooks/index.ts +++ b/apps/web/app/hooks/index.ts @@ -59,6 +59,9 @@ export * from './features/useTaskSizes'; export * from './features/useTaskStatus'; export * from './features/useTaskVersion'; +// Daily plam +export * from './features/useDailyPlan'; + export * from './features/useRefetchData'; export * from './features/useRolePermissions'; diff --git a/apps/web/app/interfaces/IDailyPlan.ts b/apps/web/app/interfaces/IDailyPlan.ts index d598de283..4e882b084 100644 --- a/apps/web/app/interfaces/IDailyPlan.ts +++ b/apps/web/app/interfaces/IDailyPlan.ts @@ -22,12 +22,14 @@ export interface ICreateDailyPlan { status: DailyPlanStatusEnum; employeeId?: IEmployee['id']; taskId?: ITeamTask['id']; - organizationId: string; - tenantId: string; + organizationId?: string; + tenantId?: string | null; } -export declare enum DailyPlanStatusEnum { +export enum DailyPlanStatusEnum { OPEN = 'open', IN_PROGRESS = 'in-progress', COMPLETED = 'completed' } + +export type IDailyPlanMode = 'today' | 'tomorow' | 'custom'; diff --git a/apps/web/lib/features/daily-plan/create-daily-plan-form-modal.tsx b/apps/web/lib/features/daily-plan/create-daily-plan-form-modal.tsx new file mode 100644 index 000000000..23b36833b --- /dev/null +++ b/apps/web/lib/features/daily-plan/create-daily-plan-form-modal.tsx @@ -0,0 +1,90 @@ +import { useCallback } from 'react'; +import { useForm } from 'react-hook-form'; +import { useRecoilState } from 'recoil'; +import { DailyPlanStatusEnum, IDailyPlanMode } from '@app/interfaces'; +import { useDailyPlan, useRefetchData } from '@app/hooks'; +import { userState } from '@app/stores'; +import { Button, Card, InputField, Modal, Text } from 'lib/components'; + +export function CreateDailyPlanFormModal({ + open, + closeModal, + taskId, + planMode +}: { + open: boolean; + closeModal: () => void; + taskId: string; + planMode: IDailyPlanMode; +}) { + const [user] = useRecoilState(userState); + const { handleSubmit, reset, register } = useForm(); + const { createDailyPlan, createDailyPlanLoading } = useDailyPlan(); + const { refetch } = useRefetchData(); + + const onSubmit = useCallback( + async (values: any) => { + const toDay = new Date(); + createDailyPlan({ + workTimePlanned: values.workTimePlanned, + taskId, + date: planMode == 'today' ? toDay : new Date(toDay.getDate() + 1), + status: DailyPlanStatusEnum.OPEN, + tenantId: user?.tenantId, + employeeId: user?.employee.id, + organizationId: user?.employee.organizationId + }).then(() => { + refetch(); + reset(); + }); + }, + [ + createDailyPlan, + taskId, + planMode, + user?.tenantId, + user?.employee.id, + user?.employee.organizationId, + refetch, + reset + ] + ); + return ( + +
+ +
+ {/* Form header */} +
+ + CREATE DAILY PLAN + + + You are creating a new plan +
+ + {/* Form Fields */} +
+ + +
+
+
+
+
+ ); +} diff --git a/apps/web/lib/features/task/task-card.tsx b/apps/web/lib/features/task/task-card.tsx index fc072ac20..d4ff734e3 100644 --- a/apps/web/lib/features/task/task-card.tsx +++ b/apps/web/lib/features/task/task-card.tsx @@ -4,6 +4,7 @@ import { secondsToTime } from '@app/helpers'; import { I_TeamMemberCardHook, I_UserProfilePage, + useModal, useOrganizationEmployeeTeams, useOrganizationTeams, useTMCardTaskEdit, @@ -12,7 +13,7 @@ import { useTeamTasks, useTimerView } from '@app/hooks'; -import { IClassName, IOrganizationTeamList, ITeamTask, Nullable, OT_Member } from '@app/interfaces'; +import { IClassName, IDailyPlanMode, IOrganizationTeamList, ITeamTask, Nullable, OT_Member } from '@app/interfaces'; import { timerSecondsState } from '@app/stores'; import { clsxm } from '@app/utils'; import { Popover, Transition } from '@headlessui/react'; @@ -38,6 +39,7 @@ import { ActiveTaskStatusDropdown } from './task-status'; import { TaskTimes } from './task-times'; import { useTranslations } from 'next-intl'; import { SixSquareGridIcon, ThreeCircleOutlineVerticalIcon } from 'assets/svg'; +import { CreateDailyPlanFormModal } from '../daily-plan/create-daily-plan-form-modal'; type Props = { active?: boolean; @@ -484,37 +486,13 @@ function TaskCardMenu({
  • - - Plan for today - +
  • - - Plan for tomorrow - +
  • - - Plan for some day - +
  • @@ -546,3 +524,24 @@ function TaskCardMenu({ ); } + +function PlanTask({ planMode, taskId }: { taskId: string; planMode: IDailyPlanMode }) { + const { closeModal, isOpen, openModal } = useModal(); + + return ( + <> + + + {planMode === 'today' && 'Plan for today'} + {planMode === 'tomorow' && 'Plan for tomorow'} + {planMode === 'custom' && 'Plan for some day'} + + + ); +} From b6cba53b3a6db62400ec3110eb0aacba782d77ed Mon Sep 17 00:00:00 2001 From: GloireMutaliko21 Date: Wed, 1 May 2024 14:12:56 +0200 Subject: [PATCH 07/21] feat: create today day plan --- apps/web/app/hooks/features/useDailyPlan.ts | 6 ++++-- apps/web/app/services/server/requests/daily-plan.ts | 2 +- .../features/daily-plan/create-daily-plan-form-modal.tsx | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/web/app/hooks/features/useDailyPlan.ts b/apps/web/app/hooks/features/useDailyPlan.ts index d25b2340e..a356047f6 100644 --- a/apps/web/app/hooks/features/useDailyPlan.ts +++ b/apps/web/app/hooks/features/useDailyPlan.ts @@ -25,8 +25,10 @@ export function useDailyPlan() { const createDailyPlan = useCallback( async (data: ICreateDailyPlan) => { - const res = await createQueryCall(data, user?.tenantId || ''); - return res; + if (user?.tenantId) { + const res = await createQueryCall(data, user?.tenantId || ''); + return res; + } }, [createQueryCall, user] ); diff --git a/apps/web/app/services/server/requests/daily-plan.ts b/apps/web/app/services/server/requests/daily-plan.ts index b30fd5e19..9420d4f1b 100644 --- a/apps/web/app/services/server/requests/daily-plan.ts +++ b/apps/web/app/services/server/requests/daily-plan.ts @@ -8,7 +8,7 @@ export function createPlanRequest({ }: { data: ICreateDailyPlan; bearer_token: string; - tenantId: string; + tenantId?: any; }) { return serverFetch({ method: 'POST', diff --git a/apps/web/lib/features/daily-plan/create-daily-plan-form-modal.tsx b/apps/web/lib/features/daily-plan/create-daily-plan-form-modal.tsx index 23b36833b..08e7c75f5 100644 --- a/apps/web/lib/features/daily-plan/create-daily-plan-form-modal.tsx +++ b/apps/web/lib/features/daily-plan/create-daily-plan-form-modal.tsx @@ -26,7 +26,7 @@ export function CreateDailyPlanFormModal({ async (values: any) => { const toDay = new Date(); createDailyPlan({ - workTimePlanned: values.workTimePlanned, + workTimePlanned: parseInt(values.workTimePlanned), taskId, date: planMode == 'today' ? toDay : new Date(toDay.getDate() + 1), status: DailyPlanStatusEnum.OPEN, From edc7f10ecb8b0cc53d2312c3e7d13ab9ff25a9c0 Mon Sep 17 00:00:00 2001 From: GloireMutaliko21 Date: Wed, 1 May 2024 17:39:21 +0200 Subject: [PATCH 08/21] feat: load day plans --- apps/web/app/api/daily-plan/route.ts | 25 +++++++++- .../app/hooks/features/useAuthTeamTasks.ts | 9 ++-- apps/web/app/hooks/features/useDailyPlan.ts | 21 +++++++-- .../web/app/services/client/api/daily-plan.ts | 25 +++++++++- .../services/server/requests/daily-plan.ts | 32 +++++++++++++ .../web/app/services/server/requests/index.ts | 1 + apps/web/app/stores/daily-plan.ts | 8 ++-- .../create-daily-plan-form-modal.tsx | 7 ++- apps/web/lib/features/task/task-filters.tsx | 2 +- apps/web/lib/features/user-profile-plans.tsx | 46 ++++++++++++++----- 10 files changed, 146 insertions(+), 30 deletions(-) diff --git a/apps/web/app/api/daily-plan/route.ts b/apps/web/app/api/daily-plan/route.ts index d4d96c1ed..843e168d4 100644 --- a/apps/web/app/api/daily-plan/route.ts +++ b/apps/web/app/api/daily-plan/route.ts @@ -1,7 +1,8 @@ import { NextResponse } from 'next/server'; import { authenticatedGuard } from '@app/services/server/guards/authenticated-guard-app'; -import { ICreateDailyPlan } from '@app/interfaces/IDailyPlan'; -import { createPlanRequest } from '@app/services/server/requests/daily-plan'; +import { ICreateDailyPlan } from '@app/interfaces'; +import { createPlanRequest, getDayPlansByEmployee } from '@app/services/server/requests'; +import { INextParams } from '@app/interfaces'; export async function POST(req: Request) { const res = new NextResponse(); @@ -15,3 +16,23 @@ export async function POST(req: Request) { return $res(response.data); } + +export async function GET(req: Request, { params }: INextParams) { + const res = new NextResponse(); + const { id } = params; + if (!id) { + return; + } + + const { $res, user, tenantId, organizationId, access_token } = await authenticatedGuard(req, res); + if (!user) return $res('Unauthorized'); + + const response = await getDayPlansByEmployee({ + bearer_token: access_token, + employeeId: id, + organizationId, + tenantId + }); + + return $res(response.data); +} diff --git a/apps/web/app/hooks/features/useAuthTeamTasks.ts b/apps/web/app/hooks/features/useAuthTeamTasks.ts index 025166418..c202aa3b7 100644 --- a/apps/web/app/hooks/features/useAuthTeamTasks.ts +++ b/apps/web/app/hooks/features/useAuthTeamTasks.ts @@ -1,11 +1,12 @@ import { IUser } from '@app/interfaces'; -import { tasksByTeamState } from '@app/stores'; +import { dailyPlanListState, tasksByTeamState } from '@app/stores'; import { useMemo } from 'react'; import { useRecoilValue } from 'recoil'; import { useOrganizationTeams } from './useOrganizationTeams'; export function useAuthTeamTasks(user: IUser | undefined) { const tasks = useRecoilValue(tasksByTeamState); + const plans = useRecoilValue(dailyPlanListState); const { activeTeam } = useOrganizationTeams(); const currentMember = activeTeam?.members?.find((member) => member.employee?.userId === user?.id); @@ -26,10 +27,8 @@ export function useAuthTeamTasks(user: IUser | undefined) { const dailyplan = useMemo(() => { if (!user) return []; - return tasks.filter((task) => { - return !task?.members.some((m) => m.userId === user.id); - }); - }, [tasks, user]); + return plans.items; + }, [plans, user]); const totalTodayTasks = useMemo( () => diff --git a/apps/web/app/hooks/features/useDailyPlan.ts b/apps/web/app/hooks/features/useDailyPlan.ts index a356047f6..094d31a4f 100644 --- a/apps/web/app/hooks/features/useDailyPlan.ts +++ b/apps/web/app/hooks/features/useDailyPlan.ts @@ -4,13 +4,14 @@ import { useRecoilState } from 'recoil'; import { useCallback, useEffect } from 'react'; import { useQuery } from '../useQuery'; import { dailyPlanFetchingState, dailyPlanListState, userState } from '@app/stores'; -import { createDailyPlanAPI } from '@app/services/client/api'; +import { createDailyPlanAPI, getDayPlansByEmployeeAPI } from '@app/services/client/api'; import { ICreateDailyPlan } from '@app/interfaces'; import { useFirstLoad } from '../useFirstLoad'; export function useDailyPlan() { const [user] = useRecoilState(userState); + const { loading, queryCall } = useQuery(getDayPlansByEmployeeAPI); const { loading: createDailyPlanLoading, queryCall: createQueryCall } = useQuery(createDailyPlanAPI); const [dailyPlan, setDailyPlan] = useRecoilState(dailyPlanListState); @@ -19,9 +20,21 @@ export function useDailyPlan() { useEffect(() => { if (firstLoad) { - setDailyPlanFetching(createDailyPlanLoading); // Change this after provided getDailyPlan handlers + setDailyPlanFetching(loading); } - }, [createDailyPlanLoading, firstLoad, setDailyPlanFetching]); // Update loading var after provided getDailyPlan handlers + }, [loading, firstLoad, setDailyPlanFetching, user?.employee.id]); + + const getEmployeeDayPlans = useCallback( + (employeeId: string) => { + queryCall(employeeId).then((response) => { + if (response.data.items.length) { + const { items, total } = response.data; + setDailyPlan({ items, total }); + } + }); + }, + [queryCall, setDailyPlan] + ); const createDailyPlan = useCallback( async (data: ICreateDailyPlan) => { @@ -39,6 +52,8 @@ export function useDailyPlan() { dailyPlanFetching, firstLoadDailyPlanData, createDailyPlan, + loading, + getEmployeeDayPlans, createDailyPlanLoading }; } diff --git a/apps/web/app/services/client/api/daily-plan.ts b/apps/web/app/services/client/api/daily-plan.ts index a849ad939..2fba8d07e 100644 --- a/apps/web/app/services/client/api/daily-plan.ts +++ b/apps/web/app/services/client/api/daily-plan.ts @@ -1,5 +1,26 @@ -import { ICreateDailyPlan } from '@app/interfaces/IDailyPlan'; -import { post } from '../axios'; +import qs from 'qs'; +import { get, post } from '../axios'; +import { ICreateDailyPlan, IDailyPlan, PaginationResponse } from '@app/interfaces'; +import { getOrganizationIdCookie, getTenantIdCookie } from '@app/helpers'; + +export function getDayPlansByEmployeeAPI(employeeId?: string) { + const organizationId = getOrganizationIdCookie(); + const tenantId = getTenantIdCookie(); + + const relations = ['employee', 'tasks']; + + const obj = { + 'where[organizationId]': organizationId, + 'where[tenantId]': tenantId + } as Record; + + relations.forEach((relation, i) => { + obj[`relations[${i}]`] = relation; + }); + + const query = qs.stringify(obj); + return get>(`/daily-plan/employee/${employeeId}?${query}`, { tenantId }); +} export function createDailyPlanAPI(data: ICreateDailyPlan, tenantId?: string) { return post('/daily-plan', data, { diff --git a/apps/web/app/services/server/requests/daily-plan.ts b/apps/web/app/services/server/requests/daily-plan.ts index 9420d4f1b..d1b962657 100644 --- a/apps/web/app/services/server/requests/daily-plan.ts +++ b/apps/web/app/services/server/requests/daily-plan.ts @@ -1,6 +1,38 @@ +import qs from 'qs'; import { ICreateDailyPlan, IDailyPlan } from '@app/interfaces/IDailyPlan'; import { serverFetch } from '../fetch'; +export function getDayPlansByEmployee({ + employeeId, + organizationId, + tenantId, + bearer_token, + relations = ['employee', 'tasks'] +}: { + employeeId: string; + organizationId: string; + tenantId: string; + bearer_token: string; + relations?: string[]; +}) { + const obj = { + 'where[organizationId]': organizationId, + 'where[tenantId]': tenantId + } as Record; + + relations.forEach((relation, i) => { + obj[`relations[${i}]`] = relation; + }); + + const query = qs.stringify(obj); + + return serverFetch({ + path: `/daily-plan/employee/${employeeId}?${query}`, + method: 'GET', + bearer_token + }); +} + export function createPlanRequest({ data, bearer_token, diff --git a/apps/web/app/services/server/requests/index.ts b/apps/web/app/services/server/requests/index.ts index 3226b849d..8915f0553 100644 --- a/apps/web/app/services/server/requests/index.ts +++ b/apps/web/app/services/server/requests/index.ts @@ -5,6 +5,7 @@ export * from './organization-team-employee'; export * from './tenant'; export * from './timer'; export * from './tasks'; +export * from './daily-plan'; export * from './employee'; export * from './invite'; export * from './timesheet'; diff --git a/apps/web/app/stores/daily-plan.ts b/apps/web/app/stores/daily-plan.ts index 540c31528..115eca379 100644 --- a/apps/web/app/stores/daily-plan.ts +++ b/apps/web/app/stores/daily-plan.ts @@ -1,9 +1,9 @@ import { atom, selector } from 'recoil'; -import { IDailyPlan } from '@app/interfaces/IDailyPlan'; +import { IDailyPlan, PaginationResponse } from '@app/interfaces'; -export const dailyPlanListState = atom({ +export const dailyPlanListState = atom>({ key: 'dailyPlanListState', - default: [] + default: { items: [], total: 0 } }); export const activeDailyPlanIdState = atom({ @@ -21,6 +21,6 @@ export const activeDailyPlanState = selector({ get: ({ get }) => { const dailyPlans = get(dailyPlanListState); const activeId = get(activeDailyPlanIdState); - return dailyPlans.find((plan) => plan.id === activeId) || dailyPlans[0] || null; + return dailyPlans.items.find((plan) => plan.id === activeId) || dailyPlans.items[0] || null; } }); diff --git a/apps/web/lib/features/daily-plan/create-daily-plan-form-modal.tsx b/apps/web/lib/features/daily-plan/create-daily-plan-form-modal.tsx index 08e7c75f5..dba90b073 100644 --- a/apps/web/lib/features/daily-plan/create-daily-plan-form-modal.tsx +++ b/apps/web/lib/features/daily-plan/create-daily-plan-form-modal.tsx @@ -36,6 +36,7 @@ export function CreateDailyPlanFormModal({ }).then(() => { refetch(); reset(); + closeModal(); }); }, [ @@ -46,7 +47,8 @@ export function CreateDailyPlanFormModal({ user?.employee.id, user?.employee.organizationId, refetch, - reset + reset, + closeModal ] ); return ( @@ -70,7 +72,8 @@ export function CreateDailyPlanFormModal({ placeholder="Working time to plan" className="mb-0 min-w-[350px]" wrapperClassName="mb-0 rounded-lg" - {...register('workTimePlanned')} + required + // {...register('workTimePlanned')} /> + + + setDate(day ?? new Date())} + initialFocus + /> + + + )} + diff --git a/apps/web/lib/features/task/task-all-status-type.tsx b/apps/web/lib/features/task/task-all-status-type.tsx index 26c67f1a3..98c0e2687 100644 --- a/apps/web/lib/features/task/task-all-status-type.tsx +++ b/apps/web/lib/features/task/task-all-status-type.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useCustomEmblaCarousel, useSyncRef } from '@app/hooks'; +import { useCustomEmblaCarousel, useDailyPlan, useSyncRef } from '@app/hooks'; import { ITeamTask, Nullable } from '@app/interfaces'; import { RoundedButton } from 'lib/components'; import { useEffect, useMemo } from 'react'; @@ -12,6 +12,8 @@ import { useTaskStatusValue } from './task-status'; import { clsxm } from '@app/utils'; +import { planBadgeContent } from '@app/helpers'; +import { CalendarIcon } from '@radix-ui/react-icons'; export function TaskAllStatusTypes({ task, @@ -29,6 +31,8 @@ export function TaskAllStatusTypes({ const taskLabels = useTaskLabelsValue(); const taskStatus = useTaskStatusValue(); + const { dailyPlan, getAllDayPlans } = useDailyPlan(); + const { viewportRef, nextBtnEnabled, scrollNext, prevBtnEnabled, scrollPrev, emblaApi } = useCustomEmblaCarousel( 0, { @@ -43,6 +47,10 @@ export function TaskAllStatusTypes({ emblaApiRef.current?.reInit(); }, [task, emblaApiRef]); + useEffect(() => { + getAllDayPlans(); + }, [getAllDayPlans]); + const tags = useMemo(() => { return ( task?.tags @@ -86,7 +94,10 @@ export function TaskAllStatusTypes({ titleClassName={'text-[0.625rem] font-[500]'} /> )} - +
    + + {planBadgeContent(dailyPlan.items, task?.id ?? '')} +
    {tags.map((tag, i) => { return ( new Date(a.date).getTime() - new Date(b.date).getTime()); if (currentTab === 'Future Tasks') - filteredPlans = ascSortedPlans.filter((plan) => new Date(plan.date).getTime() > new Date().getTime()); + filteredPlans = ascSortedPlans.filter((plan) => { + const planDate = new Date(plan.date); + const today = new Date(); + today.setHours(23, 59, 59, 0); // Set today time to exclude timestamps in comparization + return planDate.getTime() >= today.getTime(); + }); if (currentTab === 'Past Tasks') filteredPlans = descSortedPlans.filter((plan) => { From 6034a45a2f11763c250bb8b2028282ff37917ecb Mon Sep 17 00:00:00 2001 From: GloireMutaliko21 Date: Fri, 3 May 2024 10:36:43 +0200 Subject: [PATCH 17/21] feat: plan for some day disable past dates --- apps/web/app/[locale]/profile/[memberId]/page.tsx | 7 ++++++- .../daily-plan/create-daily-plan-form-modal.tsx | 6 ++++-- apps/web/lib/features/task/task-all-status-type.tsx | 10 ++++++---- apps/web/lib/features/user-profile-plans.tsx | 12 +++--------- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/apps/web/app/[locale]/profile/[memberId]/page.tsx b/apps/web/app/[locale]/profile/[memberId]/page.tsx index d5c3762c6..4826c1c86 100644 --- a/apps/web/app/[locale]/profile/[memberId]/page.tsx +++ b/apps/web/app/[locale]/profile/[memberId]/page.tsx @@ -2,7 +2,7 @@ /* eslint-disable no-mixed-spaces-and-tabs */ import { imgTitle } from '@app/helpers'; -import { useAuthenticateUser, useOrganizationTeams, useTimer, useUserProfilePage } from '@app/hooks'; +import { useAuthenticateUser, useDailyPlan, useOrganizationTeams, useTimer, useUserProfilePage } from '@app/hooks'; import { ITimerStatusEnum, OT_Member } from '@app/interfaces'; import { clsxm, isValidUrl } from '@app/utils'; import clsx from 'clsx'; @@ -29,6 +29,7 @@ const Profile = React.memo(function ProfilePage({ params }: { params: { memberId const profile = useUserProfilePage(); const { user } = useAuthenticateUser(); const { isTrackingEnabled, activeTeam, activeTeamManagers } = useOrganizationTeams(); + const { getEmployeeDayPlans } = useDailyPlan(); const fullWidth = useRecoilValue(fullWidthState); const [activityFilter, setActivityFilter] = useState('Tasks'); const setActivityTypeFilter = useSetRecoilState(activityTypeState); @@ -68,6 +69,10 @@ const Profile = React.memo(function ProfilePage({ params }: { params: { memberId // eslint-disable-next-line react-hooks/exhaustive-deps }, [profile.member]); + React.useEffect(() => { + getEmployeeDayPlans(params.memberId); + }, [getEmployeeDayPlans, params.memberId]); + // Example usage return ( diff --git a/apps/web/lib/features/daily-plan/create-daily-plan-form-modal.tsx b/apps/web/lib/features/daily-plan/create-daily-plan-form-modal.tsx index a6d8a09e9..bd9cee9b0 100644 --- a/apps/web/lib/features/daily-plan/create-daily-plan-form-modal.tsx +++ b/apps/web/lib/features/daily-plan/create-daily-plan-form-modal.tsx @@ -28,7 +28,7 @@ export function CreateDailyPlanFormModal({ const { handleSubmit, reset, register } = useForm(); const { createDailyPlan, createDailyPlanLoading } = useDailyPlan(); - const [date, setDate] = useState(new Date()); + const [date, setDate] = useState(new Date(tomorrowDate)); const onSubmit = useCallback( async (values: any) => { @@ -101,8 +101,10 @@ export function CreateDailyPlanFormModal({ setDate(day ?? new Date())} + onSelect={(day) => setDate(day ?? new Date(tomorrowDate))} initialFocus + disabled={{ from: new Date(1970, 1, 1), to: new Date() }} + // de /> diff --git a/apps/web/lib/features/task/task-all-status-type.tsx b/apps/web/lib/features/task/task-all-status-type.tsx index 98c0e2687..ce783a704 100644 --- a/apps/web/lib/features/task/task-all-status-type.tsx +++ b/apps/web/lib/features/task/task-all-status-type.tsx @@ -94,10 +94,12 @@ export function TaskAllStatusTypes({ titleClassName={'text-[0.625rem] font-[500]'} /> )} -
    - - {planBadgeContent(dailyPlan.items, task?.id ?? '')} -
    + {planBadgeContent(dailyPlan.items, task?.id ?? '') && ( +
    + + {planBadgeContent(dailyPlan.items, task?.id ?? '')} +
    + )} {tags.map((tag, i) => { return ( ('Today Tasks'); @@ -30,10 +28,6 @@ export function UserProfilePlans() { Outstanding: <> }; - useEffect(() => { - getEmployeeDayPlans(user?.employee.id ?? ''); - }, [getEmployeeDayPlans, user?.employee.id]); - return (
    From abc612d42d455ccc49e9fddb2f82338780d54389 Mon Sep 17 00:00:00 2001 From: Ushindi Gedeon Date: Fri, 3 May 2024 11:32:00 +0200 Subject: [PATCH 18/21] [Improvement] Add translations for resend code messages (#2479) * [Improvement] Add translations for resend code messages * Fix type error * Add missing translation copies --- apps/web/app/[locale]/auth/passcode/component.tsx | 14 +++++++++----- apps/web/lib/i18n/en.ts | 2 ++ apps/web/messages/ar.json | 2 ++ apps/web/messages/bg.json | 2 ++ apps/web/messages/de.json | 2 ++ apps/web/messages/en.json | 2 ++ apps/web/messages/es.json | 2 ++ apps/web/messages/fr.json | 2 ++ apps/web/messages/he.json | 2 ++ apps/web/messages/it.json | 2 ++ apps/web/messages/nl.json | 2 ++ apps/web/messages/pl.json | 2 ++ apps/web/messages/pt.json | 2 ++ apps/web/messages/ru.json | 2 ++ apps/web/messages/zh.json | 2 ++ apps/web/public/locales/ar/common.json | 2 ++ apps/web/public/locales/bg/common.json | 2 ++ apps/web/public/locales/de/common.json | 2 ++ apps/web/public/locales/en/common.json | 2 ++ apps/web/public/locales/es/common.json | 2 ++ apps/web/public/locales/fr/common.json | 2 ++ apps/web/public/locales/he/common.json | 2 ++ apps/web/public/locales/it/common.json | 2 ++ apps/web/public/locales/nl/common.json | 2 ++ apps/web/public/locales/pl/common.json | 2 ++ apps/web/public/locales/pt/common.json | 2 ++ apps/web/public/locales/ru/common.json | 2 ++ apps/web/public/locales/zh/common.json | 2 ++ 28 files changed, 63 insertions(+), 5 deletions(-) diff --git a/apps/web/app/[locale]/auth/passcode/component.tsx b/apps/web/app/[locale]/auth/passcode/component.tsx index 7861cd28c..f01490ef5 100644 --- a/apps/web/app/[locale]/auth/passcode/component.tsx +++ b/apps/web/app/[locale]/auth/passcode/component.tsx @@ -129,6 +129,12 @@ function PasscodeScreen({ form, className }: { form: TAuthenticationPasscode } & const t = useTranslations(); const inputsRef = useRef>([]); + const formatTime = (seconds: number) => { + const minutes = Math.floor(seconds / 60); + const remainingSeconds = seconds % 60; + return `${String(minutes).padStart(2, '0')}:${String(remainingSeconds).padStart(2, '0')}`; + }; + const [timer, setTimer] = useState(60); const [disabled, setDisabled] = useState(true); @@ -229,14 +235,12 @@ function PasscodeScreen({ form, className }: { form: TAuthenticationPasscode } & > {!disabled ? ( - {'Re'} - {t('pages.auth.SEND_CODE')} + {t('pages.auth.RESEND_CODE')} ) : ( - {'Re'} - {t('pages.auth.SEND_CODE')} {' in 00:'} - {timer} + {t('pages.auth.RESEND_CODE_IN')} {' '} + {formatTime(timer)} )} diff --git a/apps/web/lib/i18n/en.ts b/apps/web/lib/i18n/en.ts index 72764e8da..dc0c10db7 100644 --- a/apps/web/lib/i18n/en.ts +++ b/apps/web/lib/i18n/en.ts @@ -163,6 +163,8 @@ export const en = { auth: { SEND_CODE: 'send code', + RESEND_CODE: 'Resend Code', + RESEND_CODE_IN: 'Resend Code in', JOIN: 'Join', UNRECEIVED_CODE: "Didn't receive code ?", JOIN_TEAM: 'Join Team', diff --git a/apps/web/messages/ar.json b/apps/web/messages/ar.json index 6d6faae20..a15a41719 100644 --- a/apps/web/messages/ar.json +++ b/apps/web/messages/ar.json @@ -246,6 +246,8 @@ }, "auth": { "SEND_CODE": "إرسال الرمز", + "RESEND_CODE": "إعادة إرسال الرمز", + "RESEND_CODE_IN": "إعادة إرسال الرمز في", "JOIN": "انضمام", "UNRECEIVED_CODE": "لم تتلقى الرمز؟", "JOIN_TEAM": "انضمام للفريق", diff --git a/apps/web/messages/bg.json b/apps/web/messages/bg.json index d915544ce..e221eb317 100644 --- a/apps/web/messages/bg.json +++ b/apps/web/messages/bg.json @@ -246,6 +246,8 @@ }, "auth": { "SEND_CODE": "изпрати код", + "RESEND_CODE": "Изпрати код отново", + "RESEND_CODE_IN": "Изпрати код отново след", "JOIN": "Присъединяване", "UNRECEIVED_CODE": "Не получихте код?", "JOIN_TEAM": "Присъединяване към отбор", diff --git a/apps/web/messages/de.json b/apps/web/messages/de.json index 7373577ea..e43fe74d1 100644 --- a/apps/web/messages/de.json +++ b/apps/web/messages/de.json @@ -247,6 +247,8 @@ }, "auth": { "SEND_CODE": "Code senden", + "RESEND_CODE": "Code erneut senden", + "RESEND_CODE_IN": "Code in", "JOIN": "Beitreten", "UNRECEIVED_CODE": "Keinen Code erhalten?", "JOIN_TEAM": "Team beitreten", diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index 7d44fc1a2..b7f393eca 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -246,6 +246,8 @@ }, "auth": { "SEND_CODE": "send code", + "RESEND_CODE": "Resend Code", + "RESEND_CODE_IN": "Resend Code in", "JOIN": "Join", "UNRECEIVED_CODE": "Didn't receive code ?", "JOIN_TEAM": "Join Team", diff --git a/apps/web/messages/es.json b/apps/web/messages/es.json index 7e6bd1e06..5467bcd7a 100644 --- a/apps/web/messages/es.json +++ b/apps/web/messages/es.json @@ -246,6 +246,8 @@ }, "auth": { "SEND_CODE": "enviar código", + "RESEND_CODE": "Reenviar código", + "RESEND_CODE_IN": "Reenviar código en", "JOIN": "Unirse", "UNRECEIVED_CODE": "¿No recibiste el código?", "JOIN_TEAM": "Unirse al equipo", diff --git a/apps/web/messages/fr.json b/apps/web/messages/fr.json index 0e1a40b9f..3e2417aab 100644 --- a/apps/web/messages/fr.json +++ b/apps/web/messages/fr.json @@ -246,6 +246,8 @@ }, "auth": { "SEND_CODE": "envoyer le code", + "RESEND_CODE": "Renvoyer le code", + "RESEND_CODE_IN": "Renvoyer le code dans", "JOIN": "Joindre", "UNRECEIVED_CODE": "Vous n'avez pas reçu de code ?", "JOIN_TEAM": "Rejoindre l'équipe", diff --git a/apps/web/messages/he.json b/apps/web/messages/he.json index 9955b93d7..c15eb8a95 100644 --- a/apps/web/messages/he.json +++ b/apps/web/messages/he.json @@ -246,6 +246,8 @@ }, "auth": { "SEND_CODE": "שלח קוד", + "RESEND_CODE": "שלח קוד מחדש", + "RESEND_CODE_IN": "שלח קוד מחדש ב-", "JOIN": "הצטרף", "UNRECEIVED_CODE": "לא קיבלת קוד?", "JOIN_TEAM": "הצטרף לצוות", diff --git a/apps/web/messages/it.json b/apps/web/messages/it.json index b2b3f5e6e..9371c7d02 100644 --- a/apps/web/messages/it.json +++ b/apps/web/messages/it.json @@ -246,6 +246,8 @@ }, "auth": { "SEND_CODE": "Invia Codice", + "RESEND_CODE": "Reinvia Codice", + "RESEND_CODE_IN": "Invia nuovamente il codice", "JOIN": "Unisciti", "UNRECEIVED_CODE": "Non hai ricevuto il codice?", "JOIN_TEAM": "Unisciti al Team", diff --git a/apps/web/messages/nl.json b/apps/web/messages/nl.json index e4cebba98..68db3e947 100644 --- a/apps/web/messages/nl.json +++ b/apps/web/messages/nl.json @@ -246,6 +246,8 @@ }, "auth": { "SEND_CODE": "code verzenden", + "RESEND_CODE": "Code opnieuw verzenden", + "RESEND_CODE_IN": "Code opnieuw verzenden in", "JOIN": "Word lid", "UNRECEIVED_CODE": "Geen code ontvangen?", "JOIN_TEAM": "Word lid van team", diff --git a/apps/web/messages/pl.json b/apps/web/messages/pl.json index b8b3fbb17..92883309b 100644 --- a/apps/web/messages/pl.json +++ b/apps/web/messages/pl.json @@ -246,6 +246,8 @@ }, "auth": { "SEND_CODE": "wyślij kod", + "RESEND_CODE": "Wyślij ponownie kod", + "RESEND_CODE_IN": "Wyślij ponownie kod w", "JOIN": "Dołącz", "UNRECEIVED_CODE": "Nie otrzymałeś kodu?", "JOIN_TEAM": "Dołącz do Zespołu", diff --git a/apps/web/messages/pt.json b/apps/web/messages/pt.json index 94cf7c429..cabb8ad58 100644 --- a/apps/web/messages/pt.json +++ b/apps/web/messages/pt.json @@ -246,6 +246,8 @@ }, "auth": { "SEND_CODE": "enviar código", + "RESEND_CODE": "Reenviar Código", + "RESEND_CODE_IN": "Reenviar Código em", "JOIN": "Participar", "UNRECEIVED_CODE": "Não recebeu o código?", "JOIN_TEAM": "Participar da Equipe", diff --git a/apps/web/messages/ru.json b/apps/web/messages/ru.json index 89c89fc7c..e3581792b 100644 --- a/apps/web/messages/ru.json +++ b/apps/web/messages/ru.json @@ -246,6 +246,8 @@ }, "auth": { "SEND_CODE": "отправить код", + "RESEND_CODE": "Отправить код повторно", + "RESEND_CODE_IN": "Отправить код повторно через", "JOIN": "Присоединиться", "UNRECEIVED_CODE": "Не получили код?", "JOIN_TEAM": "Присоединиться к команде", diff --git a/apps/web/messages/zh.json b/apps/web/messages/zh.json index d26b5a235..f3228409b 100644 --- a/apps/web/messages/zh.json +++ b/apps/web/messages/zh.json @@ -246,6 +246,8 @@ }, "auth": { "SEND_CODE": "发送验证码", + "RESEND_CODE": "重新发送验证码", + "RESEND_CODE_IN": "重新发送验证码", "JOIN": "加入", "UNRECEIVED_CODE": "未收到验证码?", "JOIN_TEAM": "加入团队", diff --git a/apps/web/public/locales/ar/common.json b/apps/web/public/locales/ar/common.json index cde1569fb..8e6d87965 100644 --- a/apps/web/public/locales/ar/common.json +++ b/apps/web/public/locales/ar/common.json @@ -241,6 +241,8 @@ "auth": { "SEND_CODE": "إرسال الرمز", + "RESEND_CODE": "إعادة إرسال الرمز", + "RESEND_CODE_IN": "إعادة إرسال الرمز في", "JOIN": "انضمام", "UNRECEIVED_CODE": "لم تتلقى الرمز؟", "JOIN_TEAM": "انضمام للفريق", diff --git a/apps/web/public/locales/bg/common.json b/apps/web/public/locales/bg/common.json index 255a60c06..b68db5261 100644 --- a/apps/web/public/locales/bg/common.json +++ b/apps/web/public/locales/bg/common.json @@ -242,6 +242,8 @@ "auth": { "SEND_CODE": "изпрати код", + "RESEND_CODE": "Изпрати код отново", + "RESEND_CODE_IN": "Изпрати код отново след", "JOIN": "Присъединяване", "UNRECEIVED_CODE": "Не получихте код?", "JOIN_TEAM": "Присъединяване към отбор", diff --git a/apps/web/public/locales/de/common.json b/apps/web/public/locales/de/common.json index e2f78a24e..589c0be34 100644 --- a/apps/web/public/locales/de/common.json +++ b/apps/web/public/locales/de/common.json @@ -241,6 +241,8 @@ "auth": { "SEND_CODE": "Code senden", + "RESEND_CODE": "Code erneut senden", + "RESEND_CODE_IN": "Code erneut einsenden", "JOIN": "Beitreten", "UNRECEIVED_CODE": "Keinen Code erhalten?", "JOIN_TEAM": "Team beitreten", diff --git a/apps/web/public/locales/en/common.json b/apps/web/public/locales/en/common.json index 8f2d0ece5..f6ee44d64 100644 --- a/apps/web/public/locales/en/common.json +++ b/apps/web/public/locales/en/common.json @@ -247,6 +247,8 @@ }, "auth": { "SEND_CODE": "send code", + "RESEND_CODE": "Resend Code", + "RESEND_CODE_IN": "Resend Code in", "JOIN": "Join", "UNRECEIVED_CODE": "Didn't receive code ?", "JOIN_TEAM": "Join Team", diff --git a/apps/web/public/locales/es/common.json b/apps/web/public/locales/es/common.json index e84f8fd1c..8fa0bf463 100644 --- a/apps/web/public/locales/es/common.json +++ b/apps/web/public/locales/es/common.json @@ -233,6 +233,8 @@ }, "auth": { "SEND_CODE": "enviar código", + "RESEND_CODE": "Reenviar código", + "RESEND_CODE_IN": "Reenviar código en", "JOIN": "Unirse", "UNRECEIVED_CODE": "¿No recibiste el código?", "JOIN_TEAM": "Unirse al equipo", diff --git a/apps/web/public/locales/fr/common.json b/apps/web/public/locales/fr/common.json index bc99a21d3..52efdf1fb 100644 --- a/apps/web/public/locales/fr/common.json +++ b/apps/web/public/locales/fr/common.json @@ -236,6 +236,8 @@ }, "auth": { "SEND_CODE": "envoyer le code", + "RESEND_CODE": "Renvoyer le code", + "RESEND_CODE_IN": "Renvoyer le code dans", "JOIN": "Joindre", "UNRECEIVED_CODE": "Vous n'avez pas reçu de code ?", "JOIN_TEAM": "Rejoindre l'équipe", diff --git a/apps/web/public/locales/he/common.json b/apps/web/public/locales/he/common.json index b22df5e97..55bb964d5 100644 --- a/apps/web/public/locales/he/common.json +++ b/apps/web/public/locales/he/common.json @@ -240,6 +240,8 @@ "auth": { "SEND_CODE": "שלח קוד", + "RESEND_CODE": "שלח קוד מחדש", + "RESEND_CODE_IN": "שלח קוד מחדש בעוד", "JOIN": "הצטרף", "UNRECEIVED_CODE": "לא קיבלת קוד?", "JOIN_TEAM": "הצטרף לצוות", diff --git a/apps/web/public/locales/it/common.json b/apps/web/public/locales/it/common.json index 002994b32..3ade373c1 100644 --- a/apps/web/public/locales/it/common.json +++ b/apps/web/public/locales/it/common.json @@ -243,6 +243,8 @@ "auth": { "SEND_CODE": "send code", + "RESEND_CODE": "Codice di rispedizione", + "RESEND_CODE_IN": "Invia nuovamente il codice", "JOIN": "Join", "UNRECEIVED_CODE": "Didn't receive code ?", "JOIN_TEAM": "Join Team", diff --git a/apps/web/public/locales/nl/common.json b/apps/web/public/locales/nl/common.json index 39ffc3a4a..6c2c11ac5 100644 --- a/apps/web/public/locales/nl/common.json +++ b/apps/web/public/locales/nl/common.json @@ -240,6 +240,8 @@ "auth": { "SEND_CODE": "code verzenden", + "RESEND_CODE": "Code opnieuw verzenden", + "RESEND_CODE_IN": "Code opnieuw verzenden in", "JOIN": "Word lid", "UNRECEIVED_CODE": "Geen code ontvangen?", "JOIN_TEAM": "Word lid van team", diff --git a/apps/web/public/locales/pl/common.json b/apps/web/public/locales/pl/common.json index 6402db8c0..b533b8e05 100644 --- a/apps/web/public/locales/pl/common.json +++ b/apps/web/public/locales/pl/common.json @@ -243,6 +243,8 @@ "auth": { "SEND_CODE": "send code", + "RESEND_CODE": "Wyślij kod ponownie", + "RESEND_CODE_IN": "Wyślij kod ponownie w", "JOIN": "Join", "UNRECEIVED_CODE": "Didn't receive code ?", "JOIN_TEAM": "Join Team", diff --git a/apps/web/public/locales/pt/common.json b/apps/web/public/locales/pt/common.json index 97a517daf..367da9425 100644 --- a/apps/web/public/locales/pt/common.json +++ b/apps/web/public/locales/pt/common.json @@ -243,6 +243,8 @@ "auth": { "SEND_CODE": "send code", + "RESEND_CODE": "Reenviar código", + "RESEND_CODE_IN": "Reenviar código em", "JOIN": "Join", "UNRECEIVED_CODE": "Didn't receive code ?", "JOIN_TEAM": "Join Team", diff --git a/apps/web/public/locales/ru/common.json b/apps/web/public/locales/ru/common.json index a393e68e8..f3a908001 100644 --- a/apps/web/public/locales/ru/common.json +++ b/apps/web/public/locales/ru/common.json @@ -242,6 +242,8 @@ "auth": { "SEND_CODE": "send code", + "RESEND_CODE": "Отправить код еще раз", + "RESEND_CODE_IN": "Повторно отправить код в", "JOIN": "Join", "UNRECEIVED_CODE": "Didn't receive code ?", "JOIN_TEAM": "Join Team", diff --git a/apps/web/public/locales/zh/common.json b/apps/web/public/locales/zh/common.json index 29513c0ee..dd9798657 100644 --- a/apps/web/public/locales/zh/common.json +++ b/apps/web/public/locales/zh/common.json @@ -241,6 +241,8 @@ "auth": { "SEND_CODE": "发送验证码", + "RESEND_CODE": "重新发送验证码", + "ENTER_CODE": "输入验证码", "JOIN": "加入", "UNRECEIVED_CODE": "未收到验证码?", "JOIN_TEAM": "加入团队", From 193a9a1b61a94cca355c7b668720206a93c20546 Mon Sep 17 00:00:00 2001 From: Anish Date: Fri, 3 May 2024 14:35:27 +0500 Subject: [PATCH 19/21] feat: worked on task edit (#2480) * feat: worked on task edit * Mod1 feat(working): working on plans and configuration * Mod1 feat: worked on kanban menu to run clicks * Mod1 feat: worked on kanban menu to run clicks * Mod1 feat: worked on kanban menu to run clicks * Mod1 feat: worked on kanban menu to run clicks --- .../app/hooks/features/useTeamMemberCard.ts | 10 ++- apps/web/app/stores/team-tasks.ts | 7 +- .../pages/kanban/menu-kanban-card.tsx | 86 +++++++++++++++++++ apps/web/lib/components/kanban-card.tsx | 27 +++--- .../lib/features/task/task-input-kanban.tsx | 6 +- 5 files changed, 113 insertions(+), 23 deletions(-) create mode 100644 apps/web/components/pages/kanban/menu-kanban-card.tsx diff --git a/apps/web/app/hooks/features/useTeamMemberCard.ts b/apps/web/app/hooks/features/useTeamMemberCard.ts index 77510197b..3d2b2612c 100644 --- a/apps/web/app/hooks/features/useTeamMemberCard.ts +++ b/apps/web/app/hooks/features/useTeamMemberCard.ts @@ -22,7 +22,8 @@ import cloneDeep from 'lodash/cloneDeep'; */ export function useTeamMemberCard(member: IOrganizationTeamList['members'][number] | undefined) { const { updateTask, tasks, setActiveTask, deleteEmployeeFromTasks } = useTeamTasks(); - + const [assignTaskLoading, setAssignTaskLoading] = useState(false); + const [unAssignTaskLoading, setUnAssignTaskLoading] = useState(false); const publicTeam = useRecoilValue(getPublicState); const allTaskStatistics = useRecoilValue(allTaskStatisticsState); @@ -167,7 +168,7 @@ export function useTeamMemberCard(member: IOrganizationTeamList['members'][numbe if (!member?.employeeId) { return Promise.resolve(); } - + setAssignTaskLoading(true); return updateTask({ ...task, members: [...task.members, (member?.employeeId ? { id: member?.employeeId } : {}) as any] @@ -175,6 +176,7 @@ export function useTeamMemberCard(member: IOrganizationTeamList['members'][numbe if (isAuthUser && !activeTeamTask) { setActiveTask(task); } + setAssignTaskLoading(false); }); }, [updateTask, member, isAuthUser, setActiveTask, activeTeamTask] @@ -185,12 +187,14 @@ export function useTeamMemberCard(member: IOrganizationTeamList['members'][numbe if (!member?.employeeId) { return Promise.resolve(); } + setUnAssignTaskLoading(true); return updateTask({ ...task, members: task.members.filter((m) => m.id !== member.employeeId) }).finally(() => { isAuthUser && setActiveTask(null); + setUnAssignTaskLoading(false); }); }, [updateTask, member, isAuthUser, setActiveTask] @@ -201,6 +205,8 @@ export function useTeamMemberCard(member: IOrganizationTeamList['members'][numbe memberUnassignTasks, isTeamManager, memberUser, + assignTaskLoading, + unAssignTaskLoading, member, memberTask: memberTaskRef.current, isAuthUser, diff --git a/apps/web/app/stores/team-tasks.ts b/apps/web/app/stores/team-tasks.ts index 27161efe4..78783383e 100644 --- a/apps/web/app/stores/team-tasks.ts +++ b/apps/web/app/stores/team-tasks.ts @@ -12,7 +12,12 @@ export const activeTeamTaskState = atom({ key: 'activeTeamTaskState', default: null }); - +export const activeTeamTaskId = atom<{ id: string }>({ + key: 'activeTeamTaskId', + default: { + id: '' + } +}); export const tasksFetchingState = atom({ key: 'tasksFetchingState', default: false diff --git a/apps/web/components/pages/kanban/menu-kanban-card.tsx b/apps/web/components/pages/kanban/menu-kanban-card.tsx new file mode 100644 index 000000000..c91fecaf4 --- /dev/null +++ b/apps/web/components/pages/kanban/menu-kanban-card.tsx @@ -0,0 +1,86 @@ +import { useTeamMemberCard } from '@app/hooks'; +import { activeTeamTaskId } from '@app/stores'; +import { Popover, PopoverContent, PopoverTrigger } from '@components/ui/popover'; +import { ThreeCircleOutlineVerticalIcon } from 'assets/svg'; +import { SpinnerLoader } from 'lib/components'; +import { useTranslations } from 'next-intl'; +import { useState } from 'react'; +import { useSetRecoilState } from 'recoil'; + +export default function MenuKanbanCard({ member, item }: { item: any; member: any }) { + const t = useTranslations(); + const { assignTask, unassignTask, assignTaskLoading, unAssignTaskLoading } = useTeamMemberCard(member); + const setActiveTask = useSetRecoilState(activeTeamTaskId); + const [load, setLoad] = useState<'' | 'assign' | 'unassign'>(''); + const menu = [ + { + name: t('common.EDIT_TASK'), + closable: true, + action: 'edit', + active: true, + onClick: () => { + setActiveTask({ + id: item.id + }); + } + }, + { + name: t('common.ESTIMATE'), + closable: true, + action: 'estimate', + onClick: () => { + // TODO: Implement estimate task after fixing the time estimate issue + }, + active: true + }, + { + name: t('common.ASSIGN_TASK'), + action: 'assign', + active: true, + onClick: () => { + setLoad('assign'); + assignTask(item); + } + }, + { + name: t('common.UNASSIGN_TASK'), + action: 'unassign', + closable: true, + active: true, + onClick: () => { + setLoad('unassign'); + unassignTask(item); + } + } + ].filter((item) => item.active || item.active === undefined); + + return ( + + + + + +
      + {menu.map((item) => { + return ( +
    • item?.onClick()}> + +
    • + ); + })} +
    +
    +
    + ); +} diff --git a/apps/web/lib/components/kanban-card.tsx b/apps/web/lib/components/kanban-card.tsx index cfab76262..19a71f50e 100644 --- a/apps/web/lib/components/kanban-card.tsx +++ b/apps/web/lib/components/kanban-card.tsx @@ -1,22 +1,17 @@ import { DraggableProvided } from 'react-beautiful-dnd'; import PriorityIcon from '@components/ui/svgs/priority-icon'; import { ITaskPriority, ITeamTask, Tag } from '@app/interfaces'; -import { - useAuthenticateUser, - useCollaborative, - useOrganizationTeams, - useTMCardTaskEdit, - useTaskStatistics, - useTeamMemberCard -} from '@app/hooks'; +import { useAuthenticateUser, useOrganizationTeams, useTaskStatistics, useTeamMemberCard } from '@app/hooks'; import ImageComponent, { ImageOverlapperProps } from './image-overlapper'; import { TaskAllStatusTypes, TaskInput, TaskIssueStatus } from 'lib/features'; import Link from 'next/link'; import CircularProgress from '@components/ui/svgs/circular-progress'; import { HorizontalSeparator } from './separator'; import { secondsToTime } from '@app/helpers'; -import { UserTeamCardMenu } from 'lib/features/team/user-team-card/user-team-card-menu'; import { TaskStatus } from '@app/constants'; +import MenuKanbanCard from '@components/pages/kanban/menu-kanban-card'; +import { activeTeamTaskId } from '@app/stores'; +import { useRecoilState } from 'recoil'; function getStyle(provided: DraggableProvided, style: any) { if (!style) { @@ -133,6 +128,7 @@ export default function Item(props: ItemProps) { const { activeTeam } = useOrganizationTeams(); const { user } = useAuthenticateUser(); const { getEstimation } = useTaskStatistics(0); + const [activeTask, setActiveTask] = useRecoilState(activeTeamTaskId); const members = activeTeam?.members || []; const currentUser = members.find((m) => m.employee.userId === user?.id); @@ -145,7 +141,6 @@ export default function Item(props: ItemProps) { }); const memberInfo = useTeamMemberCard(currentUser); - const taskEdition = useTMCardTaskEdit(memberInfo.memberTask); const taskAssignee: ImageOverlapperProps[] = item.members.map((member: any) => { return { @@ -154,9 +149,7 @@ export default function Item(props: ItemProps) { alt: member.user.firstName }; }); - const { collaborativeSelect } = useCollaborative(memberInfo.memberUser); - const menu = <>{!collaborativeSelect && }; const progress = getEstimation(null, item, totalWorkedTasksTimer || 1, item.estimate || 0); const currentMember = activeTeam?.members.find((member) => member.id === memberInfo.member?.id || item?.id); @@ -183,11 +176,13 @@ export default function Item(props: ItemProps) { - {menu} + + +
    - {!taskEdition.editMode ? ( + {activeTask?.id !== item.id ? ( <>
    @@ -214,7 +209,7 @@ export default function Item(props: ItemProps) { ) : (
    { - taskEdition.setEditMode(false); + setActiveTask({ id: '' }); }} />
    diff --git a/apps/web/lib/features/task/task-input-kanban.tsx b/apps/web/lib/features/task/task-input-kanban.tsx index 9d3a46d44..f87d3fd1f 100644 --- a/apps/web/lib/features/task/task-input-kanban.tsx +++ b/apps/web/lib/features/task/task-input-kanban.tsx @@ -92,8 +92,7 @@ export function TaskInputKanban(props: Props) { setQuery, updateLoading, updateTaskTitleHandler, - setFilter, - taskIssue + setFilter } = datas; const inputTaskTitle = useMemo(() => inputTask?.title || '', [inputTask?.title]); @@ -153,7 +152,6 @@ export function TaskInputKanban(props: Props) { If task is passed then we don't want to set the active task for the authenticated user. after task creation */ - const autoActiveTask = props.task !== undefined ? false : true; const handleTaskCreation = useCallback(async () => { /* Checking if the `handleTaskCreation` is available and if the `hasCreateForm` is true. */ datas && @@ -171,7 +169,7 @@ export function TaskInputKanban(props: Props) { props.onClose && props.onClose(); }); - }, [datas, taskIssue, autoActiveTask, props.autoAssignTaskAuth, props.usersTaskCreatedAssignTo, onTaskCreated]); + }, [datas, props, onTaskCreated]); let updatedTaskList: ITeamTask[] = []; if (props.forParentChildRelationship) { From 1e564212789919a7cd11961aa7d1802cf4384962 Mon Sep 17 00:00:00 2001 From: Paradoxe Ng Date: Fri, 3 May 2024 12:00:41 +0200 Subject: [PATCH 20/21] UI fixes (#2476) * build(deps): update yarn.lock * Optimize hook memoization and passcode integration * Refactor signInWorkspaceAPI to accept params object * fixed(#2418): Delayed Loading of Profile Image on Member Profile Page * fixed(#2419): Incorrect z-index on Edit Menu in Members List Card * fixed(#2420): Insufficient Width for Task Type Issue Menu Dropdown * fixed(#2421): Inconsistent Button Styling for Task Title Edit Mode * fixed(#2422): Inconsistent Label Display and Text Wrapping for Start Date * fixed(#2423): Automatically Select the Latest Task Version After Creation * fixed build error * fixed(#2424): Add Title Attribute for Truncated or Cut-off Text * fixed(#2425): Inconsistent Text Size for Task Status Display --- .../hooks/auth/useAuthenticationPasscode.ts | 19 +++----- .../hooks/auth/useAuthenticationPassword.ts | 2 +- apps/web/app/hooks/features/useTaskVersion.ts | 6 +-- apps/web/app/hooks/features/useTeamTasks.ts | 10 +++- apps/web/app/services/client/api/auth.ts | 17 ++++--- .../details-section/blocks/task-main-info.tsx | 29 +++++++----- .../details-section/blocks/task-publicity.tsx | 46 ++++++++----------- .../blocks/task-secondary-info.tsx | 8 ++-- .../components/profile-info-with-time.tsx | 1 + .../components/profile-info.tsx | 5 +- .../task/title-block/task-title-block.tsx | 4 +- apps/web/lib/components/inputs/input.tsx | 6 ++- apps/web/lib/features/task/task-input.tsx | 7 +-- apps/web/lib/features/task/task-issue.tsx | 13 ++++-- apps/web/lib/features/task/task-status.tsx | 15 +++--- .../user-team-block/user-team-card-menu.tsx | 2 +- .../user-team-card/user-team-card-menu.tsx | 2 +- apps/web/lib/settings/version-form.tsx | 8 ++-- 18 files changed, 108 insertions(+), 92 deletions(-) diff --git a/apps/web/app/hooks/auth/useAuthenticationPasscode.ts b/apps/web/app/hooks/auth/useAuthenticationPasscode.ts index 986a9c46c..91b76cd8b 100644 --- a/apps/web/app/hooks/auth/useAuthenticationPasscode.ts +++ b/apps/web/app/hooks/auth/useAuthenticationPasscode.ts @@ -23,9 +23,8 @@ type AuthCodeRef = { export function useAuthenticationPasscode() { const pathname = usePathname(); const query = useSearchParams(); - const queryTeamId = useMemo(() => { - return query?.get('teamId'); - }, [query]); + + const queryTeamId = query?.get('teamId'); const queryEmail = useMemo(() => { const emailQuery = query?.get('email') || ''; @@ -110,6 +109,7 @@ export function useAuthenticationPasscode() { signInToWorkspaceRequest({ email: email, + code: code, token: currentWorkspace?.token as string, selectedTeam: queryTeamId as string }); @@ -156,16 +156,8 @@ export function useAuthenticationPasscode() { [queryCall] ); - const signInToWorkspaceRequest = ({ - email, - token, - selectedTeam - }: { - email: string; - token: string; - selectedTeam: string; - }) => { - signInWorkspaceQueryCall(email, token, selectedTeam) + const signInToWorkspaceRequest = (params: { email: string; token: string; selectedTeam: string; code: string }) => { + signInWorkspaceQueryCall(params) .then(() => { setAuthenticated(true); router.push('/'); @@ -227,6 +219,7 @@ export function useAuthenticationPasscode() { signInToWorkspaceRequest({ email: formValues.email, + code: formValues.code, token, selectedTeam }); diff --git a/apps/web/app/hooks/auth/useAuthenticationPassword.ts b/apps/web/app/hooks/auth/useAuthenticationPassword.ts index 4c8fe64d2..b553b24aa 100644 --- a/apps/web/app/hooks/auth/useAuthenticationPassword.ts +++ b/apps/web/app/hooks/auth/useAuthenticationPassword.ts @@ -87,7 +87,7 @@ export function useAuthenticationPassword() { token: string; selectedTeam: string; }) => { - signInWorkspaceQueryCall(email, token, selectedTeam) + signInWorkspaceQueryCall({ email, token, selectedTeam, code: '' }) .then(() => { setAuthenticated(true); router.push('/'); diff --git a/apps/web/app/hooks/features/useTaskVersion.ts b/apps/web/app/hooks/features/useTaskVersion.ts index f96044907..f4e8694ca 100644 --- a/apps/web/app/hooks/features/useTaskVersion.ts +++ b/apps/web/app/hooks/features/useTaskVersion.ts @@ -14,10 +14,9 @@ import { useRecoilState, useRecoilValue } from 'recoil'; import { useFirstLoad } from '../useFirstLoad'; import { useQuery } from '../useQuery'; import isEqual from 'lodash/isEqual'; -import { useCallbackRef } from '../useCallbackRef'; import { getActiveTeamIdCookie } from '@app/helpers'; -export function useTaskVersion(onVersionCreated?: (version: ITaskVersionCreate) => void) { +export function useTaskVersion() { const [user] = useRecoilState(userState); const activeTeamId = useRecoilValue(activeTeamIdState); @@ -27,7 +26,6 @@ export function useTaskVersion(onVersionCreated?: (version: ITaskVersionCreate) const { loading: editTaskVersionLoading, queryCall: editQueryCall } = useQuery(editTaskVersionAPI); const [taskVersion, setTaskVersion] = useRecoilState(taskVersionListState); - const $onVersionCreated = useCallbackRef(onVersionCreated); const [taskVersionFetching, setTaskVersionFetching] = useRecoilState(taskVersionFetchingState); const { firstLoadData: firstLoadTaskVersionData, firstLoad } = useFirstLoad(); @@ -68,7 +66,7 @@ export function useTaskVersion(onVersionCreated?: (version: ITaskVersionCreate) } }, - [$onVersionCreated, createQueryCall, createTaskVersionLoading, deleteTaskVersionLoading, activeTeamId] + [createQueryCall, createTaskVersionLoading, deleteTaskVersionLoading, activeTeamId] ); const deleteTaskVersion = useCallback( diff --git a/apps/web/app/hooks/features/useTeamTasks.ts b/apps/web/app/hooks/features/useTeamTasks.ts index e8dace649..d0735f62c 100644 --- a/apps/web/app/hooks/features/useTeamTasks.ts +++ b/apps/web/app/hooks/features/useTeamTasks.ts @@ -74,6 +74,12 @@ export function useTeamTasks() { const getTaskById = useCallback( (taskId: string) => { + tasksRef.current.forEach((task) => { + if (task.id === taskId) { + setDetailedTask(task); + } + }); + return getTasksByIdQueryCall(taskId).then((res) => { setDetailedTask(res?.data || null); return res; @@ -246,11 +252,11 @@ export function useTeamTasks() { ...(activeTeam?.projects && activeTeam?.projects.length > 0 ? { projectId: activeTeam.projects[0].id - } + } : {}), ...(description ? { description: `

    ${description}

    ` } : {}), ...(members ? { members } : {}), - taskStatusId: taskStatusId, + taskStatusId: taskStatusId }, $user.current ).then((res) => { diff --git a/apps/web/app/services/client/api/auth.ts b/apps/web/app/services/client/api/auth.ts index d6cec2346..3758550c5 100644 --- a/apps/web/app/services/client/api/auth.ts +++ b/apps/web/app/services/client/api/auth.ts @@ -26,7 +26,7 @@ export const getAuthenticatedUserDataAPI = () => { // Construct the query string with 'qs', including the includeEmployee parameter const query = qs.stringify({ relations: relations, - includeEmployee: true // Append includeEmployee parameter set to true + includeEmployee: true // Append includeEmployee parameter set to true }); // Execute the GET request to fetch the user data @@ -130,15 +130,20 @@ export async function signInEmailConfirmAPI(email: string, code: string) { }); } -export const signInWorkspaceAPI = (email: string, token: string, selectedTeam: string) => { +export const signInWorkspaceAPI = (params: { email: string; token: string; selectedTeam: string; code: string }) => { if (GAUZY_API_BASE_SERVER_URL.value) { - return signInWorkspaceGauzy({ email, token, teamId: selectedTeam, code: 'sign-in-workspace' }); + return signInWorkspaceGauzy({ + email: params.email, + token: params.token, + teamId: params.selectedTeam, + code: params.code + }); } return api.post(`/auth/signin-workspace`, { - email, - token, - teamId: selectedTeam + email: params.email, + token: params.token, + teamId: params.selectedTeam }); }; diff --git a/apps/web/components/pages/task/details-section/blocks/task-main-info.tsx b/apps/web/components/pages/task/details-section/blocks/task-main-info.tsx index 84de7e04c..23b320fc5 100644 --- a/apps/web/components/pages/task/details-section/blocks/task-main-info.tsx +++ b/apps/web/components/pages/task/details-section/blocks/task-main-info.tsx @@ -15,6 +15,7 @@ import TaskRow from '../components/task-row'; import { DatePicker } from 'components/ui/DatePicker'; import Link from 'next/link'; import { useTranslations } from 'next-intl'; +import { PencilSquareIcon } from '@heroicons/react/20/solid'; const TaskMainInfo = () => { const [task] = useRecoilState(detailedTaskState); @@ -115,11 +116,13 @@ function DueDates() { 'leading-[140%] tracking-[-0.02em] text-[#282048] dark:text-white' )} > - {startDate - ? formatDateString(startDate.toISOString()) - : task?.startDate - ? formatDateString(task?.startDate) - : 'Set Start Date'} + {startDate ? ( + formatDateString(startDate.toISOString()) + ) : task?.startDate ? ( + formatDateString(task?.startDate) + ) : ( + + )}
    } selected={$startDate.current ? (new Date($startDate.current) as Date) : undefined} @@ -161,11 +164,13 @@ function DueDates() { 'leading-[140%] tracking-[-0.02em] text-[#282048] dark:text-white' )} > - {dueDate - ? formatDateString(dueDate.toISOString()) - : task?.dueDate - ? formatDateString(task?.dueDate) - : 'Set Due Date'} + {dueDate ? ( + formatDateString(dueDate.toISOString()) + ) : task?.dueDate ? ( + formatDateString(task?.dueDate) + ) : ( + + )}
    } selected={$dueDate.current ? (new Date($dueDate.current) as Date) : undefined} @@ -220,7 +225,7 @@ const ManageMembersPopover = (memberList: OT_Member[], task: ITeamTask | null) = memberList.filter((member) => member.employee ? !task?.members.map((item) => item.userId).includes(member.employee.userId) && - member.employee?.isActive + member.employee?.isActive : false ), [memberList, task?.members] @@ -231,7 +236,7 @@ const ManageMembersPopover = (memberList: OT_Member[], task: ITeamTask | null) = memberList.filter((member) => member.employee ? task?.members.map((item) => item.userId).includes(member.employee?.userId) && - member.employee?.isActive + member.employee?.isActive : false ), [memberList, task?.members] diff --git a/apps/web/components/pages/task/details-section/blocks/task-publicity.tsx b/apps/web/components/pages/task/details-section/blocks/task-publicity.tsx index 6911e6316..2945f3a0a 100644 --- a/apps/web/components/pages/task/details-section/blocks/task-publicity.tsx +++ b/apps/web/components/pages/task/details-section/blocks/task-publicity.tsx @@ -5,7 +5,7 @@ import { debounce } from 'lodash'; import { useCallback, useEffect, useState } from 'react'; import { useRecoilState } from 'recoil'; import { useTranslations } from 'next-intl'; -import { GlobeIcon,LockIcon } from 'assets/svg'; +import { GlobeIcon, LockIcon } from 'assets/svg'; const TaskPublicity = () => { const [task] = useRecoilState(detailedTaskState); @@ -36,33 +36,27 @@ const TaskPublicity = () => { 'details-label px-4 flex justify-between' )} > - {isTaskPublic ? ( - <> -
    +
    + {!isTaskPublic && ( + <> + +

    {t('common.PRIVATE_TASK')}

    + + )} + + {isTaskPublic && ( + <>

    {t('common.PUBLIC_TASK')}

    -
    -
    handlePublicity(false)} - className="flex items-center cursor-pointer text-[0.625rem] 3xl:text-[0.700rem] text-[#A5A2B2]" - > - {t('common.PRIVATE_TASK_LABEL')} -
    - - ) : ( - <> -
    - -

    {t('common.PRIVATE_TASK')}

    -
    -
    handlePublicity(true)} - className="flex items-center cursor-pointer text-[0.625rem] text-[#A5A2B2]" - > - {t('common.PUBLIC_TASK_LABEL')} -
    - - )} + + )} +
    +
    handlePublicity(!isTaskPublic)} + className="flex items-center cursor-pointer text-[0.625rem] text-[#A5A2B2]" + > + {!isTaskPublic ? t('common.PUBLIC_TASK_LABEL') : t('common.PRIVATE_TASK_LABEL')} +
    ); }; diff --git a/apps/web/components/pages/task/details-section/blocks/task-secondary-info.tsx b/apps/web/components/pages/task/details-section/blocks/task-secondary-info.tsx index d2500a643..260d9f22e 100644 --- a/apps/web/components/pages/task/details-section/blocks/task-secondary-info.tsx +++ b/apps/web/components/pages/task/details-section/blocks/task-secondary-info.tsx @@ -50,9 +50,7 @@ const TaskSecondaryInfo = () => { const onVersionCreated = useCallback( (version: ITaskVersionCreate) => { - if ($taskVersion.current.length === 0) { - handleStatusUpdate(version.value || version.name, 'version', task); - } + handleStatusUpdate(version.value || version.name, 'version', task); }, [$taskVersion, task, handleStatusUpdate] ); @@ -72,6 +70,7 @@ const TaskSecondaryInfo = () => { ); const taskLabels = useTaskLabelsValue(); + const tags = useMemo(() => { return ( task?.tags @@ -120,6 +119,7 @@ const TaskSecondaryInfo = () => { /> )} + {task && } {/* Task Status */} @@ -235,7 +235,7 @@ const EpicParent = ({ task }: { task: ITeamTask }) => {
    - , +
    {`#${task?.rootEpic?.number} ${task?.rootEpic?.title}`}
    diff --git a/apps/web/components/pages/task/details-section/components/profile-info-with-time.tsx b/apps/web/components/pages/task/details-section/components/profile-info-with-time.tsx index fb2cbd0cf..44137a048 100644 --- a/apps/web/components/pages/task/details-section/components/profile-info-with-time.tsx +++ b/apps/web/components/pages/task/details-section/components/profile-info-with-time.tsx @@ -15,6 +15,7 @@ const ProfileInfoWithTime = ({ profilePicSrc, names, profileInfoWrapperClassName diff --git a/apps/web/components/pages/task/details-section/components/profile-info.tsx b/apps/web/components/pages/task/details-section/components/profile-info.tsx index 3a8aba4be..e6fc77302 100644 --- a/apps/web/components/pages/task/details-section/components/profile-info.tsx +++ b/apps/web/components/pages/task/details-section/components/profile-info.tsx @@ -8,15 +8,16 @@ import stc from 'string-to-color'; type Props = { profilePicSrc?: string; names?: string; + fullName?: string; wrapperClassName?: string; profilePicSize?: number; }; -const ProfileInfo = ({ profilePicSrc, names, wrapperClassName, profilePicSize }: Props) => { +const ProfileInfo = ({ profilePicSrc, fullName, names, wrapperClassName, profilePicSize }: Props) => { const size = profilePicSize || 20; return ( -
    +
    { onClick={() => saveTitle(title)} className="border-2 dark:border-[#464242] rounded-md" > - +
    ) : ( diff --git a/apps/web/lib/components/inputs/input.tsx b/apps/web/lib/components/inputs/input.tsx index de5e9d690..fc76d885f 100644 --- a/apps/web/lib/components/inputs/input.tsx +++ b/apps/web/lib/components/inputs/input.tsx @@ -125,7 +125,7 @@ type ITimeProps = { export const TimeInputField = forwardRef( ({ className, type = 'text', label, dash = '__', wrapperClassName, value, loading, ...res }, ref) => { return ( -
    +
    ( /> {dash}
    - {!loading ? label : } + + {loading && } + {!loading && {label} }
    ); } diff --git a/apps/web/lib/features/task/task-input.tsx b/apps/web/lib/features/task/task-input.tsx index 77d95bc96..6cffe7fe4 100644 --- a/apps/web/lib/features/task/task-input.tsx +++ b/apps/web/lib/features/task/task-input.tsx @@ -107,7 +107,7 @@ export function TaskInput(props: Props) { setQuery, updateLoading, updateTaskTitleHandler, - setFilter, + setFilter } = datas; const inputTaskTitle = useMemo(() => inputTask?.title || '', [inputTask?.title]); @@ -265,6 +265,7 @@ export function TaskInput(props: Props) { setEditMode(false); } }, [setEditMode, editMode, targetEl]); + useHotkeys(HostKeys.CREATE_TASK, handleCommandKeySequence); useEffect(() => { @@ -367,7 +368,7 @@ export function TaskInput(props: Props) { return viewType === 'one-view' ? ( taskCard ) : ( - + {inputField} -
    +
    {/* Create team button */}
    {datas.hasCreateForm && ( diff --git a/apps/web/lib/features/task/task-issue.tsx b/apps/web/lib/features/task/task-issue.tsx index 2925df597..c68719934 100644 --- a/apps/web/lib/features/task/task-issue.tsx +++ b/apps/web/lib/features/task/task-issue.tsx @@ -19,22 +19,26 @@ export const taskIssues: TStatus = { Bug: { icon: , name: 'Bug', - bgColor: '#923535' + bgColor: '#923535', + className: 'min-w-[5rem]' }, Task: { icon: , name: 'Task', - bgColor: '#5483BA' + bgColor: '#5483BA', + className: 'min-w-[5rem]' }, Story: { icon: , name: 'Story', - bgColor: '#66BB97' + bgColor: '#66BB97', + className: 'min-w-[5rem]' }, Epic: { icon: , name: 'Custom', - bgColor: '#8154BA' + bgColor: '#8154BA', + className: 'min-w-[5rem]' } }; @@ -103,6 +107,7 @@ export function ActiveTaskIssuesDropdown({ ...props }: IActiveTaskStatuses<'issu [IssueType.BUG]: items.filter((it) => [IssueType.STORY, IssueType.TASK].includes(it.value as IssueType)) }; + let updatedItemsBasedOnTaskIssueType: TStatusItem[] = []; if (props.task && props.task?.issueType && props.task.parent) { diff --git a/apps/web/lib/features/task/task-status.tsx b/apps/web/lib/features/task/task-status.tsx index 58b0eae4e..7e4617b03 100644 --- a/apps/web/lib/features/task/task-status.tsx +++ b/apps/web/lib/features/task/task-status.tsx @@ -42,6 +42,7 @@ export type TStatusItem = { value?: string; bordered?: boolean; showIcon?: boolean; + className?: string; }; export type TStatus = { @@ -824,11 +825,12 @@ export function TaskStatus({ {name && (issueType !== 'issue' || showIssueLabels) && (
    @@ -985,8 +987,7 @@ export function StatusDropdown({ 'text-dark dark:text-white bg-[#F2F2F2] dark:bg-dark--theme-light', forDetails && 'bg-transparent border dark:border-[#FFFFFF33] dark:bg-[#1B1D22]', - taskStatusClassName, - 'max-w-10' + taskStatusClassName )} name={ values.length > 0 @@ -1023,6 +1024,7 @@ export function StatusDropdown({ > {items.map((item, i) => { const item_value = item.value || item.name; + return ( ({ issueType === 'issue' && [ 'rounded-md px-2 text-white' ], - `${sidebarUI ? 'rounded-[4px]' : ''}`, - `${bordered ? 'input-border' : ''}`, - (isVersion || isEpic) && 'dark:text-white' + sidebarUI && 'rounded-[4px]', + bordered && 'input-border', + (isVersion || isEpic) && 'dark:text-white', + item?.className )} /> diff --git a/apps/web/lib/features/team/user-team-block/user-team-card-menu.tsx b/apps/web/lib/features/team/user-team-block/user-team-card-menu.tsx index 98564efe1..fc7e9cb62 100644 --- a/apps/web/lib/features/team/user-team-block/user-team-card-menu.tsx +++ b/apps/web/lib/features/team/user-team-block/user-team-card-menu.tsx @@ -103,7 +103,7 @@ function DropdownMenu({ edition, memberInfo }: Props) { leave="transition duration-75 ease-out" leaveFrom="transform scale-100 opacity-100" leaveTo="transform scale-95 opacity-0" - className="absolute z-10 -right-5 min-w-[13.125rem]" + className="absolute z-30 -right-5 min-w-[13.125rem]" > {({ close }) => { 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 358c4ac20..a6dc4c52d 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 @@ -103,7 +103,7 @@ function DropdownMenu({ edition, memberInfo }: Props) { leave="transition duration-75 ease-out" leaveFrom="transform scale-100 opacity-100" leaveTo="transform scale-95 opacity-0" - className="absolute z-10 -right-5 min-w-[13.125rem]" + className="absolute z-30 -right-5 min-w-[13.125rem]" > {({ close }) => { diff --git a/apps/web/lib/settings/version-form.tsx b/apps/web/lib/settings/version-form.tsx index f97e82671..feaf8b2f0 100644 --- a/apps/web/lib/settings/version-form.tsx +++ b/apps/web/lib/settings/version-form.tsx @@ -1,7 +1,7 @@ import { Button, InputField, Text } from 'lib/components'; import { StatusesListCard } from './list-card'; -import { useTaskVersion } from '@app/hooks'; +import { useCallbackRef, useTaskVersion } from '@app/hooks'; import { ITaskVersionCreate, ITaskVersionItemList } from '@app/interfaces'; import { userState } from '@app/stores'; import { Spinner } from '@components/ui/loaders/spinner'; @@ -27,6 +27,7 @@ export const VersionForm = ({ formOnly = false, onCreated, onVersionCreated }: S const { register, setValue, handleSubmit, reset, getValues } = useForm(); const [createNew, setCreateNew] = useState(formOnly); const [edit, setEdit] = useState(null); + const $onVersionCreated = useCallbackRef(onVersionCreated); const { loading, @@ -36,7 +37,7 @@ export const VersionForm = ({ formOnly = false, onCreated, onVersionCreated }: S editTaskVersion, createTaskVersionLoading, editTaskVersionLoading - } = useTaskVersion(onVersionCreated); + } = useTaskVersion(); const { refetch } = useRefetchData(); useEffect(() => { @@ -64,10 +65,11 @@ export const VersionForm = ({ formOnly = false, onCreated, onVersionCreated }: S tenantId: user?.tenantId // icon: values.icon, // projectId: '', - })?.then(() => { + })?.then(({ data }) => { !formOnly && setCreateNew(false); onCreated && onCreated(); + $onVersionCreated.current && $onVersionCreated.current(data); refetch(); reset(); }); From d102cb0af382c2edbf868de15d1a3abcf784a4e3 Mon Sep 17 00:00:00 2001 From: Ushindi Gedeon Date: Fri, 3 May 2024 15:07:05 +0200 Subject: [PATCH 21/21] [Improvement] add translations for the 'Not found' messages (#2475) * [Improvement] add translatioins for the 'Not found' messages * Remove unnecessary text --- apps/web/components/pages/404/index.tsx | 4 +++- apps/web/lib/components/Kanban.tsx | 2 +- apps/web/messages/ar.json | 2 ++ apps/web/messages/bg.json | 2 ++ apps/web/messages/de.json | 2 ++ apps/web/messages/en.json | 2 ++ apps/web/messages/es.json | 2 ++ apps/web/messages/fr.json | 2 ++ apps/web/messages/he.json | 2 ++ apps/web/messages/it.json | 2 ++ apps/web/messages/nl.json | 2 ++ apps/web/messages/pl.json | 2 ++ apps/web/messages/pt.json | 4 +++- apps/web/messages/ru.json | 2 ++ apps/web/messages/zh.json | 2 ++ apps/web/public/locales/ar/common.json | 2 ++ apps/web/public/locales/bg/common.json | 2 ++ apps/web/public/locales/de/common.json | 2 ++ apps/web/public/locales/en/common.json | 2 ++ apps/web/public/locales/es/common.json | 2 ++ apps/web/public/locales/fr/common.json | 2 ++ apps/web/public/locales/he/common.json | 2 ++ apps/web/public/locales/it/common.json | 2 ++ apps/web/public/locales/nl/common.json | 2 ++ apps/web/public/locales/pl/common.json | 2 ++ apps/web/public/locales/pt/common.json | 2 ++ apps/web/public/locales/ru/common.json | 2 ++ apps/web/public/locales/zh/common.json | 2 ++ 28 files changed, 57 insertions(+), 3 deletions(-) diff --git a/apps/web/components/pages/404/index.tsx b/apps/web/components/pages/404/index.tsx index a26d8643a..6ed5f7686 100644 --- a/apps/web/components/pages/404/index.tsx +++ b/apps/web/components/pages/404/index.tsx @@ -2,8 +2,10 @@ import SadCry from '@components/ui/svgs/sad-cry'; import { Button, Text } from 'lib/components'; import Link from 'next/link'; +import { useTranslations } from 'next-intl'; function NotFound() { + const t = useTranslations(); return (
    @@ -12,7 +14,7 @@ function NotFound() {
    - Page not found ! + {t('common.PAGE_NOT_FOUND')}
    diff --git a/apps/web/lib/components/Kanban.tsx b/apps/web/lib/components/Kanban.tsx index 5f3600047..70aac0ad4 100644 --- a/apps/web/lib/components/Kanban.tsx +++ b/apps/web/lib/components/Kanban.tsx @@ -98,7 +98,7 @@ function InnerItemList({ items, title }: { title: string; items: ITeamTask[]; dr {Array.isArray(items) && items?.length == 0 && (
    - not found! + {t('common.NOT_FOUND')}!