Skip to content

Commit 3573f47

Browse files
committed
Restructure the CoachingSessionSelector to use the API hooks instead of useEffect blocks, which allows the list to be updated with a call to refresh() from the OverarchingGoalContainer
1 parent d5faa25 commit 3573f47

File tree

2 files changed

+41
-90
lines changed

2 files changed

+41
-90
lines changed

src/components/ui/coaching-session-selector.tsx

Lines changed: 40 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,18 @@ import {
1212
} from "@/components/ui/select";
1313
import { getDateTimeFromString, Id } from "@/types/general";
1414
import { useCoachingSessionList } from "@/lib/api/coaching-sessions";
15-
import { useEffect, useState } from "react";
15+
import { useEffect } from "react";
1616
import { DateTime } from "ts-luxon";
1717
import { useCoachingSessionStateStore } from "@/lib/providers/coaching-session-state-store-provider";
18-
import { OverarchingGoalApi } from "@/lib/api/overarching-goals";
19-
import { OverarchingGoal } from "@/types/overarching-goal";
2018
import { CoachingSession } from "@/types/coaching-session";
19+
import {
20+
useOverarchingGoalBySession,
21+
useOverarchingGoalList,
22+
} from "@/lib/api/overarching-goals";
2123

2224
interface CoachingSessionsSelectorProps extends PopoverProps {
23-
/// The CoachingRelationship Id for which to get a list of associated CoachingSessions
2425
relationshipId: Id;
25-
/// Disable the component from interaction with the user
2626
disabled: boolean;
27-
/// Called when a CoachingSession is selected
2827
onSelect?: (coachingSessionId: Id) => void;
2928
}
3029

