Skip to content

Commit 40a88ee

Browse files
committed
Force end sessions / revamp of activity component
1 parent 36f85f7 commit 40a88ee

4 files changed

Lines changed: 238 additions & 108 deletions

File tree

components/profile/activity.tsx

Lines changed: 84 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,12 @@ const Activity: FC<Props> = ({
129129
const [adjustReason, setAdjustReason] = useState("");
130130
const [adjustType, setAdjustType] = useState<"award" | "remove">("award");
131131
const [submittingAdjust, setSubmittingAdjust] = useState(false);
132+
const [localSessions, setLocalSessions] = useState(sessions);
133+
134+
// keep in sync if prop changes (e.g. week switch)
135+
useEffect(() => {
136+
setLocalSessions(sessions);
137+
}, [sessions]);
132138

133139
// Update displayMinutes when timeSpent prop changes (e.g., when switching between weeks)
134140
useEffect(() => {
@@ -139,7 +145,9 @@ const Activity: FC<Props> = ({
139145
const fetchConfig = async () => {
140146
if (id) {
141147
try {
142-
const res = await axios.get(`/api/workspace/${id}/settings/activity/getConfig`);
148+
const res = await axios.get(
149+
`/api/workspace/${id}/settings/activity/getConfig`,
150+
);
143151
setIdleTimeEnabled(res.data.idleTimeEnabled ?? true);
144152
} catch (error) {
145153
console.error("Failed to fetch activity config:", error);
@@ -183,11 +191,11 @@ const Activity: FC<Props> = ({
183191
minutes: val,
184192
action: adjustType,
185193
reason: adjustReason,
186-
}
194+
},
187195
);
188196
if (!data.success) throw new Error("Failed");
189197
setDisplayMinutes(
190-
(prev) => prev + (adjustType === "remove" ? -val : val)
198+
(prev) => prev + (adjustType === "remove" ? -val : val),
191199
);
192200
toast.success("Adjustment saved!");
193201
setAdjustModal(false);
@@ -209,7 +217,10 @@ const Activity: FC<Props> = ({
209217
Activity
210218
</Tab>
211219
<Tab className={({ selected }) => profileTabClass(selected)}>
212-
<IconCalendarEvent className="w-3.5 h-3.5 sm:w-4 sm:h-4" stroke={1.75} />
220+
<IconCalendarEvent
221+
className="w-3.5 h-3.5 sm:w-4 sm:h-4"
222+
stroke={1.75}
223+
/>
213224
Sessions
214225
</Tab>
215226
<Tab className={({ selected }) => profileTabClass(selected)}>
@@ -233,11 +244,11 @@ const Activity: FC<Props> = ({
233244
{selectedWeek > 0 && availableHistory[selectedWeek - 1] ? (
234245
<>
235246
{moment(
236-
availableHistory[selectedWeek - 1].period.start
247+
availableHistory[selectedWeek - 1].period.start,
237248
).format("MMM DD")}{" "}
238249
-{" "}
239250
{moment(
240-
availableHistory[selectedWeek - 1].period.end
251+
availableHistory[selectedWeek - 1].period.end,
241252
).format("MMM DD, YYYY")}
242253
</>
243254
) : (
@@ -273,39 +284,69 @@ const Activity: FC<Props> = ({
273284
) : (
274285
<div>
275286
{isHistorical && historicalPeriod && (
276-
<div className="mb-6 rounded-xl bg-amber-500/10 p-4">
277-
<div className="flex items-center gap-3">
278-
<div className="rounded-lg bg-amber-500/15 p-2">
279-
<IconCalendarTime className="h-5 w-5 text-amber-600 dark:text-amber-400" stroke={1.75} />
280-
</div>
281-
<div>
282-
<h3 className="text-sm font-medium text-amber-900 dark:text-amber-200">
283-
Historical Activity Data
284-
</h3>
285-
<p className="text-xs text-amber-700 dark:text-amber-300">
286-
Showing activity from{" "}
287-
{moment(historicalPeriod.start).format("MMM DD")} -{" "}
288-
{moment(historicalPeriod.end).format("MMM DD, YYYY")}
289-
</p>
287+
<div className="mb-6 rounded-xl bg-amber-500/10 p-4">
288+
<div className="flex items-center gap-3">
289+
<div className="rounded-lg bg-amber-500/15 p-2">
290+
<IconCalendarTime
291+
className="h-5 w-5 text-amber-600 dark:text-amber-400"
292+
stroke={1.75}
293+
/>
294+
</div>
295+
<div>
296+
<h3 className="text-sm font-medium text-amber-900 dark:text-amber-200">
297+
Historical Activity Data
298+
</h3>
299+
<p className="text-xs text-amber-700 dark:text-amber-300">
300+
Showing activity from{" "}
301+
{moment(historicalPeriod.start).format("MMM DD")} -{" "}
302+
{moment(historicalPeriod.end).format("MMM DD, YYYY")}
303+
</p>
304+
</div>
290305
</div>
291306
</div>
292-
</div>
293307
)}
294308

295309
<Tab.Panels className="min-h-[400px]">
296310
<Tab.Panel>
297311
{!isHistorical && canAdjustActivity && (
298-
<div className="mb-4 flex justify-end">
299-
<button
300-
onClick={() => setAdjustModal(true)}
301-
className={profilePrimaryButtonClass}
302-
>
303-
<IconAdjustments className="h-4 w-4" stroke={1.75} />
304-
Manual Adjustment
305-
</button>
306-
</div>
307-
)}
312+
<div className="mb-4 flex justify-end">
313+
<button
314+
onClick={() => setAdjustModal(true)}
315+
className={profilePrimaryButtonClass}
316+
>
317+
<IconAdjustments className="h-4 w-4" stroke={1.75} />
318+
Manual Adjustment
319+
</button>
320+
</div>
321+
)}
308322
<ActivityOverview
323+
onEndSession={(sid, wid) => {
324+
toast.loading("Ending session...", {
325+
id: `session-${sid}`,
326+
});
327+
axios
328+
.post("/api/activity/force-end", {
329+
sessionId: sid,
330+
workspaceId: wid,
331+
})
332+
.then(() => {
333+
toast.success("Session ended", {
334+
id: `session-${sid}`,
335+
});
336+
setLocalSessions((prev) =>
337+
prev.map((s) =>
338+
s.id === sid
339+
? { ...s, active: false, endTime: new Date() }
340+
: s,
341+
),
342+
);
343+
})
344+
.catch(() => {
345+
toast.error("Failed to end session", {
346+
id: `session-${sid}`,
347+
});
348+
});
349+
}}
309350
data={data}
310351
displayMinutes={displayMinutes}
311352
messages={messages}
@@ -315,13 +356,13 @@ const Activity: FC<Props> = ({
315356
idleTimeEnabled={idleTimeEnabled}
316357
notices={notices}
317358
adjustments={adjustments}
318-
sessions={sessions}
359+
sessions={localSessions}
319360
avatar={avatar}
320361
/>
321362
</Tab.Panel>
322363
<Tab.Panel>
323364
<SessionsHistory
324-
sessions={sessions}
365+
sessions={localSessions}
325366
notices={notices}
326367
adjustments={adjustments}
327368
avatar={avatar}
@@ -374,7 +415,9 @@ const Activity: FC<Props> = ({
374415
leaveFrom="opacity-100 scale-100"
375416
leaveTo="opacity-0 scale-95"
376417
>
377-
<Dialog.Panel className={`w-full max-w-md transform overflow-hidden rounded-2xl bg-white p-6 text-left align-middle transition-all dark:bg-zinc-900 ${profilePanelShadow}`}>
418+
<Dialog.Panel
419+
className={`w-full max-w-md transform overflow-hidden rounded-2xl bg-white p-6 text-left align-middle transition-all dark:bg-zinc-900 ${profilePanelShadow}`}
420+
>
378421
<Dialog.Title
379422
as="h3"
380423
className="mb-4 text-lg font-semibold text-zinc-900 dark:text-white"
@@ -394,7 +437,9 @@ const Activity: FC<Props> = ({
394437
type="button"
395438
onClick={() => setAdjustType("remove")}
396439
className={`flex-1 ${profileTabClass(adjustType === "remove")} ${
397-
adjustType === "remove" ? "!bg-red-600 !text-white dark:!bg-red-600" : ""
440+
adjustType === "remove"
441+
? "!bg-red-600 !text-white dark:!bg-red-600"
442+
: ""
398443
}`}
399444
>
400445
Remove
@@ -413,8 +458,8 @@ const Activity: FC<Props> = ({
413458
setAdjustMinutes(
414459
Math.min(
415460
1000,
416-
Math.max(0, parseInt(e.target.value, 10) || 0)
417-
)
461+
Math.max(0, parseInt(e.target.value, 10) || 0),
462+
),
418463
)
419464
}
420465
className={profileInputClass}
@@ -453,8 +498,8 @@ const Activity: FC<Props> = ({
453498
{submittingAdjust
454499
? "Saving..."
455500
: adjustType === "award"
456-
? "Award Minutes"
457-
: "Remove Minutes"}
501+
? "Award Minutes"
502+
: "Remove Minutes"}
458503
</button>
459504
</div>
460505
</Dialog.Panel>

0 commit comments

Comments
 (0)