From a60ac2a4329b7fd75b8cf94ba317d8b591710f11 Mon Sep 17 00:00:00 2001 From: Vinay Badgujar Date: Thu, 17 Oct 2024 15:05:10 +0530 Subject: [PATCH 01/22] basic taskhistorycollection added --- src/api/TaskHistoryAPI/index.ts | 21 +++++++++++++++++++ .../MyTimeline/MyTimeline.tsx | 6 +++++- src/models/TaskHistoryItem.ts | 11 ++++++++++ src/models/db.ts | 3 +++ src/models/dexie.ts | 1 + 5 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 src/api/TaskHistoryAPI/index.ts create mode 100644 src/models/TaskHistoryItem.ts diff --git a/src/api/TaskHistoryAPI/index.ts b/src/api/TaskHistoryAPI/index.ts new file mode 100644 index 000000000..9a10bff61 --- /dev/null +++ b/src/api/TaskHistoryAPI/index.ts @@ -0,0 +1,21 @@ +import { db } from "@src/models"; +import { TaskHistoryEvents, TaskHistoryItem } from "@src/models/TaskHistoryItem"; +import { ITask } from "@src/Interfaces/Task"; + +import { v4 as uuidv4 } from "uuid"; + +export async function addTaskActionEvent(task: ITask, eventType: TaskHistoryEvents) { + if (!task) return; + + const newEvent: TaskHistoryItem = { + id: uuidv4(), + goalId: task.goalid, + eventType, + duration: task.duration, + scheduledStart: task.start, + scheduledEnd: task.deadline, + eventTime: new Date().toLocaleDateString(), + }; + + await db.taskHistoryCollection.add(newEvent); +} diff --git a/src/components/MyTimeComponents/MyTimeline/MyTimeline.tsx b/src/components/MyTimeComponents/MyTimeline/MyTimeline.tsx index 3729a26a8..328253277 100644 --- a/src/components/MyTimeComponents/MyTimeline/MyTimeline.tsx +++ b/src/components/MyTimeComponents/MyTimeline/MyTimeline.tsx @@ -2,7 +2,7 @@ /* eslint-disable jsx-a11y/control-has-associated-label */ /* eslint-disable react/jsx-key */ import { v4 as uuidv4 } from "uuid"; -import React, { useEffect, useState } from "react"; +import React, { act, useEffect, useState } from "react"; import { useLocation, useNavigate } from "react-router-dom"; import { useSetRecoilState } from "recoil"; @@ -22,6 +22,7 @@ import { displayReschedule } from "@src/store/TaskState"; import { GoalTiming } from "./GoalTiming"; import { TaskOptions } from "./TaskOptions"; import { updateImpossibleGoals } from "./updateImpossibleGoals"; +import { addTaskActionEvent } from "@src/api/TaskHistoryAPI"; type ImpossibleTaskId = string; @@ -96,6 +97,9 @@ export const MyTimeline: React.FC = ({ day, myTasks, taskDetail if (actionName === TaskAction.Focus) { return handleFocusClick(task); } + if (actionName === TaskAction.Done) { + await addTaskActionEvent(task, "completed"); + } if (day === "Today") { const taskItem = await getTaskByGoalId(task.goalid); if (!taskItem) { diff --git a/src/models/TaskHistoryItem.ts b/src/models/TaskHistoryItem.ts new file mode 100644 index 000000000..4eff4ddf6 --- /dev/null +++ b/src/models/TaskHistoryItem.ts @@ -0,0 +1,11 @@ +export type TaskHistoryEvents = "completed" | "postponed" | "skipped"; + +export interface TaskHistoryItem { + id: string; + goalId: string; + eventType: TaskHistoryEvents; + scheduledStart: string; + scheduledEnd: string; + eventTime: string; + duration: number; +} diff --git a/src/models/db.ts b/src/models/db.ts index 6b5865a6a..656847f11 100644 --- a/src/models/db.ts +++ b/src/models/db.ts @@ -12,6 +12,7 @@ import { TrashItem } from "./TrashItem"; import { HintItem } from "./HintItem"; import { ImpossibleGoalItem } from "./ImpossibleGoalItem"; import { dbStoreSchema, syncVersion } from "./dexie"; +import { TaskHistoryItem } from "./TaskHistoryItem"; export const dexieVersion = 21; @@ -41,6 +42,8 @@ export class ZinZenDB extends Dexie { impossibleGoalsCollection!: Table; + taskHistoryCollection!: Table; + constructor() { super("ZinZenDB"); this.version(dexieVersion) diff --git a/src/models/dexie.ts b/src/models/dexie.ts index 423927085..56aad9732 100644 --- a/src/models/dexie.ts +++ b/src/models/dexie.ts @@ -24,6 +24,7 @@ export const dbStoreSchema = { "id, category, deletedAt, title, duration, sublist, habit, on, start, due, afterTime, beforeTime, createdAt, parentGoalId, archived, participants, goalColor, language, link, rootGoalId, timeBudget, typeOfGoal", hintsCollection: "id, hintOptionEnabled, availableGoalHints, lastCheckedDate, nextCheckDate", impossibleGoalsCollection: "goalId, goalTitle", + taskHistoryCollection: "id, goalId, action, eventTime, scheduledStart, scheduledEnd, duration", }; export const syncVersion = (transaction: Transaction, currentVersion: number) => { if (currentVersion < 9) { From 87852d38976ee3be478f8f8fc179f0819a21159b Mon Sep 17 00:00:00 2001 From: Vinay Badgujar Date: Fri, 18 Oct 2024 15:54:25 +0530 Subject: [PATCH 02/22] create taskdonetoday collection to specifically handle tasks that are completed today only --- src/api/TasksAPI/index.ts | 21 +++++++++++ src/api/TasksDoneTodayAPI/index.ts | 35 +++++++++++++++++++ .../MyTimeline/MyTimeline.tsx | 7 ++-- src/helpers/MyTimeHelper.ts | 14 ++++++-- src/models/TasksDoneTodayItem.ts | 7 ++++ src/models/db.ts | 3 ++ src/models/dexie.ts | 1 + 7 files changed, 80 insertions(+), 8 deletions(-) create mode 100644 src/api/TasksDoneTodayAPI/index.ts create mode 100644 src/models/TasksDoneTodayItem.ts diff --git a/src/api/TasksAPI/index.ts b/src/api/TasksAPI/index.ts index a041cde00..3d6a9c497 100644 --- a/src/api/TasksAPI/index.ts +++ b/src/api/TasksAPI/index.ts @@ -7,6 +7,8 @@ import { convertDateToDay } from "@src/utils/SchedulerUtils"; import { ITask } from "@src/Interfaces/Task"; import { ISchedulerInputGoal } from "@src/Interfaces/IScheduler"; import { getGoal } from "../GoalsAPI"; +import { v4 as uuidv4 } from "uuid"; +import { addTaskDoneToday } from "../TasksDoneTodayAPI"; export const addTask = async (taskDetails: TaskItem) => { let newTaskId; @@ -125,6 +127,25 @@ export const completeTask = async (id: string, duration: number, task: ITask) => }); }; +export const newCompleteTask = async ( + scheduledTaskId: string, + goalId: string, + scheduledStart: string, + scheduledEnd: string, +) => { + try { + await addTaskDoneToday({ + id: uuidv4(), + scheduledTaskId, + goalId, + scheduledStart, + scheduledEnd, + }); + } catch (error) { + console.log(error); + } +}; + export const skipTask = async (id: string, period: string, task: ITask) => { db.transaction("rw", db.taskCollection, async () => { await db.taskCollection diff --git a/src/api/TasksDoneTodayAPI/index.ts b/src/api/TasksDoneTodayAPI/index.ts new file mode 100644 index 000000000..594b4a0cd --- /dev/null +++ b/src/api/TasksDoneTodayAPI/index.ts @@ -0,0 +1,35 @@ +import { db } from "@src/models"; +import { TasksDoneTodayItem } from "@src/models/TasksDoneTodayItem"; + +export const addTaskDoneToday = async (completedTask: TasksDoneTodayItem) => { + await db.tasksDoneTodayCollection.add(completedTask); +}; + +export const getTaskDoneTodayByTaskId = async (taskId: string) => { + const task = await db.tasksDoneTodayCollection.where("taskId").equals(taskId).first(); + if (task) { + return task; + } + return false; +}; + +export const isTaskDoneToday = async (taskId: string) => { + const task = await getTaskDoneTodayByTaskId(taskId); + if (task) { + return true; + } + return false; +}; + +export const getAllTasksDoneToday = async () => { + const tasks = await db.tasksDoneTodayCollection.toArray(); + return tasks; +}; + +export const deleteTaskDoneToday = async (id: string) => { + await db.tasksDoneTodayCollection.delete(id); +}; + +export const deleteAllTasksDoneToday = async () => { + await db.tasksDoneTodayCollection.clear(); +}; diff --git a/src/components/MyTimeComponents/MyTimeline/MyTimeline.tsx b/src/components/MyTimeComponents/MyTimeline/MyTimeline.tsx index 328253277..293b1deb4 100644 --- a/src/components/MyTimeComponents/MyTimeline/MyTimeline.tsx +++ b/src/components/MyTimeComponents/MyTimeline/MyTimeline.tsx @@ -15,7 +15,7 @@ import { TaskItem } from "@src/models/TaskItem"; import { GoalItem } from "@src/models/GoalItem"; import { useTranslation } from "react-i18next"; import { displayToast, focusTaskTitle } from "@src/store"; -import { addTask, completeTask, getTaskByGoalId } from "@src/api/TasksAPI"; +import { addTask, getTaskByGoalId, newCompleteTask } from "@src/api/TasksAPI"; import "./index.scss"; import { displayReschedule } from "@src/store/TaskState"; @@ -98,6 +98,7 @@ export const MyTimeline: React.FC = ({ day, myTasks, taskDetail return handleFocusClick(task); } if (actionName === TaskAction.Done) { + await newCompleteTask(task.taskid, task.goalid, task.start, task.deadline); await addTaskActionEvent(task, "completed"); } if (day === "Today") { @@ -127,10 +128,6 @@ export const MyTimeline: React.FC = ({ day, myTasks, taskDetail : [], blockedSlots: [], }); - } else if (actionName === TaskAction.Done) { - const markDone = !!taskDetails[task.goalid]?.completedTodayIds.includes(task.taskid); - if (markDone) return null; - await completeTask(taskItem.id, Number(task.duration), task); } else if (actionName === TaskAction.NotNow) { setOpenReschedule(task); } diff --git a/src/helpers/MyTimeHelper.ts b/src/helpers/MyTimeHelper.ts index db87668eb..5fd10902a 100644 --- a/src/helpers/MyTimeHelper.ts +++ b/src/helpers/MyTimeHelper.ts @@ -10,6 +10,7 @@ import { ITaskOfDay } from "@src/Interfaces/Task"; import { addSchedulerRes, getFromOutbox, updateSchedulerCachedRes } from "@src/api/DumpboxAPI"; import { getAllGoals } from "@src/api/GoalsAPI"; import { getAllTasks, getAllBlockedTasks, adjustNotOnBlocks } from "@src/api/TasksAPI"; +import { getAllTasksDoneToday } from "@src/api/TasksDoneTodayAPI"; import { GoalItem } from "@src/models/GoalItem"; import { TCompletedTaskTiming, TaskItem, blockedSlotOfTask } from "@src/models/TaskItem"; import { convertDateToString } from "@src/utils"; @@ -154,9 +155,16 @@ export const organizeDataForInptPrep = async (inputGoals: GoalItem[]) => { const startDate = convertDateToString(new Date(_today)); const endDate = convertDateToString(new Date(_today.setDate(_today.getDate() + 7))); const tasksCompletedToday: TCompletedTaskTiming[] = []; - getAllTasks().then((docs) => - docs.filter((doc) => doc.completedToday > 0).map((doc) => tasksCompletedToday.push(...doc.completedTodayTimings)), - ); + + getAllTasksDoneToday().then((task) => { + task.forEach((ele) => { + tasksCompletedToday.push({ + goalid: ele.goalId, + start: ele.scheduledStart, + deadline: ele.scheduledEnd, + }); + }); + }); const schedulerInput: ISchedulerInput = { startDate, diff --git a/src/models/TasksDoneTodayItem.ts b/src/models/TasksDoneTodayItem.ts new file mode 100644 index 000000000..9066cfb55 --- /dev/null +++ b/src/models/TasksDoneTodayItem.ts @@ -0,0 +1,7 @@ +export interface TasksDoneTodayItem { + id: string; + scheduledTaskId: string; + goalId: string; + scheduledStart: string; + scheduledEnd: string; +} diff --git a/src/models/db.ts b/src/models/db.ts index 656847f11..fea4a04c4 100644 --- a/src/models/db.ts +++ b/src/models/db.ts @@ -13,6 +13,7 @@ import { HintItem } from "./HintItem"; import { ImpossibleGoalItem } from "./ImpossibleGoalItem"; import { dbStoreSchema, syncVersion } from "./dexie"; import { TaskHistoryItem } from "./TaskHistoryItem"; +import { TasksDoneTodayItem } from "./TasksDoneTodayItem"; export const dexieVersion = 21; @@ -44,6 +45,8 @@ export class ZinZenDB extends Dexie { taskHistoryCollection!: Table; + tasksDoneTodayCollection!: Table; + constructor() { super("ZinZenDB"); this.version(dexieVersion) diff --git a/src/models/dexie.ts b/src/models/dexie.ts index 56aad9732..7227525f5 100644 --- a/src/models/dexie.ts +++ b/src/models/dexie.ts @@ -25,6 +25,7 @@ export const dbStoreSchema = { hintsCollection: "id, hintOptionEnabled, availableGoalHints, lastCheckedDate, nextCheckDate", impossibleGoalsCollection: "goalId, goalTitle", taskHistoryCollection: "id, goalId, action, eventTime, scheduledStart, scheduledEnd, duration", + tasksDoneTodayCollection: "id, goalId, scheduledStart, scheduledEnd", }; export const syncVersion = (transaction: Transaction, currentVersion: number) => { if (currentVersion < 9) { From 83a02c44e22d3525cbeff9515d1a0d05f8adc9ec Mon Sep 17 00:00:00 2001 From: Vinay Badgujar Date: Fri, 18 Oct 2024 16:09:05 +0530 Subject: [PATCH 03/22] implement taskDoneToday colleciton cleanup --- src/api/TasksDoneTodayAPI/index.ts | 22 ++++++++++++++++++++++ src/hooks/useApp.tsx | 2 ++ 2 files changed, 24 insertions(+) diff --git a/src/api/TasksDoneTodayAPI/index.ts b/src/api/TasksDoneTodayAPI/index.ts index 594b4a0cd..d7d278104 100644 --- a/src/api/TasksDoneTodayAPI/index.ts +++ b/src/api/TasksDoneTodayAPI/index.ts @@ -33,3 +33,25 @@ export const deleteTaskDoneToday = async (id: string) => { export const deleteAllTasksDoneToday = async () => { await db.tasksDoneTodayCollection.clear(); }; + +export const checkAndCleanupDoneTodayCollection = async () => { + const tasks = await getAllTasksDoneToday(); + + if (tasks.length === 0) { + return; + } + + const firstTaskScheduledStart = new Date(tasks[0].scheduledStart); + const today = new Date(); + const isSameDay = (date1: Date, date2: Date): boolean => { + return ( + date1.getDate() === date2.getDate() && + date1.getMonth() === date2.getMonth() && + date1.getFullYear() === date2.getFullYear() + ); + }; + + if (!isSameDay(firstTaskScheduledStart, today)) { + await deleteAllTasksDoneToday(); + } +}; diff --git a/src/hooks/useApp.tsx b/src/hooks/useApp.tsx index 0a4f4ecda..42210b1a4 100644 --- a/src/hooks/useApp.tsx +++ b/src/hooks/useApp.tsx @@ -15,6 +15,7 @@ import { useSetRecoilState, useRecoilValue, useRecoilState } from "recoil"; import { scheduledHintCalls } from "@src/api/HintsAPI/ScheduledHintCall"; import { LocalStorageKeys } from "@src/constants/localStorageKeys"; import { checkAndCleanupTrash } from "@src/api/TrashAPI"; +import { checkAndCleanupDoneTodayCollection } from "@src/api/TasksDoneTodayAPI"; const langFromStorage = localStorage.getItem(LocalStorageKeys.LANGUAGE)?.slice(1, -1); const exceptionRoutes = ["/", "/invest", "/feedback", "/donate"]; @@ -147,6 +148,7 @@ function useApp() { useEffect(() => { checkAndCleanupTrash(); + checkAndCleanupDoneTodayCollection(); }, []); useEffect(() => { From d7f6d2c0aaf915d55f9e8f2dcc3a0324a01c3119 Mon Sep 17 00:00:00 2001 From: Vinay Badgujar Date: Sun, 20 Oct 2024 12:10:15 +0530 Subject: [PATCH 04/22] refactor: optmise the code for maitainability --- src/api/TasksAPI/index.ts | 46 +---------------- src/api/TasksDoneTodayAPI/index.ts | 38 -------------- .../DisplayChangesModal.tsx | 2 +- .../MyTimeline/MyTimeline.tsx | 51 +++++-------------- .../GoalController.ts | 2 +- .../NewUserController.ts | 0 .../PartnerController.ts | 2 +- .../PubSubController.ts | 2 +- src/controllers/TaskDoneTodayController.ts | 43 ++++++++++++++++ src/helpers/GoalActionHelper.tsx | 2 +- src/hooks/useApp.tsx | 4 +- src/hooks/useGoalActions.tsx | 4 +- src/models/TaskItem.ts | 1 - src/models/dexie.ts | 4 +- src/pages/MyTimePage/MyTimePage.tsx | 15 ++++-- 15 files changed, 81 insertions(+), 135 deletions(-) rename src/{helpers => controllers}/GoalController.ts (98%) rename src/{helpers => controllers}/NewUserController.ts (100%) rename src/{helpers => controllers}/PartnerController.ts (95%) rename src/{helpers => controllers}/PubSubController.ts (96%) create mode 100644 src/controllers/TaskDoneTodayController.ts diff --git a/src/api/TasksAPI/index.ts b/src/api/TasksAPI/index.ts index 3d6a9c497..e7f52fd15 100644 --- a/src/api/TasksAPI/index.ts +++ b/src/api/TasksAPI/index.ts @@ -7,8 +7,6 @@ import { convertDateToDay } from "@src/utils/SchedulerUtils"; import { ITask } from "@src/Interfaces/Task"; import { ISchedulerInputGoal } from "@src/Interfaces/IScheduler"; import { getGoal } from "../GoalsAPI"; -import { v4 as uuidv4 } from "uuid"; -import { addTaskDoneToday } from "../TasksDoneTodayAPI"; export const addTask = async (taskDetails: TaskItem) => { let newTaskId; @@ -108,56 +106,14 @@ export const refreshTaskCollection = async () => { console.error("Error updating field:", error); } }; -export const completeTask = async (id: string, duration: number, task: ITask) => { - db.transaction("rw", db.taskCollection, async () => { - await db.taskCollection - .where("id") - .equals(id) - .modify((obj: TaskItem) => { - obj.completedToday += duration; - obj.completedTodayTimings.push({ - goalid: task.goalid, - start: task.start, - deadline: task.deadline, - }); - obj.completedTodayIds.push(task.taskid); - }); - }).catch((e) => { - console.log(e.stack || e); - }); -}; - -export const newCompleteTask = async ( - scheduledTaskId: string, - goalId: string, - scheduledStart: string, - scheduledEnd: string, -) => { - try { - await addTaskDoneToday({ - id: uuidv4(), - scheduledTaskId, - goalId, - scheduledStart, - scheduledEnd, - }); - } catch (error) { - console.log(error); - } -}; -export const skipTask = async (id: string, period: string, task: ITask) => { +export const skipTask = async (id: string, period: string) => { db.transaction("rw", db.taskCollection, async () => { await db.taskCollection .where("id") .equals(id) .modify((obj: TaskItem) => { obj.skippedToday.push(period); - obj.completedTodayTimings.push({ - goalid: task.goalid, - start: task.start, - deadline: task.deadline, - }); if (obj.skippedToday.length > 1) { obj.skippedToday.sort((a, b) => Number(a.split("-")[0]) - Number(b.split("-")[0])); } diff --git a/src/api/TasksDoneTodayAPI/index.ts b/src/api/TasksDoneTodayAPI/index.ts index d7d278104..790de3d62 100644 --- a/src/api/TasksDoneTodayAPI/index.ts +++ b/src/api/TasksDoneTodayAPI/index.ts @@ -5,22 +5,6 @@ export const addTaskDoneToday = async (completedTask: TasksDoneTodayItem) => { await db.tasksDoneTodayCollection.add(completedTask); }; -export const getTaskDoneTodayByTaskId = async (taskId: string) => { - const task = await db.tasksDoneTodayCollection.where("taskId").equals(taskId).first(); - if (task) { - return task; - } - return false; -}; - -export const isTaskDoneToday = async (taskId: string) => { - const task = await getTaskDoneTodayByTaskId(taskId); - if (task) { - return true; - } - return false; -}; - export const getAllTasksDoneToday = async () => { const tasks = await db.tasksDoneTodayCollection.toArray(); return tasks; @@ -33,25 +17,3 @@ export const deleteTaskDoneToday = async (id: string) => { export const deleteAllTasksDoneToday = async () => { await db.tasksDoneTodayCollection.clear(); }; - -export const checkAndCleanupDoneTodayCollection = async () => { - const tasks = await getAllTasksDoneToday(); - - if (tasks.length === 0) { - return; - } - - const firstTaskScheduledStart = new Date(tasks[0].scheduledStart); - const today = new Date(); - const isSameDay = (date1: Date, date2: Date): boolean => { - return ( - date1.getDate() === date2.getDate() && - date1.getMonth() === date2.getMonth() && - date1.getFullYear() === date2.getFullYear() - ); - }; - - if (!isSameDay(firstTaskScheduledStart, today)) { - await deleteAllTasksDoneToday(); - } -}; diff --git a/src/components/GoalsComponents/DisplayChangesModal/DisplayChangesModal.tsx b/src/components/GoalsComponents/DisplayChangesModal/DisplayChangesModal.tsx index 24df73de1..1b5679818 100644 --- a/src/components/GoalsComponents/DisplayChangesModal/DisplayChangesModal.tsx +++ b/src/components/GoalsComponents/DisplayChangesModal/DisplayChangesModal.tsx @@ -8,7 +8,7 @@ import { ITagsChanges } from "@src/Interfaces/IDisplayChangesModal"; import { sendNewGoals } from "@src/helpers/BatchPublisher"; import { darkModeState, lastAction } from "@src/store"; import { getAllContacts } from "@src/api/ContactsAPI"; -import { sendUpdatedGoal } from "@src/helpers/PubSubController"; +import { sendUpdatedGoal } from "@src/controllers/PubSubController"; import { typeOfChange, typeOfIntent } from "@src/models/InboxItem"; import { archiveUserGoal, getGoal, removeGoalWithChildrens, updateGoal } from "@src/api/GoalsAPI"; import { deleteGoalChangesInID, getInboxItem, removeGoalInbox, removePPTFromInboxOfGoal } from "@src/api/InboxAPI"; diff --git a/src/components/MyTimeComponents/MyTimeline/MyTimeline.tsx b/src/components/MyTimeComponents/MyTimeline/MyTimeline.tsx index 293b1deb4..2b0c5aaea 100644 --- a/src/components/MyTimeComponents/MyTimeline/MyTimeline.tsx +++ b/src/components/MyTimeComponents/MyTimeline/MyTimeline.tsx @@ -2,7 +2,7 @@ /* eslint-disable jsx-a11y/control-has-associated-label */ /* eslint-disable react/jsx-key */ import { v4 as uuidv4 } from "uuid"; -import React, { act, useEffect, useState } from "react"; +import React, { useEffect, useState } from "react"; import { useLocation, useNavigate } from "react-router-dom"; import { useSetRecoilState } from "recoil"; @@ -11,38 +11,34 @@ import chevronLeftIcon from "@assets/images/chevronLeft.svg"; import { ITask, TaskAction } from "@src/Interfaces/Task"; import { getGoal } from "@src/api/GoalsAPI"; -import { TaskItem } from "@src/models/TaskItem"; import { GoalItem } from "@src/models/GoalItem"; import { useTranslation } from "react-i18next"; import { displayToast, focusTaskTitle } from "@src/store"; -import { addTask, getTaskByGoalId, newCompleteTask } from "@src/api/TasksAPI"; +import { addTask, getTaskByGoalId } from "@src/api/TasksAPI"; import "./index.scss"; import { displayReschedule } from "@src/store/TaskState"; +import { TasksDoneTodayItem } from "@src/models/TasksDoneTodayItem"; +import { addTaskActionEvent } from "@src/api/TaskHistoryAPI"; +import { completeTask } from "@src/controllers/TaskDoneTodayController"; import { GoalTiming } from "./GoalTiming"; import { TaskOptions } from "./TaskOptions"; import { updateImpossibleGoals } from "./updateImpossibleGoals"; -import { addTaskActionEvent } from "@src/api/TaskHistoryAPI"; type ImpossibleTaskId = string; interface MyTimelineProps { day: string; - taskDetails: { [goalid: string]: TaskItem }; - setTaskDetails: React.Dispatch< - React.SetStateAction<{ - [goalid: string]: TaskItem; - }> - >; myTasks: { scheduled: ITask[]; impossible: ImpossibleTaskId[]; freeHrsOfDay: number; scheduledHrs: number; }; + doneTasks: TasksDoneTodayItem[]; } -export const MyTimeline: React.FC = ({ day, myTasks, taskDetails, setTaskDetails }) => { +export const MyTimeline: React.FC = ({ day, myTasks, doneTasks }) => { const { t } = useTranslation(); const navigate = useNavigate(); const { state } = useLocation(); @@ -98,8 +94,10 @@ export const MyTimeline: React.FC = ({ day, myTasks, taskDetail return handleFocusClick(task); } if (actionName === TaskAction.Done) { - await newCompleteTask(task.taskid, task.goalid, task.start, task.deadline); + await completeTask(task.taskid, task.goalid, task.start, task.deadline); await addTaskActionEvent(task, "completed"); + await doneSound.play(); + return null; } if (day === "Today") { const taskItem = await getTaskByGoalId(task.goalid); @@ -112,35 +110,16 @@ export const MyTimeline: React.FC = ({ day, myTasks, taskDetail title: task.title, completedTodayIds: [], skippedToday: [], - completedToday: actionName === TaskAction.Done ? Number(task.duration) : 0, + completedToday: 0, lastSkipped: "", - lastCompleted: actionName === TaskAction.Done ? new Date().toLocaleDateString() : "", + lastCompleted: "", hoursSpent: 0, - completedTodayTimings: - actionName === TaskAction.Done - ? [ - { - goalid: task.goalid, - start: task.start, - deadline: task.deadline, - }, - ] - : [], blockedSlots: [], }); } else if (actionName === TaskAction.NotNow) { setOpenReschedule(task); } - if (actionName === TaskAction.Done) { - await doneSound.play(); - const updatedTask = await getTaskByGoalId(task.goalid); - if (updatedTask) { - setTaskDetails({ - ...taskDetails, - [task.goalid]: updatedTask, - }); - } - } else if (actionName === TaskAction.NotNow) { + if (actionName === TaskAction.NotNow) { setOpenReschedule({ ...task }); } } else { @@ -161,9 +140,7 @@ export const MyTimeline: React.FC = ({ day, myTasks, taskDetail const nextTask = myTasks.scheduled[index + 1]; const nextStartTime = nextTask ? nextTask.start.split("T")[1].slice(0, 2) : null; const displayEndTime = endTime !== nextStartTime; - const markDone = !!taskDetails[task.goalid]?.completedTodayTimings.find( - (ele) => ele.start === task.start && ele.deadline === task.deadline, - ); + const markDone = doneTasks.some((doneTask) => doneTask.scheduledTaskId === task.taskid); const showTaskOptions = displayOptionsIndex === task.taskid; return (
{showTasks.includes(day) && tasks[day] && tasks[day].scheduled.length > 0 && ( - + )}
From 90c61716a31011243333d1e4fc80858995f5503f Mon Sep 17 00:00:00 2001 From: Vinay Badgujar Date: Sun, 20 Oct 2024 15:20:58 +0530 Subject: [PATCH 05/22] delete taskdonetoday record if the related goal is deleted --- src/api/GoalsAPI/index.ts | 3 +++ src/api/TasksDoneTodayAPI/index.ts | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/api/GoalsAPI/index.ts b/src/api/GoalsAPI/index.ts index b0cd37cae..6d576d0d6 100644 --- a/src/api/GoalsAPI/index.ts +++ b/src/api/GoalsAPI/index.ts @@ -6,6 +6,7 @@ import { getInstallId } from "@src/utils"; import { IHintRequestBody } from "@src/models/HintItem"; import { sortGoalsByProps } from "../GCustomAPI"; import { deleteAvailableGoalHint, deleteHintItem, getGoalHintItem } from "../HintsAPI"; +import { deleteTasksDoneTodayByGoalId } from "../TasksDoneTodayAPI"; export const addDeletedGoal = async (goal: GoalItem) => { await db @@ -173,6 +174,7 @@ export const removeChildrenGoals = async (parentGoalId: string) => { childrenGoals.forEach((goal) => { removeChildrenGoals(goal.id); removeGoal(goal); + deleteTasksDoneTodayByGoalId(goal.id); }); }; @@ -315,6 +317,7 @@ export const notifyNewColabRequest = async (id: string, relId: string) => { export const removeGoalWithChildrens = async (goal: GoalItem) => { await removeChildrenGoals(goal.id); await removeGoal(goal); + await deleteTasksDoneTodayByGoalId(goal.id); if (goal.parentGoalId !== "root") { getGoal(goal.parentGoalId).then(async (parentGoal: GoalItem) => { const parentGoalSublist = parentGoal.sublist; diff --git a/src/api/TasksDoneTodayAPI/index.ts b/src/api/TasksDoneTodayAPI/index.ts index 790de3d62..dd33cc027 100644 --- a/src/api/TasksDoneTodayAPI/index.ts +++ b/src/api/TasksDoneTodayAPI/index.ts @@ -14,6 +14,10 @@ export const deleteTaskDoneToday = async (id: string) => { await db.tasksDoneTodayCollection.delete(id); }; +export const deleteTasksDoneTodayByGoalId = async (goalId: string) => { + await db.tasksDoneTodayCollection.where("goalId").equals(goalId).delete(); +}; + export const deleteAllTasksDoneToday = async () => { await db.tasksDoneTodayCollection.clear(); }; From a01c5749646076af889bef0555bb1b8d62ab2ed5 Mon Sep 17 00:00:00 2001 From: Vinay Badgujar Date: Sun, 20 Oct 2024 15:51:31 +0530 Subject: [PATCH 06/22] rename: outbox collection to scheduleroutputcache --- .../index.ts | 20 +++++++++---------- src/helpers/MyTimeHelper.ts | 6 +++--- ...boxItem.ts => SchedulerOutputCacheItem.ts} | 2 +- src/models/db.ts | 4 ++-- src/models/dexie.ts | 3 ++- 5 files changed, 18 insertions(+), 17 deletions(-) rename src/api/{DumpboxAPI => SchedulerOutputCache}/index.ts (51%) rename src/models/{DumpboxItem.ts => SchedulerOutputCacheItem.ts} (52%) diff --git a/src/api/DumpboxAPI/index.ts b/src/api/SchedulerOutputCache/index.ts similarity index 51% rename from src/api/DumpboxAPI/index.ts rename to src/api/SchedulerOutputCache/index.ts index 07f0a0a8d..a0ff76c10 100644 --- a/src/api/DumpboxAPI/index.ts +++ b/src/api/SchedulerOutputCache/index.ts @@ -1,22 +1,22 @@ /* eslint-disable no-param-reassign */ import { db } from "@models"; -import { DumpboxItem } from "@src/models/DumpboxItem"; +import { SchedulerOutputCacheItem } from "@src/models/SchedulerOutputCacheItem"; import { v4 as uuidv4 } from "uuid"; -export const getFromOutbox = async (key: string) => { +export const getSchedulerCachedRes = async (key: string) => { try { - const dumpbox = await db.dumpboxCollection.where("key").equals(key).toArray(); - return dumpbox[0]; + const schedulerOutputCache = await db.schedulerOutputCacheCollection.where("key").equals(key).toArray(); + return schedulerOutputCache[0]; } catch (err) { return null; } }; -export const addSchedulerRes = async (uniqueId: string, output: string) => { +export const addSchedulerResToCache = async (uniqueId: string, output: string) => { let newId; await db - .transaction("rw", db.dumpboxCollection, async () => { - newId = await db.dumpboxCollection.add({ + .transaction("rw", db.schedulerOutputCacheCollection, async () => { + newId = await db.schedulerOutputCacheCollection.add({ key: "scheduler", value: JSON.stringify({ uniqueId, @@ -32,11 +32,11 @@ export const addSchedulerRes = async (uniqueId: string, output: string) => { }; export const updateSchedulerCachedRes = async (uniqueId: string, output: string) => { - db.transaction("rw", db.dumpboxCollection, async () => { - await db.dumpboxCollection + db.transaction("rw", db.schedulerOutputCacheCollection, async () => { + await db.schedulerOutputCacheCollection .where("key") .equals("scheduler") - .modify((obj: DumpboxItem) => { + .modify((obj: SchedulerOutputCacheItem) => { obj.value = JSON.stringify({ uniqueId, output, diff --git a/src/helpers/MyTimeHelper.ts b/src/helpers/MyTimeHelper.ts index 5fd10902a..1a8fc1551 100644 --- a/src/helpers/MyTimeHelper.ts +++ b/src/helpers/MyTimeHelper.ts @@ -7,7 +7,7 @@ import { ISchedulerOutputGoal, } from "@src/Interfaces/IScheduler"; import { ITaskOfDay } from "@src/Interfaces/Task"; -import { addSchedulerRes, getFromOutbox, updateSchedulerCachedRes } from "@src/api/DumpboxAPI"; +import { addSchedulerResToCache, getSchedulerCachedRes, updateSchedulerCachedRes } from "@src/api/SchedulerOutputCache"; import { getAllGoals } from "@src/api/GoalsAPI"; import { getAllTasks, getAllBlockedTasks, adjustNotOnBlocks } from "@src/api/TasksAPI"; import { getAllTasksDoneToday } from "@src/api/TasksDoneTodayAPI"; @@ -186,7 +186,7 @@ export const organizeDataForInptPrep = async (inputGoals: GoalItem[]) => { }; export const getCachedSchedule = async (generatedInputId: string) => { - const schedulerCachedRes = await getFromOutbox("scheduler"); + const schedulerCachedRes = await getSchedulerCachedRes("scheduler"); if (!schedulerCachedRes) { return { code: "not-exist" }; @@ -204,5 +204,5 @@ export const getCachedSchedule = async (generatedInputId: string) => { export const putSchedulerRes = async (code: string, generatedInputId: string, output: string) => { return code === "expired" ? updateSchedulerCachedRes(generatedInputId, output) - : addSchedulerRes(generatedInputId, output); + : addSchedulerResToCache(generatedInputId, output); }; diff --git a/src/models/DumpboxItem.ts b/src/models/SchedulerOutputCacheItem.ts similarity index 52% rename from src/models/DumpboxItem.ts rename to src/models/SchedulerOutputCacheItem.ts index 2c65dd14a..adc7cb9da 100644 --- a/src/models/DumpboxItem.ts +++ b/src/models/SchedulerOutputCacheItem.ts @@ -1,4 +1,4 @@ -export interface DumpboxItem { +export interface SchedulerOutputCacheItem { id: string; key: string; value: string; diff --git a/src/models/db.ts b/src/models/db.ts index fea4a04c4..6f7f4be43 100644 --- a/src/models/db.ts +++ b/src/models/db.ts @@ -7,7 +7,7 @@ import ContactItem from "./ContactItem"; import { InboxItem } from "./InboxItem"; import { TaskItem } from "./TaskItem"; import { GCustomItem } from "./GCustomItem"; -import { DumpboxItem } from "./DumpboxItem"; +import { SchedulerOutputCacheItem } from "./SchedulerOutputCacheItem"; import { TrashItem } from "./TrashItem"; import { HintItem } from "./HintItem"; import { ImpossibleGoalItem } from "./ImpossibleGoalItem"; @@ -35,7 +35,7 @@ export class ZinZenDB extends Dexie { customizationCollection!: Table; - dumpboxCollection!: Table; + schedulerOutputCacheCollection!: Table; goalTrashCollection!: Table; diff --git a/src/models/dexie.ts b/src/models/dexie.ts index ea525614e..d1daa1d2f 100644 --- a/src/models/dexie.ts +++ b/src/models/dexie.ts @@ -18,12 +18,13 @@ export const dbStoreSchema = { taskCollection: "id, goalId, title, hoursSpent, completedTodayIds, lastCompleted, lastSkipped, blockedSlots, skippedToday, completedToday", customizationCollection: "++id, goalId, posIndex", - dumpboxCollection: "id, key, value", + dumpboxCollection: null, partnersCollection: null, goalTrashCollection: "id, category, deletedAt, title, duration, sublist, habit, on, start, due, afterTime, beforeTime, createdAt, parentGoalId, archived, participants, goalColor, language, link, rootGoalId, timeBudget, typeOfGoal", hintsCollection: "id, hintOptionEnabled, availableGoalHints, lastCheckedDate, nextCheckDate", impossibleGoalsCollection: "goalId, goalTitle", + schedulerOutputCacheCollection: "id, key, value", taskHistoryCollection: "id, goalId, action, eventTime, scheduledStart, scheduledEnd, duration", tasksDoneTodayCollection: "id, goalId, scheduledStart, scheduledEnd", }; From 3f3c1295e34138065718726f0dbec0daa43d5b11 Mon Sep 17 00:00:00 2001 From: Vinay Badgujar Date: Mon, 21 Oct 2024 15:06:42 +0530 Subject: [PATCH 07/22] add: push skip and postpone event in taskhistory collection --- src/api/GoalsAPI/index.ts | 3 +++ src/api/TaskHistoryAPI/index.ts | 9 +++++---- src/api/TasksAPI/index.ts | 1 - .../MyTimeComponents/MyTimeline/MyTimeline.tsx | 11 +++++++---- .../MyTimeComponents/NotNow/NotNowModal.tsx | 7 +++++-- src/models/TaskHistoryItem.ts | 1 - src/models/dexie.ts | 2 +- 7 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/api/GoalsAPI/index.ts b/src/api/GoalsAPI/index.ts index 6d576d0d6..d869fa21b 100644 --- a/src/api/GoalsAPI/index.ts +++ b/src/api/GoalsAPI/index.ts @@ -7,6 +7,7 @@ import { IHintRequestBody } from "@src/models/HintItem"; import { sortGoalsByProps } from "../GCustomAPI"; import { deleteAvailableGoalHint, deleteHintItem, getGoalHintItem } from "../HintsAPI"; import { deleteTasksDoneTodayByGoalId } from "../TasksDoneTodayAPI"; +import { deleteTaskHistoryItem } from "../TaskHistoryAPI"; export const addDeletedGoal = async (goal: GoalItem) => { await db @@ -175,6 +176,7 @@ export const removeChildrenGoals = async (parentGoalId: string) => { removeChildrenGoals(goal.id); removeGoal(goal); deleteTasksDoneTodayByGoalId(goal.id); + deleteTaskHistoryItem(goal.id); }); }; @@ -318,6 +320,7 @@ export const removeGoalWithChildrens = async (goal: GoalItem) => { await removeChildrenGoals(goal.id); await removeGoal(goal); await deleteTasksDoneTodayByGoalId(goal.id); + await deleteTaskHistoryItem(goal.id); if (goal.parentGoalId !== "root") { getGoal(goal.parentGoalId).then(async (parentGoal: GoalItem) => { const parentGoalSublist = parentGoal.sublist; diff --git a/src/api/TaskHistoryAPI/index.ts b/src/api/TaskHistoryAPI/index.ts index 9a10bff61..ebb5efe34 100644 --- a/src/api/TaskHistoryAPI/index.ts +++ b/src/api/TaskHistoryAPI/index.ts @@ -2,20 +2,21 @@ import { db } from "@src/models"; import { TaskHistoryEvents, TaskHistoryItem } from "@src/models/TaskHistoryItem"; import { ITask } from "@src/Interfaces/Task"; -import { v4 as uuidv4 } from "uuid"; - export async function addTaskActionEvent(task: ITask, eventType: TaskHistoryEvents) { if (!task) return; const newEvent: TaskHistoryItem = { - id: uuidv4(), goalId: task.goalid, eventType, duration: task.duration, scheduledStart: task.start, scheduledEnd: task.deadline, - eventTime: new Date().toLocaleDateString(), + eventTime: new Date().toISOString(), }; await db.taskHistoryCollection.add(newEvent); } + +export async function deleteTaskHistoryItem(goalId: string) { + await db.taskHistoryCollection.where("goalId").equals(goalId).delete(); +} diff --git a/src/api/TasksAPI/index.ts b/src/api/TasksAPI/index.ts index e7f52fd15..d880faba1 100644 --- a/src/api/TasksAPI/index.ts +++ b/src/api/TasksAPI/index.ts @@ -4,7 +4,6 @@ import { blockedSlotOfTask, TaskItem } from "@src/models/TaskItem"; import { GoalItem } from "@src/models/GoalItem"; import { calDays, convertDateToString, getLastDayDate } from "@src/utils"; import { convertDateToDay } from "@src/utils/SchedulerUtils"; -import { ITask } from "@src/Interfaces/Task"; import { ISchedulerInputGoal } from "@src/Interfaces/IScheduler"; import { getGoal } from "../GoalsAPI"; diff --git a/src/components/MyTimeComponents/MyTimeline/MyTimeline.tsx b/src/components/MyTimeComponents/MyTimeline/MyTimeline.tsx index 2b0c5aaea..5c9ffc48a 100644 --- a/src/components/MyTimeComponents/MyTimeline/MyTimeline.tsx +++ b/src/components/MyTimeComponents/MyTimeline/MyTimeline.tsx @@ -86,6 +86,12 @@ export const MyTimeline: React.FC = ({ day, myTasks, doneTasks navigate("/", { state: { ...state, displayFocus: true } }); }; + const handleDoneClick = async (task: ITask) => { + await completeTask(task.taskid, task.goalid, task.start, task.deadline); + await addTaskActionEvent(task, "completed"); + await doneSound.play(); + }; + const handleActionClick = async (actionName: TaskAction, task: ITask) => { if (actionName === TaskAction.Goal) { return handleOpenGoal(task.goalid); @@ -94,10 +100,7 @@ export const MyTimeline: React.FC = ({ day, myTasks, doneTasks return handleFocusClick(task); } if (actionName === TaskAction.Done) { - await completeTask(task.taskid, task.goalid, task.start, task.deadline); - await addTaskActionEvent(task, "completed"); - await doneSound.play(); - return null; + return handleDoneClick(task); } if (day === "Today") { const taskItem = await getTaskByGoalId(task.goalid); diff --git a/src/components/MyTimeComponents/NotNow/NotNowModal.tsx b/src/components/MyTimeComponents/NotNow/NotNowModal.tsx index b2b9b3f76..3ce4eb835 100644 --- a/src/components/MyTimeComponents/NotNow/NotNowModal.tsx +++ b/src/components/MyTimeComponents/NotNow/NotNowModal.tsx @@ -12,6 +12,7 @@ import ActionDiv from "@components/GoalsComponents/MyGoalActions/ActionDiv"; import { getGoalById } from "@src/api/GoalsAPI"; import { getHrFromDateString } from "@src/utils/SchedulerUtils"; import forgetTune from "@assets/forget.mp3"; +import { addTaskActionEvent } from "@src/api/TaskHistoryAPI"; const NotNowModal = () => { const [task, setDisplayReschedule] = useRecoilState(displayReschedule); @@ -36,7 +37,7 @@ const NotNowModal = () => { if (!task) return null; - const handleReschedule = (hours: number) => { + const handleReschedule = async (hours: number) => { const startTime = new Date(task.start); const endTime = new Date(startTime.getTime() + hours * MILLISECONDS_IN_HOUR); const start = convertDateToString(startTime, false); @@ -46,6 +47,7 @@ const NotNowModal = () => { start, end, }); + await addTaskActionEvent(task, "postponed"); console.log(`Task rescheduled from ${start} to ${end}`); setDisplayReschedule(null); @@ -58,7 +60,8 @@ const NotNowModal = () => { return; } const period = `${getHrFromDateString(task.start)}-${getHrFromDateString(task.deadline)}`; - await skipTask(taskItem?.id, period, task); + await skipTask(taskItem?.id, period); + await addTaskActionEvent(task, "skipped"); setDisplayReschedule(null); setLastAction("TaskSkipped"); forgetSound.play(); diff --git a/src/models/TaskHistoryItem.ts b/src/models/TaskHistoryItem.ts index 4eff4ddf6..33846584d 100644 --- a/src/models/TaskHistoryItem.ts +++ b/src/models/TaskHistoryItem.ts @@ -1,7 +1,6 @@ export type TaskHistoryEvents = "completed" | "postponed" | "skipped"; export interface TaskHistoryItem { - id: string; goalId: string; eventType: TaskHistoryEvents; scheduledStart: string; diff --git a/src/models/dexie.ts b/src/models/dexie.ts index d1daa1d2f..4490ffd21 100644 --- a/src/models/dexie.ts +++ b/src/models/dexie.ts @@ -25,7 +25,7 @@ export const dbStoreSchema = { hintsCollection: "id, hintOptionEnabled, availableGoalHints, lastCheckedDate, nextCheckDate", impossibleGoalsCollection: "goalId, goalTitle", schedulerOutputCacheCollection: "id, key, value", - taskHistoryCollection: "id, goalId, action, eventTime, scheduledStart, scheduledEnd, duration", + taskHistoryCollection: "++id, goalId, eventType, eventTime, scheduledStart, scheduledEnd, duration", tasksDoneTodayCollection: "id, goalId, scheduledStart, scheduledEnd", }; export const syncVersion = (transaction: Transaction, currentVersion: number) => { From 470ae548a051852ab9d091abdf06c53e64ded4cc Mon Sep 17 00:00:00 2001 From: Vinay Badgujar Date: Mon, 21 Oct 2024 15:36:39 +0530 Subject: [PATCH 08/22] feat: skipped tasks are also added in doneTodayCollection --- src/api/TasksAPI/index.ts | 16 --------- src/api/TasksDoneTodayAPI/index.ts | 33 +++++++++++++++---- .../MyTimeline/MyTimeline.tsx | 8 ++--- .../MyTimeComponents/NotNow/NotNowModal.tsx | 16 ++++----- src/controllers/TaskDoneTodayController.ts | 2 -- src/models/TasksDoneTodayItem.ts | 1 - src/models/dexie.ts | 2 +- 7 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/api/TasksAPI/index.ts b/src/api/TasksAPI/index.ts index d880faba1..9345bc46f 100644 --- a/src/api/TasksAPI/index.ts +++ b/src/api/TasksAPI/index.ts @@ -106,22 +106,6 @@ export const refreshTaskCollection = async () => { } }; -export const skipTask = async (id: string, period: string) => { - db.transaction("rw", db.taskCollection, async () => { - await db.taskCollection - .where("id") - .equals(id) - .modify((obj: TaskItem) => { - obj.skippedToday.push(period); - if (obj.skippedToday.length > 1) { - obj.skippedToday.sort((a, b) => Number(a.split("-")[0]) - Number(b.split("-")[0])); - } - }); - }).catch((e) => { - console.log(e.stack || e); - }); -}; - export const getAllTasks = async () => { const allGoals = await db.taskCollection.toArray(); allGoals.reverse(); diff --git a/src/api/TasksDoneTodayAPI/index.ts b/src/api/TasksDoneTodayAPI/index.ts index dd33cc027..8d5562ed5 100644 --- a/src/api/TasksDoneTodayAPI/index.ts +++ b/src/api/TasksDoneTodayAPI/index.ts @@ -2,22 +2,43 @@ import { db } from "@src/models"; import { TasksDoneTodayItem } from "@src/models/TasksDoneTodayItem"; export const addTaskDoneToday = async (completedTask: TasksDoneTodayItem) => { - await db.tasksDoneTodayCollection.add(completedTask); + try { + await db.tasksDoneTodayCollection.add(completedTask); + } catch (error) { + console.error("Error adding task:", error); + } }; export const getAllTasksDoneToday = async () => { - const tasks = await db.tasksDoneTodayCollection.toArray(); - return tasks; + try { + const tasks = await db.tasksDoneTodayCollection.toArray(); + return tasks; + } catch (error) { + console.error("Error fetching tasks:", error); + return []; + } }; export const deleteTaskDoneToday = async (id: string) => { - await db.tasksDoneTodayCollection.delete(id); + try { + await db.tasksDoneTodayCollection.delete(id); + } catch (error) { + console.error("Error deleting task:", error); + } }; export const deleteTasksDoneTodayByGoalId = async (goalId: string) => { - await db.tasksDoneTodayCollection.where("goalId").equals(goalId).delete(); + try { + await db.tasksDoneTodayCollection.where("goalId").equals(goalId).delete(); + } catch (error) { + console.error("Error deleting tasks by goalId:", error); + } }; export const deleteAllTasksDoneToday = async () => { - await db.tasksDoneTodayCollection.clear(); + try { + await db.tasksDoneTodayCollection.clear(); + } catch (error) { + console.error("Error clearing tasks:", error); + } }; diff --git a/src/components/MyTimeComponents/MyTimeline/MyTimeline.tsx b/src/components/MyTimeComponents/MyTimeline/MyTimeline.tsx index 5c9ffc48a..501a7da78 100644 --- a/src/components/MyTimeComponents/MyTimeline/MyTimeline.tsx +++ b/src/components/MyTimeComponents/MyTimeline/MyTimeline.tsx @@ -102,6 +102,9 @@ export const MyTimeline: React.FC = ({ day, myTasks, doneTasks if (actionName === TaskAction.Done) { return handleDoneClick(task); } + if (actionName === TaskAction.NotNow) { + return setOpenReschedule({ ...task }); + } if (day === "Today") { const taskItem = await getTaskByGoalId(task.goalid); if (!taskItem) { @@ -119,11 +122,6 @@ export const MyTimeline: React.FC = ({ day, myTasks, doneTasks hoursSpent: 0, blockedSlots: [], }); - } else if (actionName === TaskAction.NotNow) { - setOpenReschedule(task); - } - if (actionName === TaskAction.NotNow) { - setOpenReschedule({ ...task }); } } else { setShowToast({ open: true, message: "Let's focus on Today :)", extra: "" }); diff --git a/src/components/MyTimeComponents/NotNow/NotNowModal.tsx b/src/components/MyTimeComponents/NotNow/NotNowModal.tsx index 3ce4eb835..e7d0c9089 100644 --- a/src/components/MyTimeComponents/NotNow/NotNowModal.tsx +++ b/src/components/MyTimeComponents/NotNow/NotNowModal.tsx @@ -4,15 +4,15 @@ import React, { useEffect, useState } from "react"; import { lastAction } from "@src/store"; import "./NotNowModal.scss"; import ZModal from "@src/common/ZModal"; -import { addBlockedSlot, getTaskByGoalId, skipTask } from "@src/api/TasksAPI"; // Assume getGoalById exists +import { addBlockedSlot } from "@src/api/TasksAPI"; import { displayReschedule } from "@src/store/TaskState"; import { MILLISECONDS_IN_HOUR, RESCHEDULE_OPTIONS } from "@src/constants/rescheduleOptions"; import { convertDateToString } from "@src/utils"; import ActionDiv from "@components/GoalsComponents/MyGoalActions/ActionDiv"; import { getGoalById } from "@src/api/GoalsAPI"; -import { getHrFromDateString } from "@src/utils/SchedulerUtils"; import forgetTune from "@assets/forget.mp3"; import { addTaskActionEvent } from "@src/api/TaskHistoryAPI"; +import { addTaskDoneToday } from "@src/api/TasksDoneTodayAPI"; const NotNowModal = () => { const [task, setDisplayReschedule] = useRecoilState(displayReschedule); @@ -55,12 +55,12 @@ const NotNowModal = () => { }; const handleSkip = async () => { - const taskItem = await getTaskByGoalId(task.goalid); - if (!taskItem) { - return; - } - const period = `${getHrFromDateString(task.start)}-${getHrFromDateString(task.deadline)}`; - await skipTask(taskItem?.id, period); + await addTaskDoneToday({ + scheduledTaskId: task.taskid, + scheduledStart: task.start, + scheduledEnd: task.deadline, + goalId: task.goalid, + }); await addTaskActionEvent(task, "skipped"); setDisplayReschedule(null); setLastAction("TaskSkipped"); diff --git a/src/controllers/TaskDoneTodayController.ts b/src/controllers/TaskDoneTodayController.ts index 5bbc9ae21..4940dedf0 100644 --- a/src/controllers/TaskDoneTodayController.ts +++ b/src/controllers/TaskDoneTodayController.ts @@ -1,5 +1,4 @@ import { addTaskDoneToday, deleteAllTasksDoneToday, getAllTasksDoneToday } from "@src/api/TasksDoneTodayAPI"; -import { v4 as uuidv4 } from "uuid"; export const completeTask = async ( scheduledTaskId: string, @@ -9,7 +8,6 @@ export const completeTask = async ( ) => { try { await addTaskDoneToday({ - id: uuidv4(), scheduledTaskId, goalId, scheduledStart, diff --git a/src/models/TasksDoneTodayItem.ts b/src/models/TasksDoneTodayItem.ts index 9066cfb55..a4e8c72e2 100644 --- a/src/models/TasksDoneTodayItem.ts +++ b/src/models/TasksDoneTodayItem.ts @@ -1,5 +1,4 @@ export interface TasksDoneTodayItem { - id: string; scheduledTaskId: string; goalId: string; scheduledStart: string; diff --git a/src/models/dexie.ts b/src/models/dexie.ts index 4490ffd21..36a71cfbb 100644 --- a/src/models/dexie.ts +++ b/src/models/dexie.ts @@ -26,7 +26,7 @@ export const dbStoreSchema = { impossibleGoalsCollection: "goalId, goalTitle", schedulerOutputCacheCollection: "id, key, value", taskHistoryCollection: "++id, goalId, eventType, eventTime, scheduledStart, scheduledEnd, duration", - tasksDoneTodayCollection: "id, goalId, scheduledStart, scheduledEnd", + tasksDoneTodayCollection: "++id, goalId, scheduledStart, scheduledEnd", }; export const syncVersion = (transaction: Transaction, currentVersion: number) => { if (currentVersion < 9) { From 8b92ade8ecc6fbdee7df79ec8670592087f7fe0b Mon Sep 17 00:00:00 2001 From: Vinay Badgujar Date: Tue, 22 Oct 2024 14:14:00 +0530 Subject: [PATCH 09/22] update db version --- src/models/db.ts | 2 +- src/models/dexie.ts | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/models/db.ts b/src/models/db.ts index 6f7f4be43..f50050ef9 100644 --- a/src/models/db.ts +++ b/src/models/db.ts @@ -15,7 +15,7 @@ import { dbStoreSchema, syncVersion } from "./dexie"; import { TaskHistoryItem } from "./TaskHistoryItem"; import { TasksDoneTodayItem } from "./TasksDoneTodayItem"; -export const dexieVersion = 21; +export const dexieVersion = 22; const currentVersion = Number(localStorage.getItem(LocalStorageKeys.DEXIE_VERSION) || dexieVersion); localStorage.setItem(LocalStorageKeys.DEXIE_VERSION, `${dexieVersion}`); diff --git a/src/models/dexie.ts b/src/models/dexie.ts index 36a71cfbb..1fdfe9fbb 100644 --- a/src/models/dexie.ts +++ b/src/models/dexie.ts @@ -161,8 +161,15 @@ export const syncVersion = (transaction: Transaction, currentVersion: number) => if (currentVersion < 21) { console.log("processing updates for 20th version"); const taskCollection = transaction.table("taskCollection"); - taskCollection.toCollection().modify((task: TaskItem) => { - // task.completedTodayTimings = []; + taskCollection.toCollection().modify((task) => { + task.completedTodayTimings = []; + }); + } + if (currentVersion < 22) { + console.log("processing updates for 22th version"); + const taskCollection = transaction.table("taskCollection"); + taskCollection.toCollection().modify((task) => { + delete task.completedTodayTimings; }); } }; From 841b07596bc29389b836f430788d81878938bc3d Mon Sep 17 00:00:00 2001 From: Vinay Badgujar Date: Thu, 7 Nov 2024 16:36:10 +0530 Subject: [PATCH 10/22] feat: v1 of show scheduled status in edit modal --- .../GoalConfigModal/ConfigGoal.scss | 5 ++ .../GoalConfigModal/ConfigGoal.tsx | 65 +++++++++++++++++++ src/hooks/useScheduler.tsx | 18 +++++ 3 files changed, 88 insertions(+) diff --git a/src/components/GoalsComponents/GoalConfigModal/ConfigGoal.scss b/src/components/GoalsComponents/GoalConfigModal/ConfigGoal.scss index ed1f3d62c..d2e654010 100644 --- a/src/components/GoalsComponents/GoalConfigModal/ConfigGoal.scss +++ b/src/components/GoalsComponents/GoalConfigModal/ConfigGoal.scss @@ -156,3 +156,8 @@ gap: 10px; justify-content: center; } + +.schedule-status { + margin-top: 8px; + font-size: 14px; +} diff --git a/src/components/GoalsComponents/GoalConfigModal/ConfigGoal.tsx b/src/components/GoalsComponents/GoalConfigModal/ConfigGoal.tsx index 56541b32f..cea958c67 100644 --- a/src/components/GoalsComponents/GoalConfigModal/ConfigGoal.tsx +++ b/src/components/GoalsComponents/GoalConfigModal/ConfigGoal.tsx @@ -21,6 +21,8 @@ import { ILocationState } from "@src/Interfaces"; import { useLocation, useNavigate } from "react-router-dom"; import { suggestedGoalState } from "@src/store/SuggestedGoalState"; import { getHistoryUptoGoal } from "@src/helpers/GoalProcessor"; +import { ISchedulerOutput } from "@src/Interfaces/IScheduler"; +import useScheduler from "@src/hooks/useScheduler"; import { colorPalleteList, calDays, convertOnFilterToArray, getSelectedLanguage } from "../../../utils"; import "./ConfigGoal.scss"; @@ -277,8 +279,65 @@ const ConfigGoal = ({ type, goal, mode }: { type: TGoalCategory; mode: TGoalConf setHintOption(hint?.hintOptionEnabled || false); }; + const { checkGoalSchedule } = useScheduler(); + const titlePlaceholder = t(`${type !== "Budget" ? "goal" : "budget"}Title`); + type ScheduleStatus = "pending" | "scheduled" | "impossible" | "future" | null; + + const [scheduleStatus, setScheduleStatus] = useState(null); + + const checkSchedulingStatus = async (schedulerOutput: ISchedulerOutput | undefined, goalId: string) => { + if (!schedulerOutput) return "pending"; + + const { scheduled, impossible } = schedulerOutput; + + if (impossible?.some((task) => task.id === goalId)) { + return "impossible"; + } + + const isScheduledInNext7Days = scheduled.some((day) => day.tasks.some((task) => task.goalid === goalId)); + + return isScheduledInNext7Days ? "scheduled" : "future"; + }; + + const getScheduleStatusText = (status: ScheduleStatus) => { + switch (status) { + case "scheduled": + return "Auto scheduled"; + case "impossible": + return "! Impossible"; + case "future": + return "Scheduled someday"; + default: + return ""; + } + }; + + const checkSchedule = async () => { + // if (t) { + // setScheduleStatus(null); + // console.log("no duration"); + // return; + // } + + setScheduleStatus("pending"); + const schedulerOutput = await checkGoalSchedule(getFinalTags()); + console.log("schedulerOutput", schedulerOutput); + const status = await checkSchedulingStatus(schedulerOutput, goal.id); + console.log("status", status); + setScheduleStatus(status); + }; + + useEffect(() => { + const debounceTimer = setTimeout(() => { + console.log("checking schedule"); + checkSchedule(); + }, 1000); + + return () => clearTimeout(debounceTimer); + }, [tags.duration, afterTime, beforeTime, tags.on]); + return ( {t(`${action} Budget`)} + {scheduleStatus && ( +
{getScheduleStatusText(scheduleStatus)}
+ )} ) : ( @@ -425,6 +487,9 @@ const ConfigGoal = ({ type, goal, mode }: { type: TGoalCategory; mode: TGoalConf {t(`${action} Goal`)} + {scheduleStatus && ( +
{getScheduleStatusText(scheduleStatus)}
+ )}
{t("duration")} { + try { + const activeGoals: GoalItem[] = await getAllGoals(); + const goalsWithConfig = [...activeGoals, goal]; + + const { schedulerInput } = await organizeDataForInptPrep(goalsWithConfig); + + await init(); + const res = schedule(schedulerInput); + + return res; + } catch (error) { + console.log("Error checking goal schedule:", error); + return undefined; + } + }; + return { tasks, tasksStatus, setTasksStatus, + checkGoalSchedule, }; } From 2c5be17243b7f4339c62f5c3119760ef8a8c46d7 Mon Sep 17 00:00:00 2001 From: Vinay Badgujar Date: Sat, 9 Nov 2024 14:28:28 +0530 Subject: [PATCH 11/22] organize the code --- src/Interfaces/index.ts | 2 ++ .../GoalConfigModal/ConfigGoal.scss | 1 + .../GoalConfigModal/ConfigGoal.tsx | 29 +++++++------------ 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/src/Interfaces/index.ts b/src/Interfaces/index.ts index 41e81983d..7c0860a4e 100644 --- a/src/Interfaces/index.ts +++ b/src/Interfaces/index.ts @@ -33,3 +33,5 @@ export interface ILocationState { export interface ImpossibleGoal extends GoalItem { impossible: boolean; } + +export type ScheduleStatus = "pending" | "scheduled" | "impossible" | "future" | null; diff --git a/src/components/GoalsComponents/GoalConfigModal/ConfigGoal.scss b/src/components/GoalsComponents/GoalConfigModal/ConfigGoal.scss index d2e654010..89d30f086 100644 --- a/src/components/GoalsComponents/GoalConfigModal/ConfigGoal.scss +++ b/src/components/GoalsComponents/GoalConfigModal/ConfigGoal.scss @@ -160,4 +160,5 @@ .schedule-status { margin-top: 8px; font-size: 14px; + text-align: center; } diff --git a/src/components/GoalsComponents/GoalConfigModal/ConfigGoal.tsx b/src/components/GoalsComponents/GoalConfigModal/ConfigGoal.tsx index cea958c67..2f47f49a5 100644 --- a/src/components/GoalsComponents/GoalConfigModal/ConfigGoal.tsx +++ b/src/components/GoalsComponents/GoalConfigModal/ConfigGoal.tsx @@ -17,7 +17,7 @@ import { useParentGoalContext } from "@src/contexts/parentGoal-context"; import useGoalActions from "@src/hooks/useGoalActions"; import useGoalStore from "@src/hooks/useGoalStore"; import { unarchiveUserGoal } from "@src/api/GoalsAPI"; -import { ILocationState } from "@src/Interfaces"; +import { ILocationState, ScheduleStatus } from "@src/Interfaces"; import { useLocation, useNavigate } from "react-router-dom"; import { suggestedGoalState } from "@src/store/SuggestedGoalState"; import { getHistoryUptoGoal } from "@src/helpers/GoalProcessor"; @@ -49,6 +49,9 @@ const ConfigGoal = ({ type, goal, mode }: { type: TGoalCategory; mode: TGoalConf const location = useLocation(); const navigate = useNavigate(); + const { checkGoalSchedule } = useScheduler(); + const [scheduleStatus, setScheduleStatus] = useState(null); + let defaultColorIndex = Math.floor(Math.random() * colorPalleteList.length - 1) + 1; let defaultAfterTime = isEditMode ? (goal.afterTime ?? 9) : 9; let defaultBeforeTime = isEditMode ? (goal.beforeTime ?? 18) : 18; @@ -279,14 +282,8 @@ const ConfigGoal = ({ type, goal, mode }: { type: TGoalCategory; mode: TGoalConf setHintOption(hint?.hintOptionEnabled || false); }; - const { checkGoalSchedule } = useScheduler(); - const titlePlaceholder = t(`${type !== "Budget" ? "goal" : "budget"}Title`); - type ScheduleStatus = "pending" | "scheduled" | "impossible" | "future" | null; - - const [scheduleStatus, setScheduleStatus] = useState(null); - const checkSchedulingStatus = async (schedulerOutput: ISchedulerOutput | undefined, goalId: string) => { if (!schedulerOutput) return "pending"; @@ -315,12 +312,6 @@ const ConfigGoal = ({ type, goal, mode }: { type: TGoalCategory; mode: TGoalConf }; const checkSchedule = async () => { - // if (t) { - // setScheduleStatus(null); - // console.log("no duration"); - // return; - // } - setScheduleStatus("pending"); const schedulerOutput = await checkGoalSchedule(getFinalTags()); console.log("schedulerOutput", schedulerOutput); @@ -474,10 +465,10 @@ const ConfigGoal = ({ type, goal, mode }: { type: TGoalCategory; mode: TGoalConf - {scheduleStatus && ( -
{getScheduleStatusText(scheduleStatus)}
- )}
+ {scheduleStatus && ( +
{getScheduleStatusText(scheduleStatus)}
+ )} ) : (
@@ -487,9 +478,6 @@ const ConfigGoal = ({ type, goal, mode }: { type: TGoalCategory; mode: TGoalConf {t(`${action} Goal`)}
- {scheduleStatus && ( -
{getScheduleStatusText(scheduleStatus)}
- )}
{t("duration")}
+ {scheduleStatus && tags.duration && ( +
{getScheduleStatusText(scheduleStatus)}
+ )} )} From a0aae540e4e0f9705bdec78c2fa297368aa53baf Mon Sep 17 00:00:00 2001 From: Vinay Badgujar Date: Sat, 9 Nov 2024 14:50:13 +0530 Subject: [PATCH 12/22] add the day and week budget hours in checkSchedule effect dependency --- .../GoalsComponents/GoalConfigModal/ConfigGoal.tsx | 14 ++++++++------ src/hooks/useScheduler.tsx | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/components/GoalsComponents/GoalConfigModal/ConfigGoal.tsx b/src/components/GoalsComponents/GoalConfigModal/ConfigGoal.tsx index 2f47f49a5..23ef1c95f 100644 --- a/src/components/GoalsComponents/GoalConfigModal/ConfigGoal.tsx +++ b/src/components/GoalsComponents/GoalConfigModal/ConfigGoal.tsx @@ -313,11 +313,13 @@ const ConfigGoal = ({ type, goal, mode }: { type: TGoalCategory; mode: TGoalConf const checkSchedule = async () => { setScheduleStatus("pending"); - const schedulerOutput = await checkGoalSchedule(getFinalTags()); - console.log("schedulerOutput", schedulerOutput); - const status = await checkSchedulingStatus(schedulerOutput, goal.id); - console.log("status", status); - setScheduleStatus(status); + try { + const schedulerOutput = await checkGoalSchedule(getFinalTags()); + const status = await checkSchedulingStatus(schedulerOutput, goal.id); + setScheduleStatus(status); + } catch (error) { + setScheduleStatus(null); + } }; useEffect(() => { @@ -327,7 +329,7 @@ const ConfigGoal = ({ type, goal, mode }: { type: TGoalCategory; mode: TGoalConf }, 1000); return () => clearTimeout(debounceTimer); - }, [tags.duration, afterTime, beforeTime, tags.on]); + }, [tags.duration, afterTime, beforeTime, perDayHrs, perWeekHrs]); return ( Date: Thu, 14 Nov 2024 14:57:08 +0530 Subject: [PATCH 13/22] add: csv strategy for exporting data --- src/components/BackupRestoreModal.tsx | 33 ++++--- src/types/export.ts | 4 + .../ExportStrategies/CsvExport.strategy.ts | 98 +++++++++++++++++++ .../ExportStrategies/JsonExport.strategy.ts | 25 +++++ 4 files changed, 145 insertions(+), 15 deletions(-) create mode 100644 src/types/export.ts create mode 100644 src/utils/ExportStrategies/CsvExport.strategy.ts create mode 100644 src/utils/ExportStrategies/JsonExport.strategy.ts diff --git a/src/components/BackupRestoreModal.tsx b/src/components/BackupRestoreModal.tsx index ab8c85265..b6b89e757 100644 --- a/src/components/BackupRestoreModal.tsx +++ b/src/components/BackupRestoreModal.tsx @@ -9,6 +9,9 @@ import { backupRestoreModal, darkModeState, displayToast, lastAction } from "@sr import "dexie-export-import"; import "./index.scss"; +import { ExportStrategy } from "@src/types/export"; +import { JsonExportStrategy } from "@src/utils/ExportStrategies/JsonExport.strategy"; +import { CsvExportStrategy } from "@src/utils/ExportStrategies/CsvExport.strategy"; const backupImg = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAACXBIWXMAAAsTAAALEwEAmpwYAAADB0lEQVR4nO2Z3YtMYRzHP3a9jpc21sxQ5C1FFFHakJeibd24EQnXe4H2brkTpVUU+QMWiVLWhfdEsSHvNizLtkoJid3FLlvs6Nm+R481M7szc87OeTSfOs0855zn9/y+53n7nd+BAgUKhIHBwAJgE7Ad2AqsBRYCxTjAIuAI8BVIpDg+ArVAGSFkAnAK6LYcfg6cAA4Bh4E64FkvUXXAdELCcuC9HPsM7AYmpbl/BrALaFedVqCcPLMa+C6HTgLRDOqOV4+Zuj+BLeSJ2cA3ObIzSxuDVNcMyS5gCQER0UqzUkPCYwjwVCL2+NDOXtkyQ7QEH5kGHAc6e03ORmAdUKXydaDIh/aKgKuyWYNPlFsT0YzdR8A14LUlyAyFX8AsvxoF5smmeXgxP4x1yNlaLas2ZRLmLZ1+c0a2K3M1dFOG9vUxbyr9eGpJ2Kz2L5ID82XklSZzPojKh0+5GKnycRXKhU75MSKbykuB+zKQt41JtMiPqWRAzJpgXkBn7xf54K18OQCsAYb2VWGmtaS2aKJl1Z0+86TX3vUBqE41b8cBzbrxNDCK8DAGWAxs1KbcJT/vJovljuni5TyuUP3FRBm3rcjCCP0T7HVr956IGwxXOJRQL/WwXycO4hZx4Is6wUQgPJCQZbhHjd0JrSqMDagxMwTuBZgTSGhl44cKwwJqzFs2g6BEtttM4Y0K6d6rwypkpGybN1OuqLDeQSFzZPulKWxT4ayDQqqtdyVKrTdAk8pxRUjEisMqvJM7dOIdMMURIUdl95ayLz2Y/OsFS8yKEAuJWCLaFZn8xWjgvNXwOWADMLk/oXPAQiLAXM0JbziZXX1VqgrFurktTdI51VGfhZD6LNpJaDj90xPJKFXq/5L2GS90TnfcCFBIB9Ck1anCnhMDSZDL74BSEBI2nOyRh8BjvfSkEmKuNQB3CDEN1me2eBIhcV1LKGccWqLWd5Im5QA8ITHr2gsX8gNx66l7v/Z/u7dCT9R6+vbhRE/0JcZJER5xJdEaXRpO6Xomk8/UBfgf+A3SSyxFIXLo1QAAAABJRU5ErkJggg=="; @@ -21,16 +24,14 @@ const BackupRestoreModal = () => { const setShowToast = useSetRecoilState(displayToast); const setLastAction = useSetRecoilState(lastAction); - const backupData = async () => { - const file = await db.export({ prettyJson: true }); - const blob = new Blob([file], { type: "application/json" }); - const url = URL.createObjectURL(blob); - const a = document.createElement("a"); - a.href = url; - a.download = `ZinZenBackup-${new Date().toLocaleDateString()}.json`; - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); + const exportData = async (strategy: ExportStrategy) => { + try { + await strategy.export(); + window.history.back(); + } catch (error) { + console.error(error); + setShowToast({ open: true, message: "Failed to export data", extra: error.message }); + } }; const importSuccessfull = () => { @@ -80,32 +81,34 @@ const BackupRestoreModal = () => { } }; - const getOption = (text: "Backup" | "Restore") => ( + const getOption = (text: "Backup" | "CSV Export" | "Restore") => ( ); + return ( window.history.back()} type="backupRestoreModal">

- {" "} Choose an option from below

{getOption("Backup")} + {getOption("CSV Export")} {getOption("Restore")}
diff --git a/src/types/export.ts b/src/types/export.ts new file mode 100644 index 000000000..8cfc2d75a --- /dev/null +++ b/src/types/export.ts @@ -0,0 +1,4 @@ +export interface ExportStrategy { + export(): Promise; + getFileName(): string; +} diff --git a/src/utils/ExportStrategies/CsvExport.strategy.ts b/src/utils/ExportStrategies/CsvExport.strategy.ts new file mode 100644 index 000000000..efbc9f929 --- /dev/null +++ b/src/utils/ExportStrategies/CsvExport.strategy.ts @@ -0,0 +1,98 @@ +import { db } from "@models"; +import { ExportStrategy } from "@src/types/export"; + +function formatCsvValue(value: any): string { + if (value === null || value === undefined) { + return '""'; + } + + if (Array.isArray(value)) { + const isArrayOfObjects = value.some((item) => typeof item === "object" && !Array.isArray(item)); + + if (isArrayOfObjects) { + return `"${JSON.stringify(value).replace(/"/g, '""')}"`; + } + const formattedArray = value.map((item) => formatCsvValue(item).replace(/^"|"$/g, "")).join(";"); + return `"${formattedArray}"`; + } + + if (typeof value === "object" && !(value instanceof Date)) { + const formattedObject = Object.entries(value).reduce( + (acc, [key, val]) => { + if (val === null || val === undefined) { + acc[key] = '""'; + } else { + acc[key] = formatCsvValue(val).replace(/^"|"$/g, ""); + } + return acc; + }, + {} as Record, + ); + return `"${JSON.stringify(formattedObject).replace(/"/g, '""')}"`; + } + + if (value instanceof Date) { + return `"${value.toISOString()}"`; + } + + if (typeof value === "string") { + const escaped = value.replace(/"/g, '""'); + return `"${escaped}"`; + } + + if (typeof value === "boolean") { + return value.toString(); + } + + return value.toString(); +} + +function convertJSONToCSV(jsonData: any[], columnHeaders: string[]): string { + if (jsonData.length === 0) { + return ""; + } + + const headers = `${columnHeaders.join(",")}\n`; + + const rows = jsonData + .map((row) => { + return columnHeaders.map((field) => formatCsvValue(row[field])).join(","); + }) + .join("\n"); + + return headers + rows; +} + +export class CsvExportStrategy implements ExportStrategy { + async export(): Promise { + try { + const goals = await db.goalsCollection.toArray(); + const feelings = await db.feelingsCollection.toArray(); + const goalsCollectionKeys = db.goalsCollection.schema.indexes; + const keys = goalsCollectionKeys.map((key) => key.name); + + const csvContent = convertJSONToCSV(goals, keys); + + const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" }); + await this.downloadFile(blob); + } catch (error) { + console.error("CSV Export failed:", error); + throw error; + } + } + + static getFileName(): string { + return `ZinZen-Export-${new Date().toLocaleDateString()}.csv`; + } + + private async downloadFile(blob: Blob): Promise { + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = CsvExportStrategy.getFileName(); + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); + } +} diff --git a/src/utils/ExportStrategies/JsonExport.strategy.ts b/src/utils/ExportStrategies/JsonExport.strategy.ts new file mode 100644 index 000000000..af66ddeff --- /dev/null +++ b/src/utils/ExportStrategies/JsonExport.strategy.ts @@ -0,0 +1,25 @@ +import { db } from "@src/models"; +import { ExportStrategy } from "@src/types/export"; + +export class JsonExportStrategy implements ExportStrategy { + async export(): Promise { + const file = await db.export({ prettyJson: true }); + const blob = new Blob([file], { type: "application/json" }); + await this.downloadFile(blob); + } + + getFileName(): string { + return `ZinZenBackup-${new Date().toLocaleDateString()}.json`; + } + + private async downloadFile(blob: Blob): Promise { + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = this.getFileName(); + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); + } +} From 2dfdadaf3180885930f3cfe702e85bd1c67bd3d4 Mon Sep 17 00:00:00 2001 From: Vinay Badgujar Date: Sat, 16 Nov 2024 19:19:55 +0530 Subject: [PATCH 14/22] remove: setting explicit font size to schedule status --- src/components/GoalsComponents/GoalConfigModal/ConfigGoal.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/GoalsComponents/GoalConfigModal/ConfigGoal.scss b/src/components/GoalsComponents/GoalConfigModal/ConfigGoal.scss index 89d30f086..727ce1fe9 100644 --- a/src/components/GoalsComponents/GoalConfigModal/ConfigGoal.scss +++ b/src/components/GoalsComponents/GoalConfigModal/ConfigGoal.scss @@ -159,6 +159,5 @@ .schedule-status { margin-top: 8px; - font-size: 14px; text-align: center; } From 519270d7e93b583ec1e7289cd9cfb6389496af84 Mon Sep 17 00:00:00 2001 From: Vinay Badgujar Date: Tue, 19 Nov 2024 15:15:48 +0530 Subject: [PATCH 15/22] refactor: create utils for exporting data --- .../ExportStrategy.ts} | 1 - src/components/BackupRestoreModal.tsx | 6 +-- .../CsvExport.strategy.ts => BackupUtils.ts} | 51 ++++++------------- .../ExportStrategies/CsvExportStrategy.ts | 30 +++++++++++ .../ExportStrategies/JsonExport.strategy.ts | 25 --------- .../ExportStrategies/JsonExportStrategy.ts | 12 +++++ 6 files changed, 60 insertions(+), 65 deletions(-) rename src/{types/export.ts => Interfaces/ExportStrategy.ts} (71%) rename src/utils/{ExportStrategies/CsvExport.strategy.ts => BackupUtils.ts} (53%) create mode 100644 src/utils/ExportStrategies/CsvExportStrategy.ts delete mode 100644 src/utils/ExportStrategies/JsonExport.strategy.ts create mode 100644 src/utils/ExportStrategies/JsonExportStrategy.ts diff --git a/src/types/export.ts b/src/Interfaces/ExportStrategy.ts similarity index 71% rename from src/types/export.ts rename to src/Interfaces/ExportStrategy.ts index 8cfc2d75a..2e147e0c0 100644 --- a/src/types/export.ts +++ b/src/Interfaces/ExportStrategy.ts @@ -1,4 +1,3 @@ export interface ExportStrategy { export(): Promise; - getFileName(): string; } diff --git a/src/components/BackupRestoreModal.tsx b/src/components/BackupRestoreModal.tsx index b6b89e757..dba99247f 100644 --- a/src/components/BackupRestoreModal.tsx +++ b/src/components/BackupRestoreModal.tsx @@ -9,9 +9,9 @@ import { backupRestoreModal, darkModeState, displayToast, lastAction } from "@sr import "dexie-export-import"; import "./index.scss"; -import { ExportStrategy } from "@src/types/export"; -import { JsonExportStrategy } from "@src/utils/ExportStrategies/JsonExport.strategy"; -import { CsvExportStrategy } from "@src/utils/ExportStrategies/CsvExport.strategy"; +import { JsonExportStrategy } from "@src/utils/ExportStrategies/JsonExportStrategy"; +import { CsvExportStrategy } from "@src/utils/ExportStrategies/CsvExportStrategy"; +import { ExportStrategy } from "@src/Interfaces/ExportStrategy"; const backupImg = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAACXBIWXMAAAsTAAALEwEAmpwYAAADB0lEQVR4nO2Z3YtMYRzHP3a9jpc21sxQ5C1FFFHakJeibd24EQnXe4H2brkTpVUU+QMWiVLWhfdEsSHvNizLtkoJid3FLlvs6Nm+R481M7szc87OeTSfOs0855zn9/y+53n7nd+BAgUKhIHBwAJgE7Ad2AqsBRYCxTjAIuAI8BVIpDg+ArVAGSFkAnAK6LYcfg6cAA4Bh4E64FkvUXXAdELCcuC9HPsM7AYmpbl/BrALaFedVqCcPLMa+C6HTgLRDOqOV4+Zuj+BLeSJ2cA3ObIzSxuDVNcMyS5gCQER0UqzUkPCYwjwVCL2+NDOXtkyQ7QEH5kGHAc6e03ORmAdUKXydaDIh/aKgKuyWYNPlFsT0YzdR8A14LUlyAyFX8AsvxoF5smmeXgxP4x1yNlaLas2ZRLmLZ1+c0a2K3M1dFOG9vUxbyr9eGpJ2Kz2L5ID82XklSZzPojKh0+5GKnycRXKhU75MSKbykuB+zKQt41JtMiPqWRAzJpgXkBn7xf54K18OQCsAYb2VWGmtaS2aKJl1Z0+86TX3vUBqE41b8cBzbrxNDCK8DAGWAxs1KbcJT/vJovljuni5TyuUP3FRBm3rcjCCP0T7HVr956IGwxXOJRQL/WwXycO4hZx4Is6wUQgPJCQZbhHjd0JrSqMDagxMwTuBZgTSGhl44cKwwJqzFs2g6BEtttM4Y0K6d6rwypkpGybN1OuqLDeQSFzZPulKWxT4ayDQqqtdyVKrTdAk8pxRUjEisMqvJM7dOIdMMURIUdl95ayLz2Y/OsFS8yKEAuJWCLaFZn8xWjgvNXwOWADMLk/oXPAQiLAXM0JbziZXX1VqgrFurktTdI51VGfhZD6LNpJaDj90xPJKFXq/5L2GS90TnfcCFBIB9Ck1anCnhMDSZDL74BSEBI2nOyRh8BjvfSkEmKuNQB3CDEN1me2eBIhcV1LKGccWqLWd5Im5QA8ITHr2gsX8gNx66l7v/Z/u7dCT9R6+vbhRE/0JcZJER5xJdEaXRpO6Xomk8/UBfgf+A3SSyxFIXLo1QAAAABJRU5ErkJggg=="; diff --git a/src/utils/ExportStrategies/CsvExport.strategy.ts b/src/utils/BackupUtils.ts similarity index 53% rename from src/utils/ExportStrategies/CsvExport.strategy.ts rename to src/utils/BackupUtils.ts index efbc9f929..60c33ad72 100644 --- a/src/utils/ExportStrategies/CsvExport.strategy.ts +++ b/src/utils/BackupUtils.ts @@ -1,7 +1,5 @@ -import { db } from "@models"; -import { ExportStrategy } from "@src/types/export"; - -function formatCsvValue(value: any): string { +/* eslint-disable @typescript-eslint/no-explicit-any */ +export function formatCsvValue(value: any): string { if (value === null || value === undefined) { return '""'; } @@ -47,7 +45,7 @@ function formatCsvValue(value: any): string { return value.toString(); } -function convertJSONToCSV(jsonData: any[], columnHeaders: string[]): string { +export function convertJSONToCSV(jsonData: any[], columnHeaders: string[]): string { if (jsonData.length === 0) { return ""; } @@ -63,36 +61,17 @@ function convertJSONToCSV(jsonData: any[], columnHeaders: string[]): string { return headers + rows; } -export class CsvExportStrategy implements ExportStrategy { - async export(): Promise { - try { - const goals = await db.goalsCollection.toArray(); - const feelings = await db.feelingsCollection.toArray(); - const goalsCollectionKeys = db.goalsCollection.schema.indexes; - const keys = goalsCollectionKeys.map((key) => key.name); - - const csvContent = convertJSONToCSV(goals, keys); - - const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" }); - await this.downloadFile(blob); - } catch (error) { - console.error("CSV Export failed:", error); - throw error; - } - } - - static getFileName(): string { - return `ZinZen-Export-${new Date().toLocaleDateString()}.csv`; - } +export function getFileName(name: string, type: "json" | "csv"): string { + return `${name}-${new Date().toLocaleDateString()}.${type}`; +} - private async downloadFile(blob: Blob): Promise { - const url = URL.createObjectURL(blob); - const a = document.createElement("a"); - a.href = url; - a.download = CsvExportStrategy.getFileName(); - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); - URL.revokeObjectURL(url); - } +export function downloadFile(blob: Blob, fileName: string) { + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = fileName; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); } diff --git a/src/utils/ExportStrategies/CsvExportStrategy.ts b/src/utils/ExportStrategies/CsvExportStrategy.ts new file mode 100644 index 000000000..701691a70 --- /dev/null +++ b/src/utils/ExportStrategies/CsvExportStrategy.ts @@ -0,0 +1,30 @@ +import { db } from "@models"; +import { ExportStrategy } from "@src/Interfaces/ExportStrategy"; +import { convertJSONToCSV, downloadFile, getFileName } from "../BackupUtils"; + +export class CsvExportStrategy implements ExportStrategy { + // eslint-disable-next-line class-methods-use-this + async export(): Promise { + try { + const goalsArray = await db.goalsCollection.toArray(); + const feelingsArray = await db.feelingsCollection.toArray(); + const goalsCollectionKeys = db.goalsCollection.schema.indexes; + const goalsKeys = goalsCollectionKeys.map((key) => key.name); + + const feelingsCollectionKeys = db.feelingsCollection.schema.indexes; + const feelingsKeys = feelingsCollectionKeys.map((key) => key.name); + + const goalsCsvContent = convertJSONToCSV(goalsArray, goalsKeys); + const feelingsCsvContent = convertJSONToCSV(feelingsArray, feelingsKeys); + + const goalsBlob = new Blob([goalsCsvContent], { type: "text/csv;charset=utf-8;" }); + const feelingsBlob = new Blob([feelingsCsvContent], { type: "text/csv;charset=utf-8;" }); + + await downloadFile(goalsBlob, getFileName("ZinZenGoals", "csv")); + await downloadFile(feelingsBlob, getFileName("ZinZenFeelings", "csv")); + } catch (error) { + console.error("CSV Export failed:", error); + throw error; + } + } +} diff --git a/src/utils/ExportStrategies/JsonExport.strategy.ts b/src/utils/ExportStrategies/JsonExport.strategy.ts deleted file mode 100644 index af66ddeff..000000000 --- a/src/utils/ExportStrategies/JsonExport.strategy.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { db } from "@src/models"; -import { ExportStrategy } from "@src/types/export"; - -export class JsonExportStrategy implements ExportStrategy { - async export(): Promise { - const file = await db.export({ prettyJson: true }); - const blob = new Blob([file], { type: "application/json" }); - await this.downloadFile(blob); - } - - getFileName(): string { - return `ZinZenBackup-${new Date().toLocaleDateString()}.json`; - } - - private async downloadFile(blob: Blob): Promise { - const url = URL.createObjectURL(blob); - const a = document.createElement("a"); - a.href = url; - a.download = this.getFileName(); - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); - URL.revokeObjectURL(url); - } -} diff --git a/src/utils/ExportStrategies/JsonExportStrategy.ts b/src/utils/ExportStrategies/JsonExportStrategy.ts new file mode 100644 index 000000000..e9f335f44 --- /dev/null +++ b/src/utils/ExportStrategies/JsonExportStrategy.ts @@ -0,0 +1,12 @@ +import { db } from "@src/models"; +import { ExportStrategy } from "@src/Interfaces/ExportStrategy"; +import { downloadFile, getFileName } from "../BackupUtils"; + +export class JsonExportStrategy implements ExportStrategy { + // eslint-disable-next-line class-methods-use-this + async export(): Promise { + const file = await db.export({ prettyJson: true }); + const blob = new Blob([file], { type: "application/json" }); + await downloadFile(blob, getFileName("ZinZenBackup", "json")); + } +} From f83822f3e908bcfa4809aa8521971b3d3608ef23 Mon Sep 17 00:00:00 2001 From: Vinay Badgujar Date: Sat, 30 Nov 2024 18:42:59 +0530 Subject: [PATCH 16/22] format feeling's date field to not show time --- src/utils/ExportStrategies/CsvExportStrategy.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/utils/ExportStrategies/CsvExportStrategy.ts b/src/utils/ExportStrategies/CsvExportStrategy.ts index 701691a70..f99ba95f8 100644 --- a/src/utils/ExportStrategies/CsvExportStrategy.ts +++ b/src/utils/ExportStrategies/CsvExportStrategy.ts @@ -8,6 +8,15 @@ export class CsvExportStrategy implements ExportStrategy { try { const goalsArray = await db.goalsCollection.toArray(); const feelingsArray = await db.feelingsCollection.toArray(); + + // Format dates only show YYYY-MM-DD + const formattedFeelingsArray = feelingsArray.map((feeling) => ({ + ...feeling, + date: new Date(feeling.date).toISOString().slice(0, 10), + })); + + console.log(formattedFeelingsArray[0].date); + const goalsCollectionKeys = db.goalsCollection.schema.indexes; const goalsKeys = goalsCollectionKeys.map((key) => key.name); @@ -15,7 +24,7 @@ export class CsvExportStrategy implements ExportStrategy { const feelingsKeys = feelingsCollectionKeys.map((key) => key.name); const goalsCsvContent = convertJSONToCSV(goalsArray, goalsKeys); - const feelingsCsvContent = convertJSONToCSV(feelingsArray, feelingsKeys); + const feelingsCsvContent = convertJSONToCSV(formattedFeelingsArray, feelingsKeys); const goalsBlob = new Blob([goalsCsvContent], { type: "text/csv;charset=utf-8;" }); const feelingsBlob = new Blob([feelingsCsvContent], { type: "text/csv;charset=utf-8;" }); From d86c28f1c07d603e6025b10a292dee0c9cc4f900 Mon Sep 17 00:00:00 2001 From: Vinay Badgujar Date: Sat, 30 Nov 2024 18:54:56 +0530 Subject: [PATCH 17/22] only download csv if respective data is present --- .../ExportStrategies/CsvExportStrategy.ts | 42 +++++++++---------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/src/utils/ExportStrategies/CsvExportStrategy.ts b/src/utils/ExportStrategies/CsvExportStrategy.ts index f99ba95f8..137bbe7c1 100644 --- a/src/utils/ExportStrategies/CsvExportStrategy.ts +++ b/src/utils/ExportStrategies/CsvExportStrategy.ts @@ -9,28 +9,26 @@ export class CsvExportStrategy implements ExportStrategy { const goalsArray = await db.goalsCollection.toArray(); const feelingsArray = await db.feelingsCollection.toArray(); - // Format dates only show YYYY-MM-DD - const formattedFeelingsArray = feelingsArray.map((feeling) => ({ - ...feeling, - date: new Date(feeling.date).toISOString().slice(0, 10), - })); - - console.log(formattedFeelingsArray[0].date); - - const goalsCollectionKeys = db.goalsCollection.schema.indexes; - const goalsKeys = goalsCollectionKeys.map((key) => key.name); - - const feelingsCollectionKeys = db.feelingsCollection.schema.indexes; - const feelingsKeys = feelingsCollectionKeys.map((key) => key.name); - - const goalsCsvContent = convertJSONToCSV(goalsArray, goalsKeys); - const feelingsCsvContent = convertJSONToCSV(formattedFeelingsArray, feelingsKeys); - - const goalsBlob = new Blob([goalsCsvContent], { type: "text/csv;charset=utf-8;" }); - const feelingsBlob = new Blob([feelingsCsvContent], { type: "text/csv;charset=utf-8;" }); - - await downloadFile(goalsBlob, getFileName("ZinZenGoals", "csv")); - await downloadFile(feelingsBlob, getFileName("ZinZenFeelings", "csv")); + if (goalsArray.length > 0) { + const goalsCollectionKeys = db.goalsCollection.schema.indexes; + const goalsKeys = goalsCollectionKeys.map((key) => key.name); + const goalsCsvContent = convertJSONToCSV(goalsArray, goalsKeys); + const goalsBlob = new Blob([goalsCsvContent], { type: "text/csv;charset=utf-8;" }); + await downloadFile(goalsBlob, getFileName("ZinZenGoals", "csv")); + } + + if (feelingsArray.length > 0) { + const formattedFeelingsArray = feelingsArray.map((feeling) => ({ + ...feeling, + date: new Date(feeling.date).toISOString().slice(0, 10), + })); + + const feelingsCollectionKeys = db.feelingsCollection.schema.indexes; + const feelingsKeys = feelingsCollectionKeys.map((key) => key.name); + const feelingsCsvContent = convertJSONToCSV(formattedFeelingsArray, feelingsKeys); + const feelingsBlob = new Blob([feelingsCsvContent], { type: "text/csv;charset=utf-8;" }); + await downloadFile(feelingsBlob, getFileName("ZinZenFeelings", "csv")); + } } catch (error) { console.error("CSV Export failed:", error); throw error; From 86072488967e99e43987da799258f578f2528d70 Mon Sep 17 00:00:00 2001 From: HadassaAvimor Date: Thu, 11 Apr 2024 02:41:59 +0300 Subject: [PATCH 18/22] add translation to hebrew --- src/constants/languages.ts | 6 + src/translations/he/translation.json | 187 +++++++++++++++++++++++++++ src/translations/i18n.ts | 7 +- 3 files changed, 199 insertions(+), 1 deletion(-) create mode 100644 src/translations/he/translation.json diff --git a/src/constants/languages.ts b/src/constants/languages.ts index eaef6dc3d..780cf82c7 100644 --- a/src/constants/languages.ts +++ b/src/constants/languages.ts @@ -58,6 +58,12 @@ export const getLanguages = () => { langId: "gt", selected: false, }, + { + sno: 10, + title: t("hebrew"), + langId: "he", + selected: false, + }, ]; return languages; diff --git a/src/translations/he/translation.json b/src/translations/he/translation.json new file mode 100644 index 000000000..7ba84e3b5 --- /dev/null +++ b/src/translations/he/translation.json @@ -0,0 +1,187 @@ +{ + "langChoice": "?הי! באיזה שפה אתה מעוניין", + "english": "אנגלית", + "french": "צרפתית", + "hindi": "הודית", + "spanish": "ספרדית", + "german": "גרמנית", + "dutch": "הולנדית", + "marathi": "מראהטי", + "gujarati": "גוג'ראטי", + "portuguese": "פורטוגזית", + "hebrew": "עברית", + "themeChoice": "?מה אתה אוהב", + "home": "בית", + "discover": "גלה את הקוד", + "donate": "תרום", + "myGoals": "המטרות שלי", + "goalSubText": "-הוסף את המשימה שלך בפורמט", + "format": "משימה + משך + תדירות", + "addGoalPlaceholder": "הקלד את המטרה שלך + שעה + יומי", + "addTimePlaceholder": "הוסף זמן", + "myFeelings": "הרגשות שלי", + "myTime": "הזמן שלי", + "myJournal": "היומן שלי", + "explore": "חקור", + "zinzen": "ZinZen", + "feelingsMessage": "?היי! איך אתה מרגיש היום", + "feelingsMessagePast": "הי! איך הרגשת ב-: ", + "myGoalsMessage": "הוסף מטרה!", + "happy": "שמח", + "loved": "אהוב", + "relieved": "מרוחק", + "content": "מרוצה", + "peaceful": "שליו", + "joyful": "שמח", + "excited": "נרגש", + "amused": "משועשע", + "topOfTheWorld": "בראש העולם", + "proud": "גאה", + "compassionate": "רחמן", + "cheerful": "שמח", + "gratitude": "הכרת תודה", + "harmony": "הרמוניה", + "thankful": "תודה", + "triumphed": "ניצח", + "worthy": "ראוי", + "satisfied": "מרוצה", + "awed": "נדהם", + "sad": "עצוב", + "lonely": "בודד", + "gloomy": "עגום", + "disappointed": "מאוכזב", + "miserable": "אומלל", + "hopeless": "נואש", + "afraid": "מפחד", + "worried": "דואג", + "doubtful": "מפקפק", + "nervous": "חרד", + "anxious": "חרד", + "panicked": "בפאניקה", + "stressed": "מתוח", + "angry": "כועס", + "annoyed": "מוטרד", + "frustrated": "מתוסכל", + "bitter": "מר", + "infuriated": "מורת", + "mad": "כועס", + "insulted": "נפגע", + "tired": "עייף", + "sleepy": "שינה", + "drained": "מנוקז", + "exhausted": "מותש", + "feedback": "פידבק", + "opinion": " .אנחנו מעריכים את דעתך", + "rate": "בבקשה דרג את חוויתך", + "feedbackPlaceholder": "...הקלד את הפידבק כאן", + "experience": "? איך אנחנו יכולים לשפר את החוויה שלך", + "submit": "שלח", + "anonymousFeedback": "המשוב שלך הוא אנונימי. אם אתה רוצה תשובה, נא להשאיר מייל או מספר טלפון.", + "blog": "בלוג", + "backup": "גיבוי", + "changeLanguage": "שנה שפה", + "changeTheme": "שנה ערכת נושא", + "showFeelingsMessage": "הרגשות שלי", + "iHaveQuestions": "הקדמה מהירה", + "iAlreadyKnowZinZen": "דלג על ההקדמה", + "qWhatIsZinZen": "?ZinZen® מה זה", + "ansWhatIsZinZen": "מתכנן חכם.", + "qIsZinZenPrivate": "?האם זה פרטי", + "AnsIsZinZenPrivate": "כן. המידע שלך נשמר במכשיר שלך בלבד", + "qIsZinZenExpensive": "?האם זה יקר", + "ansIsZinZenExpensive": "זה בחינם - נתמך בתרומות. ללא פרסומות. שום הונאה.", + "qTooGoodToBeTrue": "?טוב מכדי להיות אמיתי", + "ansTooGoodToBeTrue": "!אל תאמין לנו, פשוט תנסה", + "iHaveDifferentQuestions": ".יש לי שאלה שונה", + "iHaveNoMoreQuestions": ".אין לי עוד שאלות כרגע", + "continue": "המשך", + "privacy": "פרטיות", + "search": "חפש", + "sharedWithMe": "שותפו עימי", + "collaborationInvites": "הזמנות לשיתוף פעולה", + "lightColors": "צבע בהיר", + "darkColors": "צבע כהה", + "darkMode": "מצב כהה", + "Sleep 😴🌙": "שינה 😴🌙", + "Breakfast 🥐🥣": "ארוחת בוקר 🥐🥣", + "Lunch 🥪": "ארוחת צהריים 🥪", + "Dinner 🍽️": "ארוחת ערב 🍽️", + "Walk 🚶🏽": "הליכה 🚶🏽", + "Water the plants 🪴 indoors": "השקיית הצמחים 🪴 בתוך הבית", + "Me time 🧘🏽😌": "הזמן שלי 🧘🏽😌", + "dontAskAgain": "לא לשאול שוב על פעולה זו?", + "note": "הערה", + "completeGoal": "השלם מטרה", + "deleteGoal": "מחק מטרה", + "shareGoal": "שתף מטרה", + "chooseContact": "בחר איש קשר", + "collaborateOnGoal": "שתף פעולה על מטרה", + "confirm": "אישור", + "cancel": "ביטול", + "duration": "משך", + "noDurationText": "לחץ שוב כדי להיכנס\n או לחץ על המעגל כדי לערוך", + "dueDate": "בשל", + "dueToday": "בשל היום", + "dueDatePassed": " ימים עברו{{days}} ", + "dueDatePassedSingular": " ימים עברו{{days}} ", + "daysLeft": " ימים נשארו{{days}} ", + "daysLeftSingular": " ימים נשארו{{days}} ", + "save": "שמור", + "goal": { + "archive": { + "header": "?האם ברצונך לסמן מטלה זו כמושלמת", + "note": ".מטלה זו תועבר לארכיון ולא תופיע במטרות הפעילות שלך יותר. תוכל לשחזר אותה בכל שלב" + }, + "delete": { + "header": "?אתה רוצה למחוק מטרה זו", + "note": ".לא תוכל לשחזר את המטרה שוב" + }, + "shareAnonymously": { + "header": "?האם ברצונך לשתף מטרה זו באופן אנונימי", + "note": "רק יעד זה והמאפיינים הקשורים לזמן שלו ישותפו בפומבי :)" + }, + "shareWithOne": { + "header": "האם אתה רוצה לשתף את המטרה הזו עם אחד מאנשי הקשר שלך?", + "note": "כל שינוי שתבצע על/תחת יעד זה ישותף עם אותו אדם." + } + }, + "collaboration": { + "colabRequest": { + "header": "?תרצה לשתף פעולה", + "note": "במהלך שיתוף הפעולה, יעד זה יתווסף ל-'מטרות שלי' שלך, וכל שינוי שתבצע יועבר לאדם האחר." + }, + "delete": { + "header": "?אתה רוצה למחוק מטרה זו", + "note": "זה יפסיק את שיתוף הפעולה ולא תקבל עדכונים על המטרה יותר" + }, + "archive": { + "header": "?האם תרצה להעביר מטרה זו לארכיון", + "note": "זה יפסיק את שיתוף הפעולה ולא תקבל עדכונים על המטרה יותר" + } + }, + "reset": "אפס", + "editTime": "ערוך זמן", + "pause": "השהה", + "start": "התחל", + "min": "דקה", + "sec": "שניה", + "goalTitle": "כותרת המטרה", + "budgetTitle": "תקציב המטרה", + "addBtnBudget": "תקציב", + "addBtnGoal": "מטרה", + "daily": "יומי", + "on": "ב", + "onWeekdays": "בימות השבוע", + "onWeekends": "בסופי השבוע", + "between": "בין", + "before": "לפני", + "after": "אחרי", + "started": "התחיל", + "starts": "מתחיל", + "perWeek": "לשבוע", + "everyWeek": "כל שבוע", + "hour": "שעה{{count}} ", + "hours": "{{count}} שעות", + "hourWithCount_one": "{{count}} שעה", + "hourWithCount_other": "{{count}} שעות" +} diff --git a/src/translations/i18n.ts b/src/translations/i18n.ts index 55e0a940c..c1203bf03 100644 --- a/src/translations/i18n.ts +++ b/src/translations/i18n.ts @@ -14,6 +14,7 @@ import TRANSLATIONS_DE from "./de/translation.json"; import TRANSLATIONS_PT from "./pt/translation.json"; import TRANSLATIONS_MR from "./mr/translation.json"; import TRANSLATIONS_GT from "./gt/translation.json"; +import TRANSLATIONS_HE from "./he/translation.json"; i18n .use(LanguageDetector) @@ -50,6 +51,9 @@ i18n gt: { translation: TRANSLATIONS_GT, }, + he: { + translation: TRANSLATIONS_HE, + }, }, }); @@ -63,7 +67,7 @@ i18n.init({ }, }); -const languagesAvailable = ["de", "en", "es", "fr", "hi", "nl", "mr", "gt"]; +const languagesAvailable = ["de", "en", "es", "fr", "hi", "nl", "mr", "gt", "he"]; const languagesFullForms: { [key: string]: string } = { de: "Deutsch", en: "English", @@ -73,5 +77,6 @@ const languagesFullForms: { [key: string]: string } = { nl: "Nederlands", mr: "मराठी", gt: "ગુજરાતી", + he: "עברית", }; export { i18n, languagesAvailable, languagesFullForms }; From 91761f9aa28280c28758e95cb12e6e2efce1ad3f Mon Sep 17 00:00:00 2001 From: HadassaAvimor Date: Fri, 19 Apr 2024 12:00:39 +0300 Subject: [PATCH 19/22] Update sections 1-3, pending section 4 revisions --- src/translations/en/translation.json | 1 + src/translations/es/translation.json | 1 + src/translations/fr/translation.json | 1 + src/translations/gt/translation.json | 1 + src/translations/he/translation.json | 14 +++++++++++++- src/translations/hi/translation.json | 1 + src/translations/mr/translation.json | 1 + src/translations/nl/translation.json | 1 + src/translations/pt/translation.json | 1 + 9 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/translations/en/translation.json b/src/translations/en/translation.json index fd5cdb7d8..1ec62d42c 100644 --- a/src/translations/en/translation.json +++ b/src/translations/en/translation.json @@ -8,6 +8,7 @@ "dutch": "Dutch", "marathi": "Marathi", "gujarati": "Gujarati", + "hebrew": "Hebrew", "portuguese": "Portuguese", "themeChoice": "What do you like?", "home": "Home", diff --git a/src/translations/es/translation.json b/src/translations/es/translation.json index 37edd2243..1e19b3c65 100644 --- a/src/translations/es/translation.json +++ b/src/translations/es/translation.json @@ -8,6 +8,7 @@ "dutch": "holandés", "marathi": "Marathi", "gujarati": "Gujarati", + "hebrew": "hebreo", "portuguese": "portugués", "themeChoice": "¿Qué te gusta?", "home": "Casa", diff --git a/src/translations/fr/translation.json b/src/translations/fr/translation.json index ee45c8168..1aec8a41c 100644 --- a/src/translations/fr/translation.json +++ b/src/translations/fr/translation.json @@ -8,6 +8,7 @@ "dutch": "néerlandais", "marathi": "Marathi", "gujarati": "Gujarati", + "hebrew": "hébreu", "portuguese": "portugais", "themeChoice": "Qu'est-ce que tu aimes?", "home": "Domicile", diff --git a/src/translations/gt/translation.json b/src/translations/gt/translation.json index 15f08d4ec..07f8f2ca2 100644 --- a/src/translations/gt/translation.json +++ b/src/translations/gt/translation.json @@ -7,6 +7,7 @@ "german": "જર્મન", "dutch": "ડચ", "marathi": "મરાઠી", + "hebrew": "હીબ્રુ", "portuguese": "પોર્ટુગીઝ", "themeChoice": "કઈ થીમ ગમે છે?", "home": "ઘર", diff --git a/src/translations/he/translation.json b/src/translations/he/translation.json index 7ba84e3b5..a5f2cdb0a 100644 --- a/src/translations/he/translation.json +++ b/src/translations/he/translation.json @@ -109,6 +109,11 @@ "Walk 🚶🏽": "הליכה 🚶🏽", "Water the plants 🪴 indoors": "השקיית הצמחים 🪴 בתוך הבית", "Me time 🧘🏽😌": "הזמן שלי 🧘🏽😌", + "Hobby project 🚂🚋": "🚂🚋 תחביבים ", + "House chores 🏡🧹🛠️": "מטלות הבית 🏡🧹🛠️", + "Family time 🥰": "🥰 זמן משפחה ", + "Work 💪🏽": " 💪🏽 עבודה", + "Daily habits 🔁": "הרגלים יומיים 🔁", "dontAskAgain": "לא לשאול שוב על פעולה זו?", "note": "הערה", "completeGoal": "השלם מטרה", @@ -183,5 +188,12 @@ "hour": "שעה{{count}} ", "hours": "{{count}} שעות", "hourWithCount_one": "{{count}} שעה", - "hourWithCount_other": "{{count}} שעות" + "hourWithCount_other": "{{count}} שעות", + "Sun": "יום א'", + "Mon": "יום ב'", + "Tue": "יום ג'", + "Wed": "יום ד'", + "Thu": "יום ה'", + "Fri": "יום ו'", + "Sat": "יום ש'" } diff --git a/src/translations/hi/translation.json b/src/translations/hi/translation.json index b276b84aa..964e713ab 100644 --- a/src/translations/hi/translation.json +++ b/src/translations/hi/translation.json @@ -8,6 +8,7 @@ "dutch": "डच", "marathi": "मराठी", "gujarati": "गुजराती", + "hebrew": "हिब्रू", "portuguese": "पुर्तगाली", "themeChoice": "क्या पसंद?", "home": "घर", diff --git a/src/translations/mr/translation.json b/src/translations/mr/translation.json index a22fec510..b36ade16a 100644 --- a/src/translations/mr/translation.json +++ b/src/translations/mr/translation.json @@ -8,6 +8,7 @@ "dutch": "डच", "marathi": "मराठी", "gujarati": "गुजराती", + "hebrew": "हिब्रू", "portuguese": "पुर्तगाली", "themeChoice": "कशाची आवड आहे?", "home": "घर", diff --git a/src/translations/nl/translation.json b/src/translations/nl/translation.json index 2b134a9ba..071310e3c 100644 --- a/src/translations/nl/translation.json +++ b/src/translations/nl/translation.json @@ -8,6 +8,7 @@ "dutch": "Nederlands", "marathi": "Marathi", "gujarati": "Gujarati", + "hebrew": "Hebreeuws", "portuguese": "Portugees", "themeChoice": "Waar hou je van?", "home": "Home", diff --git a/src/translations/pt/translation.json b/src/translations/pt/translation.json index 307d3aebf..6c791689c 100644 --- a/src/translations/pt/translation.json +++ b/src/translations/pt/translation.json @@ -8,6 +8,7 @@ "dutch": "Holandês", "marathi": "Marathi", "gujarati": "Gujarati", + "hebrew": "Hebraico", "portuguese": "Português", "themeChoice": "Do que você gosta?", "home": "Home", From 24653d3266e071358d4d9a53e6d30976666882db Mon Sep 17 00:00:00 2001 From: Vinay Badgujar Date: Fri, 6 Dec 2024 12:51:43 +0530 Subject: [PATCH 20/22] edit: add ExportManager class --- src/Interfaces/ExportStrategy.ts | 3 ++- src/components/BackupRestoreModal.tsx | 20 +++++++------------- src/utils/ExportStrategies/ExportManager.ts | 18 ++++++++++++++++++ 3 files changed, 27 insertions(+), 14 deletions(-) create mode 100644 src/utils/ExportStrategies/ExportManager.ts diff --git a/src/Interfaces/ExportStrategy.ts b/src/Interfaces/ExportStrategy.ts index 2e147e0c0..bd80d4079 100644 --- a/src/Interfaces/ExportStrategy.ts +++ b/src/Interfaces/ExportStrategy.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ export interface ExportStrategy { - export(): Promise; + export(options?: Record): Promise; } diff --git a/src/components/BackupRestoreModal.tsx b/src/components/BackupRestoreModal.tsx index dba99247f..03805d828 100644 --- a/src/components/BackupRestoreModal.tsx +++ b/src/components/BackupRestoreModal.tsx @@ -11,29 +11,21 @@ import "dexie-export-import"; import "./index.scss"; import { JsonExportStrategy } from "@src/utils/ExportStrategies/JsonExportStrategy"; import { CsvExportStrategy } from "@src/utils/ExportStrategies/CsvExportStrategy"; -import { ExportStrategy } from "@src/Interfaces/ExportStrategy"; +import { ExportManager } from "../utils/ExportStrategies/ExportManager"; const backupImg = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAACXBIWXMAAAsTAAALEwEAmpwYAAADB0lEQVR4nO2Z3YtMYRzHP3a9jpc21sxQ5C1FFFHakJeibd24EQnXe4H2brkTpVUU+QMWiVLWhfdEsSHvNizLtkoJid3FLlvs6Nm+R481M7szc87OeTSfOs0855zn9/y+53n7nd+BAgUKhIHBwAJgE7Ad2AqsBRYCxTjAIuAI8BVIpDg+ArVAGSFkAnAK6LYcfg6cAA4Bh4E64FkvUXXAdELCcuC9HPsM7AYmpbl/BrALaFedVqCcPLMa+C6HTgLRDOqOV4+Zuj+BLeSJ2cA3ObIzSxuDVNcMyS5gCQER0UqzUkPCYwjwVCL2+NDOXtkyQ7QEH5kGHAc6e03ORmAdUKXydaDIh/aKgKuyWYNPlFsT0YzdR8A14LUlyAyFX8AsvxoF5smmeXgxP4x1yNlaLas2ZRLmLZ1+c0a2K3M1dFOG9vUxbyr9eGpJ2Kz2L5ID82XklSZzPojKh0+5GKnycRXKhU75MSKbykuB+zKQt41JtMiPqWRAzJpgXkBn7xf54K18OQCsAYb2VWGmtaS2aKJl1Z0+86TX3vUBqE41b8cBzbrxNDCK8DAGWAxs1KbcJT/vJovljuni5TyuUP3FRBm3rcjCCP0T7HVr956IGwxXOJRQL/WwXycO4hZx4Is6wUQgPJCQZbhHjd0JrSqMDagxMwTuBZgTSGhl44cKwwJqzFs2g6BEtttM4Y0K6d6rwypkpGybN1OuqLDeQSFzZPulKWxT4ayDQqqtdyVKrTdAk8pxRUjEisMqvJM7dOIdMMURIUdl95ayLz2Y/OsFS8yKEAuJWCLaFZn8xWjgvNXwOWADMLk/oXPAQiLAXM0JbziZXX1VqgrFurktTdI51VGfhZD6LNpJaDj90xPJKFXq/5L2GS90TnfcCFBIB9Ck1anCnhMDSZDL74BSEBI2nOyRh8BjvfSkEmKuNQB3CDEN1me2eBIhcV1LKGccWqLWd5Im5QA8ITHr2gsX8gNx66l7v/Z/u7dCT9R6+vbhRE/0JcZJER5xJdEaXRpO6Xomk8/UBfgf+A3SSyxFIXLo1QAAAABJRU5ErkJggg=="; const restoreImg = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAACXBIWXMAAAsTAAALEwEAmpwYAAADnUlEQVR4nO2ay05UQRCGPyMMkyg3AVHcyE6jQZ5CQUVBV6hbI1FE5AHEpUFXRl4EMYTERBFBkIuSqAjISmWhxAUaLkIc08l/kg7OMJc+5zBj+JMOM3Sfrq5T1d1Vfw3s4P9FEXARuAf0AjPAN2AVWAN+ANPAE+A+cB4oDXpRo8CrFMblA83AU+A3EEuzbQD9wBWgIAhFPEGJEAE6gAVr7DrwDOiUZY4AFVpgvt7+UaARuKOxq9bzXzVnNCxFzgBz1pgp4GqGblKiZ8et+T4B9QSoiHlTj4A/6nvnp0CgDnhjye72wzqbFdkPjOl/xh1uA3n4j93ALWBZsozMSr8UOQzM6rtxqVqCR41OPU9mtasi5daE47JMWCgFXkr2PHDARZER/X0NFBI+9lhrGMtkz9hn/byrnzqizPIKcwCkhVQvtEHCQY11AJjTzXdFXhAe2q3N7+ulGTbygLdSxiiV0zgtRRZy3Sq7gAkpc4kcxzUp0keOo1T5jYm2i4MWZkL3m7rMfqmZ/KZVKYArnssq5wgQh6zTJV6bBKocZdzVXF0EaAlPifdKZwvVGpXqxrRhXSzTpHkeExDaJOBDAv8ttpS54SDnmOb4SIC5fkyWSPY2U+EEEqFcc3yP1znoQ+z0UwIKk7AtZsySowvHlOT9gzV1uvjuUgqKFAetyKI6TdicKbzcwWzsRLigMcNBudasOg1lkylaNcd0gs1eYuUW14Pa7L0pbNRkiOie8IQ0aU8UyRJ22my4rkzRpHl64nU+UKchz1xQZSkTrxklDgZ5ITaq0zCArojonhjWSWbakNzJxRIeBrTWBhIEYxs6CYwvZyv2WUGjcdm46JemhsbMVrRojYbVT4jLlh9na2I1qTWaKsCWF80XDTxF9uGs1vY5lTJEhxVuGy42m8iHKa3NBKdJERW1HxOhnC3o0Jpm0ikK1euhZZFj241aYEVrOpnuw93WG3CJv1xRYRWWHmYyQdSqiYyIUA4be60cZ9SlzlihmMlj5M33MC++Iasc50ykV1umNW52gnD2xJxkzqrY5AsqLTdbFvcaROktT6fTiuVOvheXotYBEBNbUu/jjW2qxd494W3sQGrvHuo2lacnRGOWZrgPWjaF/bOZHLEu1mm3wpmYItIB/WCgSVlcmUL6iD4fV4LVqbEeT+CFHW1BWyERCsSK9ykFiKXZ1hXFNm+XAvFQrESnSwzgtAiNNbVFEXc9GtOwVT6xA3IcfwEzCVxsbkJcggAAAABJRU5ErkJggg=="; +const exportManager = new ExportManager(new JsonExportStrategy()); + const BackupRestoreModal = () => { const open = useRecoilValue(backupRestoreModal); const darkModeStatus = useRecoilValue(darkModeState); const setShowToast = useSetRecoilState(displayToast); const setLastAction = useSetRecoilState(lastAction); - const exportData = async (strategy: ExportStrategy) => { - try { - await strategy.export(); - window.history.back(); - } catch (error) { - console.error(error); - setShowToast({ open: true, message: "Failed to export data", extra: error.message }); - } - }; - const importSuccessfull = () => { setLastAction("goalsRestored"); window.history.back(); @@ -88,9 +80,11 @@ const BackupRestoreModal = () => { style={{ display: "flex", flexDirection: "column", gap: 4 }} onClick={async () => { if (text === "Backup") { - await exportData(new JsonExportStrategy()); + exportManager.setStrategy(new JsonExportStrategy()); + await exportManager.export(); } else if (text === "CSV Export") { - await exportData(new CsvExportStrategy()); + exportManager.setStrategy(new CsvExportStrategy()); + await exportManager.export(); } else { document.getElementById("backupFileInput")?.click(); } diff --git a/src/utils/ExportStrategies/ExportManager.ts b/src/utils/ExportStrategies/ExportManager.ts new file mode 100644 index 000000000..b12fa972d --- /dev/null +++ b/src/utils/ExportStrategies/ExportManager.ts @@ -0,0 +1,18 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { ExportStrategy } from "@src/Interfaces/ExportStrategy"; + +export class ExportManager { + private strategy: ExportStrategy; + + constructor(strategy: ExportStrategy) { + this.strategy = strategy; + } + + setStrategy(strategy: ExportStrategy) { + this.strategy = strategy; + } + + async export(options?: Record): Promise { + await this.strategy.export(options); + } +} From 109a72e92389229d00df280f990619350f2da999 Mon Sep 17 00:00:00 2001 From: Vinay Badgujar Date: Fri, 6 Dec 2024 13:04:51 +0530 Subject: [PATCH 21/22] remove redundant try-catch --- src/controllers/TaskDoneTodayController.ts | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/controllers/TaskDoneTodayController.ts b/src/controllers/TaskDoneTodayController.ts index 4940dedf0..85c2a5825 100644 --- a/src/controllers/TaskDoneTodayController.ts +++ b/src/controllers/TaskDoneTodayController.ts @@ -6,22 +6,18 @@ export const completeTask = async ( scheduledStart: string, scheduledEnd: string, ) => { - try { - await addTaskDoneToday({ - scheduledTaskId, - goalId, - scheduledStart, - scheduledEnd, - }); - } catch (error) { - console.log(error); - } + await addTaskDoneToday({ + scheduledTaskId, + goalId, + scheduledStart, + scheduledEnd, + }); }; export const checkAndCleanupDoneTodayCollection = async () => { const tasks = await getAllTasksDoneToday(); - if (tasks.length === 0) { + if (!tasks.length) { return; } From dcd0500c05d97155954911df12d56b5dc84b22dd Mon Sep 17 00:00:00 2001 From: Vinay Badgujar Date: Fri, 6 Dec 2024 13:13:12 +0530 Subject: [PATCH 22/22] fix: missing useeffect dependency --- src/components/MyTimeComponents/MyTimeline/MyTimeline.tsx | 5 +++-- src/pages/MyTimePage/MyTimePage.tsx | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/components/MyTimeComponents/MyTimeline/MyTimeline.tsx b/src/components/MyTimeComponents/MyTimeline/MyTimeline.tsx index 501a7da78..ab3edfc63 100644 --- a/src/components/MyTimeComponents/MyTimeline/MyTimeline.tsx +++ b/src/components/MyTimeComponents/MyTimeline/MyTimeline.tsx @@ -13,7 +13,7 @@ import { ITask, TaskAction } from "@src/Interfaces/Task"; import { getGoal } from "@src/api/GoalsAPI"; import { GoalItem } from "@src/models/GoalItem"; import { useTranslation } from "react-i18next"; -import { displayToast, focusTaskTitle } from "@src/store"; +import { displayToast, focusTaskTitle, lastAction } from "@src/store"; import { addTask, getTaskByGoalId } from "@src/api/TasksAPI"; import "./index.scss"; @@ -47,7 +47,7 @@ export const MyTimeline: React.FC = ({ day, myTasks, doneTasks const setShowToast = useSetRecoilState(displayToast); const setTaskTitle = useSetRecoilState(focusTaskTitle); const setOpenReschedule = useSetRecoilState(displayReschedule); - + const setLastAction = useSetRecoilState(lastAction); const [displayOptionsIndex, setDisplayOptionsIndex] = useState("root"); const handleOpenGoal = async (goalId: string) => { @@ -90,6 +90,7 @@ export const MyTimeline: React.FC = ({ day, myTasks, doneTasks await completeTask(task.taskid, task.goalid, task.start, task.deadline); await addTaskActionEvent(task, "completed"); await doneSound.play(); + setLastAction("TaskCompleted"); }; const handleActionClick = async (actionName: TaskAction, task: ITask) => { diff --git a/src/pages/MyTimePage/MyTimePage.tsx b/src/pages/MyTimePage/MyTimePage.tsx index d1bdd2947..13d4e6f25 100644 --- a/src/pages/MyTimePage/MyTimePage.tsx +++ b/src/pages/MyTimePage/MyTimePage.tsx @@ -18,6 +18,8 @@ import { goalCategories } from "@src/constants/goals"; import { createGoalObjectFromTags } from "@src/helpers/GoalProcessor"; import { getAllTasksDoneToday } from "@src/api/TasksDoneTodayAPI"; import { TasksDoneTodayItem } from "@src/models/TasksDoneTodayItem"; +import { useRecoilValue } from "recoil"; +import { lastAction } from "@src/store"; export const MyTimePage = () => { const today = new Date(); @@ -26,6 +28,7 @@ export const MyTimePage = () => { const [doneTasks, setDoneTasks] = useState([]); const { state } = useLocation(); const [searchParams] = useSearchParams(); + const action = useRecoilValue(lastAction); const goalType = (searchParams.get("type") as TGoalCategory) || ""; @@ -33,7 +36,7 @@ export const MyTimePage = () => { getAllTasksDoneToday().then((task) => { setDoneTasks(task); }); - }); + }, [action]); const handleShowTasks = (dayName: string) => { if (showTasks.includes(dayName)) {