Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin' into vin/1918/move-goal
Browse files Browse the repository at this point in the history
  • Loading branch information
vinaybadgujar102 committed Dec 15, 2024
2 parents e279062 + 2380f37 commit 3525dab
Show file tree
Hide file tree
Showing 53 changed files with 812 additions and 177 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
.env.development.local
.env.test.local
.env.production.local
.idea

npm-debug.log*
yarn-debug.log*
Expand Down
5 changes: 5 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# No CLA

Unlike some open source projects, we don't require a Contributor License Agreement.
This is a strong guarantee that the code will remain open forever - even when the project gets popular.

# Branching convention

[developer shortcut]/[issue number]/[meaningful name]
Expand Down
29 changes: 24 additions & 5 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,38 @@ const App = () => {
}`,
});
};
const handleClick = () => {
api.destroy();

const handleOutsideClick = (e: MouseEvent) => {
const notifications = document.getElementsByClassName("ant-notification-notice");
let clickedInside = false;

Array.from(notifications).forEach((notificationElement) => {
if (notificationElement.contains(e.target as Node)) {
clickedInside = true;
}
});

if (!clickedInside) {
setTimeout(() => {
api.destroy();
}, 0);
}
};

useEffect(() => {
if (showToast.open) {
openNotification();
setShowToast({ ...showToast, open: false });
}
document.addEventListener("click", handleClick);
}, [showToast]);

useEffect(() => {
document.addEventListener("click", handleOutsideClick, true);
return () => {
document.removeEventListener("click", handleClick);
document.removeEventListener("click", handleOutsideClick, true);
};
}, [showToast]);
}, []);

return (
<div className={`${darkModeEnabled ? "dark" : "light"}-theme${theme[darkModeEnabled ? "dark" : "light"]}`}>
<div className={`App-${darkModeEnabled ? "dark" : "light"}`}>
Expand Down
4 changes: 4 additions & 0 deletions src/Interfaces/ExportStrategy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
export interface ExportStrategy {
export(options?: Record<string, any>): Promise<void>;
}
2 changes: 2 additions & 0 deletions src/Interfaces/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,5 @@ export interface ILocationState {
export interface ImpossibleGoal extends GoalItem {
impossible: boolean;
}

export type ScheduleStatus = "pending" | "scheduled" | "impossible" | "future" | null;
6 changes: 6 additions & 0 deletions src/api/GoalsAPI/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ 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";
import { deleteTaskHistoryItem } from "../TaskHistoryAPI";

export const addDeletedGoal = async (goal: GoalItem) => {
await db
Expand Down Expand Up @@ -173,6 +175,8 @@ export const removeChildrenGoals = async (parentGoalId: string, permanently = fa
childrenGoals.forEach((goal) => {
removeChildrenGoals(goal.id, permanently);
removeGoal(goal, permanently);
deleteTasksDoneTodayByGoalId(goal.id);
deleteTaskHistoryItem(goal.id);
});
};

Expand Down Expand Up @@ -315,6 +319,8 @@ export const notifyNewColabRequest = async (id: string, relId: string) => {
export const removeGoalWithChildrens = async (goal: GoalItem, permanently = false) => {
await removeChildrenGoals(goal.id, permanently);
await removeGoal(goal, permanently);
await deleteTasksDoneTodayByGoalId(goal.id);
await deleteTaskHistoryItem(goal.id);
if (goal.parentGoalId !== "root") {
getGoal(goal.parentGoalId).then(async (parentGoal: GoalItem) => {
const parentGoalSublist = parentGoal.sublist;
Expand Down
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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,
Expand Down
22 changes: 22 additions & 0 deletions src/api/TaskHistoryAPI/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { db } from "@src/models";
import { TaskHistoryEvents, TaskHistoryItem } from "@src/models/TaskHistoryItem";
import { ITask } from "@src/Interfaces/Task";

export async function addTaskActionEvent(task: ITask, eventType: TaskHistoryEvents) {
if (!task) return;

const newEvent: TaskHistoryItem = {
goalId: task.goalid,
eventType,
duration: task.duration,
scheduledStart: task.start,
scheduledEnd: task.deadline,
eventTime: new Date().toISOString(),
};

await db.taskHistoryCollection.add(newEvent);
}

export async function deleteTaskHistoryItem(goalId: string) {
await db.taskHistoryCollection.where("goalId").equals(goalId).delete();
}
40 changes: 0 additions & 40 deletions src/api/TasksAPI/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -106,45 +105,6 @@ 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 skipTask = async (id: string, period: string, task: ITask) => {
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]));
}
});
}).catch((e) => {
console.log(e.stack || e);
});
};

export const getAllTasks = async () => {
const allGoals = await db.taskCollection.toArray();
Expand Down
44 changes: 44 additions & 0 deletions src/api/TasksDoneTodayAPI/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { db } from "@src/models";
import { TasksDoneTodayItem } from "@src/models/TasksDoneTodayItem";

export const addTaskDoneToday = async (completedTask: TasksDoneTodayItem) => {
try {
await db.tasksDoneTodayCollection.add(completedTask);
} catch (error) {
console.error("Error adding task:", error);
}
};

export const getAllTasksDoneToday = async () => {
try {
const tasks = await db.tasksDoneTodayCollection.toArray();
return tasks;
} catch (error) {
console.error("Error fetching tasks:", error);
return [];
}
};

export const deleteTaskDoneToday = async (id: string) => {
try {
await db.tasksDoneTodayCollection.delete(id);
} catch (error) {
console.error("Error deleting task:", error);
}
};

export const deleteTasksDoneTodayByGoalId = async (goalId: string) => {
try {
await db.tasksDoneTodayCollection.where("goalId").equals(goalId).delete();
} catch (error) {
console.error("Error deleting tasks by goalId:", error);
}
};

export const deleteAllTasksDoneToday = async () => {
try {
await db.tasksDoneTodayCollection.clear();
} catch (error) {
console.error("Error clearing tasks:", error);
}
};
31 changes: 14 additions & 17 deletions src/components/BackupRestoreModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,23 @@ import { backupRestoreModal, darkModeState, displayToast, lastAction } from "@sr

import "dexie-export-import";
import "./index.scss";
import { JsonExportStrategy } from "@src/utils/ExportStrategies/JsonExportStrategy";
import { CsvExportStrategy } from "@src/utils/ExportStrategies/CsvExportStrategy";
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 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 importSuccessfull = () => {
setLastAction("goalsRestored");
window.history.back();
Expand Down Expand Up @@ -80,32 +73,36 @@ const BackupRestoreModal = () => {
}
};

const getOption = (text: "Backup" | "Restore") => (
const getOption = (text: "Backup" | "CSV Export" | "Restore") => (
<button
type="button"
className={`default-btn${darkModeStatus ? "-dark" : ""}`}
style={{ display: "flex", flexDirection: "column", gap: 4 }}
onClick={async () => {
if (text === "Backup") {
await backupData();
window.history.back();
exportManager.setStrategy(new JsonExportStrategy());
await exportManager.export();
} else if (text === "CSV Export") {
exportManager.setStrategy(new CsvExportStrategy());
await exportManager.export();
} else {
document.getElementById("backupFileInput")?.click();
}
}}
>
<img className="secondary-icon" alt={`${text} data`} src={text === "Backup" ? backupImg : restoreImg} />
<img className="secondary-icon" alt={`${text}`} src={text === "Restore" ? restoreImg : backupImg} />
<p>{text}</p>
</button>
);

return (
<ZModal open={open} onCancel={() => window.history.back()} type="backupRestoreModal">
<p className="popupModal-title" style={{ textAlign: "center" }}>
{" "}
Choose an option from below
</p>
<div style={{ display: "flex", justifyContent: "center", gap: "60px" }}>
{getOption("Backup")}
{getOption("CSV Export")}
{getOption("Restore")}
</div>
<input type="file" id="backupFileInput" style={{ display: "none" }} onChange={restoreData} />
Expand Down
2 changes: 1 addition & 1 deletion src/components/GlobalAddBtn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { allowAddingBudgetGoal } from "@src/store/GoalsState";
import useLongPress from "@src/hooks/useLongPress";
import { useKeyPress } from "@src/hooks/useKeyPress";
import { moveGoalState } from "@src/store/moveGoalState";
import { moveGoalHierarchy } from "@src/helpers/GoalController";
import { moveGoalHierarchy } from "@src/controllers/GoalController";
import { displayToast, lastAction } from "@src/store";
import { useParentGoalContext } from "@src/contexts/parentGoal-context";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -19,12 +19,16 @@ import SubHeader from "@src/common/SubHeader";
import ContactItem from "@src/models/ContactItem";
import ZModal from "@src/common/ZModal";

import { addGoalToNewParentSublist, getAllDescendants, removeGoalFromParentSublist } from "@src/helpers/GoalController";
import Header from "./Header";
import AcceptBtn from "./AcceptBtn";
import IgnoreBtn from "./IgnoreBtn";
import "./DisplayChangesModal.scss";
import { getMovedSubgoalsList } from "./ShowChanges";
import {
addGoalToNewParentSublist,
getAllDescendants,
removeGoalFromParentSublist,
} from "@src/controllers/GoalController";

const DisplayChangesModal = ({ currentMainGoal }: { currentMainGoal: GoalItem }) => {
const darkModeStatus = useRecoilValue(darkModeState);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,8 @@
gap: 10px;
justify-content: center;
}

.schedule-status {
margin-top: 8px;
text-align: center;
}
Loading

0 comments on commit 3525dab

Please sign in to comment.