diff --git a/src/api/GoalsAPI/index.ts b/src/api/GoalsAPI/index.ts index 9290c9050..b0cd37cae 100644 --- a/src/api/GoalsAPI/index.ts +++ b/src/api/GoalsAPI/index.ts @@ -353,14 +353,29 @@ export const addHintGoaltoMyGoals = async (goal: GoalItem) => { ]); }; -export const fetchArchivedGoalByTitle = async (value: string) => { - if (value.trim() === "") { +export const fetchArchivedDescendantGoalByTitle = async (goalTitle: string, parentGoalId: string) => { + if (!goalTitle.trim()) { return []; } - const lowerCaseValue = value.toLowerCase(); - return db.goalsCollection - .where("archived") - .equals("true") - .and((goal) => goal.title.toLowerCase().startsWith(lowerCaseValue)) - .toArray(); + + const searchTitle = goalTitle.toLowerCase(); + + const getAllChildrenGoals = async (id: string): Promise => { + const directChildren = await getChildrenGoals(id); + + const allDescendantGoals = await Promise.all( + directChildren.map(async (child) => { + const grandchildren = await getAllChildrenGoals(child.id); + return [child, ...grandchildren]; + }), + ); + + return allDescendantGoals.flat(); + }; + + const allDescendantGoals = await getAllChildrenGoals(parentGoalId); + + return allDescendantGoals.filter( + (goal) => goal.archived === "true" && goal.title.toLowerCase().startsWith(searchTitle), + ); }; diff --git a/src/components/GoalsComponents/GoalConfigModal/ConfigGoal.tsx b/src/components/GoalsComponents/GoalConfigModal/ConfigGoal.tsx index c47e1704d..56541b32f 100644 --- a/src/components/GoalsComponents/GoalConfigModal/ConfigGoal.tsx +++ b/src/components/GoalsComponents/GoalConfigModal/ConfigGoal.tsx @@ -17,7 +17,10 @@ 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 { useLocation, useNavigate } from "react-router-dom"; import { suggestedGoalState } from "@src/store/SuggestedGoalState"; +import { getHistoryUptoGoal } from "@src/helpers/GoalProcessor"; import { colorPalleteList, calDays, convertOnFilterToArray, getSelectedLanguage } from "../../../utils"; import "./ConfigGoal.scss"; @@ -41,6 +44,9 @@ const ConfigGoal = ({ type, goal, mode }: { type: TGoalCategory; mode: TGoalConf parentData: { parentGoal }, } = useParentGoalContext(); + const location = useLocation(); + const navigate = useNavigate(); + let defaultColorIndex = Math.floor(Math.random() * colorPalleteList.length - 1) + 1; let defaultAfterTime = isEditMode ? (goal.afterTime ?? 9) : 9; let defaultBeforeTime = isEditMode ? (goal.beforeTime ?? 18) : 18; @@ -156,7 +162,12 @@ const ConfigGoal = ({ type, goal, mode }: { type: TGoalCategory; mode: TGoalConf } if (suggestedGoal) { await unarchiveUserGoal(suggestedGoal); + navigate(`/goals/${suggestedGoal.parentGoalId === "root" ? "" : suggestedGoal.parentGoalId}`, { + state: { ...location.state }, + replace: true, + }); setSuggestedGoal(null); + return; } window.history.back(); }; @@ -217,15 +228,17 @@ const ConfigGoal = ({ type, goal, mode }: { type: TGoalCategory; mode: TGoalConf handleWeekSliderChange(perWeekHrs); }, [perDayHrs, setPerDayHrs, tags.on]); - // const modalStyle = { - // transform: `translate(0, ${isKeyboardOpen ? "-45%" : "0"})`, - // transition: "transform 0.3s ease-in-out", - // }; - const { openEditMode } = useGoalStore(); const onSuggestionClick = async (selectedGoal: GoalItem) => { - openEditMode(selectedGoal); + const updatedGoalsHistory = await getHistoryUptoGoal(selectedGoal.parentGoalId); + + const newState: ILocationState = { + ...location.state, + goalsHistory: updatedGoalsHistory, + }; + + openEditMode(selectedGoal, newState); setSuggestedGoal(selectedGoal); setTitle(selectedGoal.title); setColorIndex(colorPalleteList.indexOf(selectedGoal.goalColor)); diff --git a/src/components/GoalsComponents/GoalConfigModal/components/ArchivedAutoComplete.tsx b/src/components/GoalsComponents/GoalConfigModal/components/ArchivedAutoComplete.tsx index 85e670573..ff0c91fb3 100644 --- a/src/components/GoalsComponents/GoalConfigModal/components/ArchivedAutoComplete.tsx +++ b/src/components/GoalsComponents/GoalConfigModal/components/ArchivedAutoComplete.tsx @@ -1,7 +1,8 @@ import React, { useState, useCallback } from "react"; import { GoalItem } from "@src/models/GoalItem"; import AutocompleteComponent from "@components/GoalsComponents/GoalConfigModal/components/AutoComplete"; -import { fetchArchivedGoalByTitle } from "@src/api/GoalsAPI"; +import { fetchArchivedDescendantGoalByTitle } from "@src/api/GoalsAPI"; +import { useParentGoalContext } from "@src/contexts/parentGoal-context"; interface ArchivedAutoCompleteProps { onGoalSelect: (goal: GoalItem) => void; @@ -17,11 +18,19 @@ const ArchivedAutoComplete: React.FC = ({ placeholder, }) => { const [filteredGoals, setFilteredGoals] = useState([]); + const { + parentData: { parentGoal }, + } = useParentGoalContext(); - const searchArchivedGoals = useCallback(async (value: string) => { - const goals = await fetchArchivedGoalByTitle(value); - setFilteredGoals(goals); - }, []); + const parentGoalId = parentGoal ? parentGoal.id : "root"; + + const searchArchivedGoals = useCallback( + async (value: string) => { + const goals = await fetchArchivedDescendantGoalByTitle(value, parentGoalId); + setFilteredGoals(goals); + }, + [parentGoalId], + ); const handleInputChange = useCallback( (value: string) => { diff --git a/src/contexts/parentGoal-context.tsx b/src/contexts/parentGoal-context.tsx index acfec0532..413be6d6a 100644 --- a/src/contexts/parentGoal-context.tsx +++ b/src/contexts/parentGoal-context.tsx @@ -3,6 +3,7 @@ import { getSharedWMChildrenGoals, getSharedWMGoalById } from "@src/api/SharedWM import { GoalItem } from "@src/models/GoalItem"; import { lastAction } from "@src/store"; import { allowAddingBudgetGoal } from "@src/store/GoalsState"; +import { suggestedGoalState } from "@src/store/SuggestedGoalState"; import React, { ReactNode, createContext, useContext, useEffect, useMemo, useReducer } from "react"; import { useParams } from "react-router-dom"; import { useRecoilValue, useSetRecoilState } from "recoil"; @@ -46,6 +47,7 @@ export const ParentGoalProvider = ({ children }: { children: ReactNode }) => { const setAllowBudgetGoal = useSetRecoilState(allowAddingBudgetGoal); const [parentData, dispatch] = useReducer(parentGoalReducer, initialState); const isPartnerModeActive = !!partnerId; + const suggestedGoal = useRecoilValue(suggestedGoalState); async function init() { if (parentId !== "root") { @@ -67,6 +69,12 @@ export const ParentGoalProvider = ({ children }: { children: ReactNode }) => { init(); }, [parentId]); + useEffect(() => { + if (!suggestedGoal) { + init(); + } + }, [suggestedGoal]); + useEffect(() => { if (action === "goalArchived") { return; diff --git a/src/hooks/useGoalActions.tsx b/src/hooks/useGoalActions.tsx index d46a7a965..20d0925e7 100644 --- a/src/hooks/useGoalActions.tsx +++ b/src/hooks/useGoalActions.tsx @@ -10,7 +10,7 @@ import { useLocation, useParams } from "react-router-dom"; import pageCrumplingSound from "@assets/page-crumpling-sound.mp3"; import plingSound from "@assets/pling.mp3"; -import { useSetRecoilState } from "recoil"; +import { useRecoilValue, useSetRecoilState } from "recoil"; import { shareGoalWithContact } from "@src/services/contact.service"; import { addToSharingQueue } from "@src/api/ContactsAPI"; import { ILocationState } from "@src/Interfaces"; @@ -18,6 +18,7 @@ import { hashObject } from "@src/utils"; import { useActiveGoalContext } from "@src/contexts/activeGoal-context"; import { removeBackTicks } from "@src/utils/patterns"; import { getGoalHintItem } from "@src/api/HintsAPI"; +import { suggestedGoalState } from "@src/store/SuggestedGoalState"; const pageCrumple = new Audio(pageCrumplingSound); const addGoalSound = new Audio(plingSound); @@ -31,6 +32,7 @@ const useGoalActions = () => { const subGoalsHistory = state?.goalsHistory || []; const ancestors = subGoalsHistory.map((ele) => ele.goalID); const { goal: activeGoal } = useActiveGoalContext(); + const suggestedGoal = useRecoilValue(suggestedGoalState); const setShowToast = useSetRecoilState(displayToast); @@ -92,7 +94,7 @@ const useGoalActions = () => { setLastAction("goalUpdated"); setShowToast({ open: true, - message: "Goal updated!", + message: suggestedGoal ? "Goal (re)created!" : "Goal updated!", extra: "", }); addGoalSound.play(); diff --git a/src/hooks/useGoalStore.tsx b/src/hooks/useGoalStore.tsx index bb89e762c..238e4a495 100644 --- a/src/hooks/useGoalStore.tsx +++ b/src/hooks/useGoalStore.tsx @@ -1,7 +1,8 @@ import { useLocation, useNavigate, useParams } from "react-router-dom"; import { useRecoilValue } from "recoil"; -import { GoalItem, TGoalCategory } from "@src/models/GoalItem"; +import { GoalItem } from "@src/models/GoalItem"; import { displayConfirmation } from "@src/store"; +import { ILocationState } from "@src/Interfaces"; const useGoalStore = () => { const { partnerId } = useParams(); @@ -9,12 +10,14 @@ const useGoalStore = () => { const location = useLocation(); const showConfirmation = useRecoilValue(displayConfirmation); - const openEditMode = (goal: GoalItem) => { + const openEditMode = (goal: GoalItem, customState?: ILocationState) => { const prefix = `${partnerId ? `/partners/${partnerId}/` : "/"}goals`; + navigate(`${prefix}/${goal.parentGoalId}/${goal.id}?type=${goal.category}&mode=edit`, { state: { ...location.state, goalType: goal.category === "Budget" ? "Budget" : "Goal", + ...customState, }, replace: true, });