Skip to content

Commit

Permalink
Merge pull request #2044 from tijlleenders/vin/-/fix-hints
Browse files Browse the repository at this point in the history
fix: hints option not updating correctly and hints section not visible in subggoal list
  • Loading branch information
Tushar-4781 authored Oct 12, 2024
2 parents 5bdc4ef + a0ab229 commit d135a11
Show file tree
Hide file tree
Showing 11 changed files with 253 additions and 92 deletions.
12 changes: 7 additions & 5 deletions src/api/GoalsAPI/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { createGetHintsRequest, shareGoal } from "@src/services/goal.service";
import { getInstallId } from "@src/utils";
import { IHintRequestBody } from "@src/models/HintItem";
import { sortGoalsByProps } from "../GCustomAPI";
import { deleteGoalHint, deleteHintItem, getGoalHintItem } from "../HintsAPI";
import { deleteAvailableGoalHint, deleteHintItem, getGoalHintItem } from "../HintsAPI";

export const addDeletedGoal = async (goal: GoalItem) => {
await db
Expand Down Expand Up @@ -207,7 +207,7 @@ export const getHintsFromAPI = async (goal: GoalItem) => {
if (goal.parentGoalId !== "root") {
const parentGoal = await getGoal(goal.parentGoalId);
parentGoalTitle = parentGoal?.title || "";
parentGoalHint = (await getGoalHintItem(goal.parentGoalId))?.hint || false;
parentGoalHint = (await getGoalHintItem(goal.parentGoalId))?.hintOptionEnabled || false;
}

const { title, duration } = goal;
Expand Down Expand Up @@ -346,9 +346,11 @@ export const getAllLevelGoalsOfId = async (id: string, resetSharedStatus = false
};

export const addHintGoaltoMyGoals = async (goal: GoalItem) => {
await updateGoal(goal.parentGoalId, { sublist: [...goal.sublist, goal.id] });
await addGoal(goal);
await deleteGoalHint(goal.parentGoalId, goal.id);
await Promise.all([
updateGoal(goal.parentGoalId, { sublist: [...goal.sublist, goal.id] }),
addGoal(goal),
deleteAvailableGoalHint(goal.parentGoalId, goal.id),
]);
};

export const fetchArchivedGoalByTitle = async (value: string) => {
Expand Down
104 changes: 49 additions & 55 deletions src/api/HintsAPI/index.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,18 @@
import { db } from "@src/models";
import { IGoalHint } from "@src/models/HintItem";
import { HintItem, IGoalHint } from "@src/models/HintItem";
import { v4 as uuidv4 } from "uuid";

export const checkForNewGoalHints = async (hintId: string, newGoalHints: IGoalHint[]) => {
export const checkForNewGoalHints = async (hintId: string, newGoalHints: IGoalHint[]): Promise<boolean> => {
try {
const hintItem = await db.hintsCollection.get(hintId);
if (!hintItem) return false;
const currentGoalHints = hintItem.goalHints || [];
const combinedHints = [...currentGoalHints];

const existingTitles = new Set(combinedHints.map((hint) => hint.title));

const existingTitles = new Set(hintItem.availableGoalHints?.map((hint) => hint.title) || []);
return newGoalHints.some((newHint) => !existingTitles.has(newHint.title));
} catch (error) {
console.error("Error checking for new goal hints:", error);
return false;
}
};

export const ensureGoalHintsHaveIds = (goalHints: IGoalHint[]): IGoalHint[] => {
return goalHints.map((hintItem) => {
if (!hintItem.id) {
Expand All @@ -28,18 +23,18 @@ export const ensureGoalHintsHaveIds = (goalHints: IGoalHint[]): IGoalHint[] => {
};

export const getGoalHintItem = async (goalId: string) => {
const hintItem = await db.hintsCollection.where("id").equals(goalId).toArray();
return hintItem.length > 0 ? hintItem[0] : null;
const hintItem = await db.hintsCollection.where("id").equals(goalId).first();
return hintItem;
};

export const addHintItem = async (goalId: string, hint: boolean, goalHints: IGoalHint[]) => {
const updatedHintsWithId = ensureGoalHintsHaveIds(goalHints);
export const addHintItem = async (goalId: string, hintOption: boolean, availableGoalHints: IGoalHint[]) => {
const updatedAvailableGoalHintsWithId = ensureGoalHintsHaveIds(availableGoalHints);
const now = new Date();
const oneDayLater = new Date(now.getTime() + 24 * 60 * 60 * 1000);
const hintObject = {
const hintObject: HintItem = {
id: goalId,
hint,
goalHints: updatedHintsWithId,
hintOptionEnabled: hintOption,
availableGoalHints: updatedAvailableGoalHintsWithId,
lastCheckedDate: now.toISOString(),
nextCheckDate: oneDayLater.toISOString(),
};
Expand All @@ -52,44 +47,43 @@ export const addHintItem = async (goalId: string, hint: boolean, goalHints: IGoa
});
};

export const updateHintItem = async (goalId: string, hint: boolean, goalHints: IGoalHint[]) => {
const updatedHintsWithId = ensureGoalHintsHaveIds(goalHints);
const isNewHintPresent = await checkForNewGoalHints(goalId, updatedHintsWithId);

const oneDay = 24 * 60 * 60 * 1000;
const oneWeek = 7 * oneDay;
export const updateHintItem = async (goalId: string, hintOptionEnabled: boolean, availableGoalHints: IGoalHint[]) => {
try {
const updatedGoalHintsWithId = ensureGoalHintsHaveIds(availableGoalHints);
const hasNewHints = await checkForNewGoalHints(goalId, updatedGoalHintsWithId);

const now = new Date();
const nextCheckDate = new Date(now.getTime() + (isNewHintPresent ? oneDay : oneWeek));
const now = new Date();
const nextCheckDate = new Date(
now.getTime() + (hasNewHints ? 24 * 60 * 60 * 1000 : 7 * 24 * 60 * 60 * 1000),
).toISOString();

await db
.transaction("rw", db.hintsCollection, async () => {
await db.transaction("rw", db.hintsCollection, async () => {
const existingItem = await db.hintsCollection.where("id").equals(goalId).first();

if (existingItem) {
const filteredHintsWithId = updatedHintsWithId.filter(
(hintItem) =>
const filteredGoalHints = updatedGoalHintsWithId.filter(
(hint) =>
!existingItem.deletedGoalHints ||
!existingItem.deletedGoalHints.some((deletedHint) => deletedHint.title === hintItem.title),
!existingItem.deletedGoalHints.some((deletedHint) => deletedHint.title === hint.title),
);

await db.hintsCollection.update(goalId, {
hint,
goalHints: filteredHintsWithId,
hintOptionEnabled,
availableGoalHints: filteredGoalHints,
lastCheckedDate: now.toISOString(),
nextCheckDate: nextCheckDate.toISOString(),
nextCheckDate,
});
} else {
const newHints = goalHints.map((hintItem) => ({
...hintItem,
id: hintItem.id || uuidv4(),
const newGoalHints = updatedGoalHintsWithId.map((hint) => ({
...hint,
id: hint.id || uuidv4(),
}));
await addHintItem(goalId, hint, newHints);
await addHintItem(goalId, hintOptionEnabled, newGoalHints);
}
})
.catch((e) => {
console.log(e.stack || e);
});
} catch (error) {
console.error("Failed to update hint item:", error);
}
};

export const deleteHintItem = async (goalId: string) => {
Expand All @@ -102,30 +96,30 @@ export const deleteHintItem = async (goalId: string) => {
});
};

export const deleteGoalHint = async (parentGoalId: string, goalId: string) => {
await db
.transaction("rw", db.hintsCollection, async () => {
export const deleteAvailableGoalHint = async (parentGoalId: string, goalId: string) => {
try {
await db.transaction("rw", db.hintsCollection, async () => {
const goalHintsItem = await db.hintsCollection.get(parentGoalId);

if (goalHintsItem) {
const updatedGoalHints = goalHintsItem.goalHints.filter((hint) => hint.id !== goalId);
const deletedGoalHint = goalHintsItem.goalHints.find((hint) => hint.id === goalId);
const { availableGoalHints, deletedGoalHints = [] } = goalHintsItem;

const updatedDeletedGoalHints = goalHintsItem.deletedGoalHints ? [...goalHintsItem.deletedGoalHints] : [];
const deletedGoalHint = availableGoalHints.find((hint) => hint.id === goalId);
const updatedGoalHints = availableGoalHints.filter((hint) => hint.id !== goalId);

if (deletedGoalHint) {
const deletedHintDetails: IGoalHint = { ...deletedGoalHint };
delete deletedHintDetails.id;
updatedDeletedGoalHints.push(deletedHintDetails);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { id, ...deletedHintDetails } = deletedGoalHint;
const updatedDeletedGoalHints = [...deletedGoalHints, deletedHintDetails];

await db.hintsCollection.update(parentGoalId, {
availableGoalHints: updatedGoalHints,
deletedGoalHints: updatedDeletedGoalHints,
});
}

await db.hintsCollection.update(parentGoalId, {
goalHints: updatedGoalHints,
deletedGoalHints: updatedDeletedGoalHints,
});
}
})
.catch((e) => {
console.log(e.stack || e);
});
} catch (e) {
console.error("Failed to delete available goal hint:", e);
}
};
12 changes: 6 additions & 6 deletions src/components/GoalsComponents/GoalConfigModal/ConfigGoal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,11 @@ const ConfigGoal = ({ type, goal, mode }: { type: TGoalCategory; mode: TGoalConf

const [betweenSliderUpdated, setBetweenSliderUpdated] = useState(false);

const [hints, setHints] = useState(false);
const [hintOption, setHintOption] = useState(false);

useEffect(() => {
getGoalHintItem(goal.id).then((hintItem) => {
setHints(!!hintItem?.hint);
setHintOption(!!hintItem?.hintOptionEnabled);
});
}, [goal.id]);

Expand Down Expand Up @@ -143,7 +143,7 @@ const ConfigGoal = ({ type, goal, mode }: { type: TGoalCategory; mode: TGoalConf
extra: "",
});
}
await (isEditMode ? updateGoal(getFinalTags(), hints) : addGoal(getFinalTags(), hints, parentGoal));
await (isEditMode ? updateGoal(getFinalTags(), hintOption) : addGoal(getFinalTags(), hintOption, parentGoal));
} else {
setShowToast({
open: true,
Expand Down Expand Up @@ -261,7 +261,7 @@ const ConfigGoal = ({ type, goal, mode }: { type: TGoalCategory; mode: TGoalConf
setPerWeekHrs(selectedPerWeekBudget);
}
const hint = await getGoalHintItem(selectedGoal.id);
setHints(hint?.hint || false);
setHintOption(hint?.hintOptionEnabled || false);
};

const titlePlaceholder = t(`${type !== "Budget" ? "goal" : "budget"}Title`);
Expand Down Expand Up @@ -398,7 +398,7 @@ const ConfigGoal = ({ type, goal, mode }: { type: TGoalCategory; mode: TGoalConf
))}
</div>
<div className="action-btn-container">
<HintToggle setHints={setHints} defaultValue={hints} />
<HintToggle setHints={setHintOption} defaultValue={hintOption} />
<button type="submit" className="action-btn place-middle gap-16">
{t(`${action} Budget`)}
</button>
Expand All @@ -407,7 +407,7 @@ const ConfigGoal = ({ type, goal, mode }: { type: TGoalCategory; mode: TGoalConf
) : (
<div className="d-flex f-col gap-16">
<div className="action-btn-container">
<HintToggle setHints={setHints} defaultValue={hints} />
<HintToggle setHints={setHintOption} defaultValue={hintOption} />
<button type="submit" className="action-btn place-middle gap-16">
{t(`${action} Goal`)}
</button>
Expand Down
18 changes: 12 additions & 6 deletions src/components/GoalsComponents/GoalSublist/GoalSublist.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ import { lastAction } from "@src/store";
import { getGoalHintItem } from "@src/api/HintsAPI";
import { priotizeImpossibleGoals } from "@src/utils/priotizeImpossibleGoals";
import { useParentGoalContext } from "@src/contexts/parentGoal-context";
import { AvailableGoalHintProvider } from "@src/contexts/availableGoalHint-context";
import { DeletedGoalProvider } from "@src/contexts/deletedGoal-context";
import DeletedGoals from "@pages/GoalsPage/components/DeletedGoals";
import ArchivedGoals from "@pages/GoalsPage/components/ArchivedGoals";
import { TrashItem } from "@src/models/TrashItem";
import GoalItemSummary from "@src/common/GoalItemSummary/GoalItemSummary";
import AvailableGoalHints from "@pages/GoalsPage/components/AvailableGoalHints";
import GoalsList from "../GoalsList";
import GoalHistory from "./components/GoalHistory";
import "./GoalSublist.scss";
Expand All @@ -26,24 +28,25 @@ export const GoalSublist = () => {
const [activeGoals, setActiveGoals] = useState<GoalItem[]>([]);
const [deletedGoals, setDeletedGoals] = useState<TrashItem[]>([]);
const [archivedChildren, setArchivedChildren] = useState<GoalItem[]>([]);
const [goalhints, setGoalHints] = useState<GoalItem[]>([]);
const [goalHints, setGoalHints] = useState<GoalItem[]>([]);
const { t } = useTranslation();
const action = useRecoilValue(lastAction);
const goalID = useRecoilValue(displayGoalId);
const showChangesModal = useRecoilValue(displayChangesModal);
const showSuggestionModal = useRecoilValue(displaySuggestionsModal);

useEffect(() => {
getGoalHintItem(goalID).then((hintItem) => {
if (parentGoal === undefined) return;
getGoalHintItem(parentGoal?.id).then((hintItem) => {
const array: GoalItem[] = [];
hintItem?.goalHints?.forEach((hint) => {
if (hint) {
array.push(createGoalObjectFromTags({ ...hint, parentGoalId: goalID }));
hintItem?.availableGoalHints?.forEach((availableGoalHint) => {
if (availableGoalHint) {
array.push(createGoalObjectFromTags({ ...availableGoalHint, parentGoalId: parentGoal.id }));
}
});
setGoalHints(array || []);
});
}, [goalID, action]);
}, [action, parentGoal, showSuggestionModal, showChangesModal, subgoals, goalID]);

useEffect(() => {
async function init() {
Expand Down Expand Up @@ -80,6 +83,9 @@ export const GoalSublist = () => {
)}
<div className="sublist-list-container">
<GoalsList goals={activeGoals} setGoals={setGoals} />
<AvailableGoalHintProvider goalHints={goalHints}>
<AvailableGoalHints goals={goalHints} />
</AvailableGoalHintProvider>
<DeletedGoalProvider>
{deletedGoals.length > 0 && <DeletedGoals goals={deletedGoals} />}
</DeletedGoalProvider>
Expand Down
37 changes: 37 additions & 0 deletions src/contexts/availableGoalHint-context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { GoalItem } from "@src/models/GoalItem";
import React, { ReactNode, createContext, useContext, useEffect, useMemo, useState } from "react";
import { useParams } from "react-router-dom";

type AvailableGoalHintContext = {
goal: GoalItem | undefined;
setGoal: React.Dispatch<React.SetStateAction<GoalItem | undefined>>;
};

export const AvailableGoalHintContext = createContext<AvailableGoalHintContext | undefined>(undefined);

export const AvailableGoalHintProvider = ({ children, goalHints }: { children: ReactNode; goalHints: GoalItem[] }) => {
const { activeGoalId, partnerId } = useParams();
const [goal, setGoal] = useState<GoalItem>();
const isPartnerModeActive = !!partnerId;

useEffect(() => {
if (activeGoalId) {
const hint = goalHints.find((goalItem) => {
return goalItem.id === activeGoalId;
});
setGoal(hint);
}
}, [isPartnerModeActive, activeGoalId]);

const value = useMemo(() => ({ goal, setGoal }), [goal]);

return <AvailableGoalHintContext.Provider value={value}>{children}</AvailableGoalHintContext.Provider>;
};

export const useAvailableGoalHintContext = () => {
const context = useContext(AvailableGoalHintContext);
if (!context) {
throw new Error("useAvailableGoalHintContext must be used within a AvailableGoalHintContext");
}
return context;
};
23 changes: 14 additions & 9 deletions src/helpers/GoalController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ import { addHintItem, updateHintItem } from "@src/api/HintsAPI";
import { restoreUserGoal } from "@src/api/TrashAPI";
import { sendFinalUpdateOnGoal, sendUpdatedGoal } from "./PubSubController";

export const createGoal = async (newGoal: GoalItem, parentGoalId: string, ancestors: string[], goalHint: boolean) => {
export const createGoal = async (newGoal: GoalItem, parentGoalId: string, ancestors: string[], hintOption: boolean) => {
const level = ancestors.length;
if (goalHint) {
if (hintOption) {
getHintsFromAPI(newGoal)
.then((hints) => addHintItem(newGoal.id, goalHint, hints || []))
.then((hints) => addHintItem(newGoal.id, hintOption, hints || []))
.catch((error) => console.error("Error fetching hints:", error));
}

Expand Down Expand Up @@ -47,14 +47,19 @@ export const createGoal = async (newGoal: GoalItem, parentGoalId: string, ancest
return { parentGoal: null };
};

export const modifyGoal = async (goalId: string, goalTags: GoalItem, ancestors: string[], goalHint: boolean) => {
const hintsPromise = getHintsFromAPI(goalTags);
if (goalHint) {
hintsPromise
.then((hints) => updateHintItem(goalTags.id, goalHint, hints))
export const modifyGoal = async (
goalId: string,
goalTags: GoalItem,
ancestors: string[],
hintOptionEnabled: boolean,
) => {
if (hintOptionEnabled) {
const availableHintsPromise = getHintsFromAPI(goalTags);
availableHintsPromise
.then((availableGoalHints) => updateHintItem(goalTags.id, hintOptionEnabled, availableGoalHints))
.catch((err) => console.error("Error updating hints:", err));
} else {
updateHintItem(goalTags.id, goalHint, []);
updateHintItem(goalTags.id, hintOptionEnabled, []);
}
console.log(goalTags);
await updateGoal(goalId, goalTags);
Expand Down
Loading

0 comments on commit d135a11

Please sign in to comment.