@@ -33,81 +32,28 @@ function CoachingSessionsSelectItems({
3332
}: {
3433
relationshipId: Id;
3534
}) {
36-
// TODO: for now we hardcode a 2 month window centered around now,
37-
// eventually we want to make this be configurable somewhere
38-
// (either on the page or elsewhere)
3935
const fromDate = DateTime.now().minus({ month: 1 });
4036
const toDate = DateTime.now().plus({ month: 1 });
4137

4238
const {
4339
coachingSessions,
4440
isLoading: isLoadingSessions,
4541
isError: isErrorSessions,
46-
refresh,
4742
} = useCoachingSessionList(relationshipId, fromDate, toDate);
4843

4944
const { setCurrentCoachingSessions } = useCoachingSessionStateStore(
5045
(state) => state
5146
);
52-
const [goals, setGoals] = useState<(OverarchingGoal[] | undefined)[]>([]);
53-
const [isLoadingGoals, setIsLoadingGoals] = useState(false);
5447

5548
useEffect(() => {
5649
if (!coachingSessions.length) return;
5750
setCurrentCoachingSessions(coachingSessions);
5851
}, [coachingSessions]);
5952

60-
useEffect(() => {
61-
const fetchGoals = async () => {
62-
setIsLoadingGoals(true);
63-
try {
64-
const sessionIds = coachingSessions?.map((session) => session.id) || [];
65-
const goalsPromises = sessionIds.map((id) =>
66-
OverarchingGoalApi.list(id)
67-
);
68-
const fetchedGoals = await Promise.all(goalsPromises);
69-
setGoals(fetchedGoals);
70-
} catch (error) {
71-
console.error("Error fetching goals:", error);
72-
} finally {
73-
setIsLoadingGoals(false);
74-
}
75-
};
76-
77-
if (coachingSessions?.length) {
78-
fetchGoals();
79-
}
80-
}, [coachingSessions]);
81-
82-
if (isLoadingSessions || isLoadingGoals) return <div>Loading...</div>;
53+
if (isLoadingSessions) return <div>Loading...</div>;
8354
if (isErrorSessions) return <div>Error loading coaching sessions</div>;
8455
if (!coachingSessions?.length) return <div>No coaching sessions found</div>;
8556

86-
const SessionItem = ({
87-
session,
88-
goals,
89-
sessionIndex,
90-
}: {
91-
session: CoachingSession;
92-
goals: (OverarchingGoal[] | undefined)[];
93-
sessionIndex: number;
94-
}) => (
95-
<SelectItem value={session.id}>
96-
<div className="flex min-w-0 w-[calc(100%-20px)]">
97-
<div className="min-w-0 w-full">
98-
<p className="truncate text-sm font-medium">
99-
{goals[sessionIndex]?.[0]?.title || "No goal set"}
100-
</p>
101-
<p className="truncate text-sm text-gray-400">
102-
{getDateTimeFromString(session.date).toLocaleString(
103-
DateTime.DATETIME_FULL
104-
)}
105-
</p>
106-
</div>
107-
</div>
108-
</SelectItem>
109-
);
110-
11157
return (
11258
<>
11359
{[
@@ -129,14 +75,7 @@ function CoachingSessionsSelectItems({
12975
{coachingSessions
13076
.filter((session) => condition(session.date))
13177
.map((session) => (
132-
<SessionItem
133-
key={session.id}
134-
session={session}
135-
goals={goals}
136-
sessionIndex={coachingSessions.findIndex(
137-
(s) => s.id === session.id
138-
)}
139-
/>
78+
<SessionItemWithGoal key={session.id} session={session} />
14079
))}
14180
</SelectGroup>
14281
)
@@ -145,6 +84,33 @@ function CoachingSessionsSelectItems({
14584
);
14685
}
14786

87+
// Separate component to handle individual session goal fetching
88+
function SessionItemWithGoal({ session }: { session: CoachingSession }) {
89+
const { overarchingGoal, isLoading, isError } = useOverarchingGoalBySession(
90+
session.id
91+
);
92+
93+
if (isLoading) return <div>Loading goal...</div>;
94+
if (isError) return <div>Error loading goal</div>;
95+
96+
return (
97+
<SelectItem value={session.id}>
98+
<div className="flex min-w-0">
99+
<div className="min-w-0 w-full">
100+
<p className="truncate text-sm font-medium">
101+
{overarchingGoal.title || "No goal set"}
102+
</p>
103+
<p className="truncate text-sm text-gray-400">
104+
{getDateTimeFromString(session.date).toLocaleString(
105+
DateTime.DATETIME_FULL
106+
)}
107+
</p>
108+
</div>
109+
</div>
110+
</SelectItem>
111+
);
112+
}
113+
148114
export default function CoachingSessionSelector({
149115
relationshipId,
150116
disabled,
@@ -157,31 +123,15 @@ export default function CoachingSessionSelector({
157123
getCurrentCoachingSession,
158124
} = useCoachingSessionStateStore((state) => state);
159125

160-
const [currentGoal, setCurrentGoal] = useState<OverarchingGoal | undefined>();
161-
const [isLoadingGoal, setIsLoadingGoal] = useState(false);
162-
163126
const currentSession = currentCoachingSessionId
164127
? getCurrentCoachingSession(currentCoachingSessionId)
165128
: null;
166129

167-
useEffect(() => {
168-
const fetchGoal = async () => {
169-
if (!currentCoachingSessionId) return;
170-
171-
setIsLoadingGoal(true);
172-
try {
173-
const goals = await OverarchingGoalApi.list(currentCoachingSessionId);
174-
setCurrentGoal(goals[0]);
175-
} catch (error) {
176-
console.error("Error fetching goal:", error);
177-
} finally {
178-
setIsLoadingGoal(false);
179-
}
180-
};
181-
182-
fetchGoal();
183-
}, [currentCoachingSessionId]);
184-
130+
const {
131+
overarchingGoal,
132+
isLoading: isLoadingGoal,
133+
isError: isErrorGoal,
134+
} = useOverarchingGoalBySession(currentCoachingSessionId);
185135
const handleSetCoachingSession = (coachingSessionId: Id) => {
186136
setCurrentCoachingSessionId(coachingSessionId);
187137
if (onSelect) {
@@ -192,7 +142,7 @@ export default function CoachingSessionSelector({
192142
const displayValue = currentSession ? (
193143
<div className="flex flex-col w-full">
194144
<span className="truncate text-left">
195-
{currentGoal?.title || "No goal set"}
145+
{isLoadingGoal ? "Loading..." : overarchingGoal.title || "No goal set"}
196146
</span>
197147
<span className="text-sm text-gray-500 text-left truncate">
198148
{getDateTimeFromString(currentSession.date).toLocaleString(

src/components/ui/coaching-sessions/overarching-goal-container.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
1515
import { OverarchingGoalComponent } from "./overarching-goal";
1616
import {
1717
useOverarchingGoalBySession,
18+
useOverarchingGoalList,
1819
useOverarchingGoalMutation,
1920
} from "@/lib/api/overarching-goals";
2021
import {

0 commit comments

Comments
 (0)