Skip to content

Commit e84da34

Browse files
authored
Merge pull request #2 from RecentRunner/mason
Mason
2 parents 9641b12 + 5f66e56 commit e84da34

11 files changed

Lines changed: 728 additions & 402 deletions

components/avatar/avatar-status-card.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,14 @@ export function AvatarStatusCard() {
2929
const [isReady, setIsReady] = useState(false);
3030

3131
useEffect(() => {
32-
const checkedIn = hasCompletedDailyQuizToday();
33-
setHasCheckedInToday(checkedIn);
34-
setCondition(getAvatarConditionForToday() ?? defaultAvatarCondition);
35-
setIsReady(true);
32+
async function loadStatus() {
33+
const checkedIn = await hasCompletedDailyQuizToday();
34+
setHasCheckedInToday(checkedIn);
35+
setCondition((await getAvatarConditionForToday()) ?? defaultAvatarCondition);
36+
setIsReady(true);
37+
}
38+
39+
void loadStatus();
3640
}, []);
3741

3842
if (!isReady) {

components/daily-quiz/daily-quiz-form.tsx

Lines changed: 103 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"use client";
22

3+
import { CheckCircle2 } from "lucide-react";
34
import { useEffect, useState } from "react";
45

56
import { PixelAvatar } from "@/components/avatar/pixel-avatar";
@@ -16,19 +17,18 @@ import {
1617
import { Label } from "@/components/ui/label";
1718
import {
1819
defaultDailyQuizAnswers,
20+
formatSleepHours,
21+
SLEEP_HOURS_MAX,
22+
SLEEP_HOURS_MIN,
23+
SLEEP_HOURS_STEP,
1924
WELLNESS_SCALE_MAX,
2025
type DailyQuizAnswers,
2126
type DailyQuizSubmission,
2227
} from "@/lib/avatar-state";
2328
import {
24-
getDailyQuizSubmission,
25-
getTodayDateKey,
26-
saveDailyQuizSubmission,
29+
getDailyEntryForToday,
30+
saveDailyEntry,
2731
} from "@/lib/daily-quiz-storage";
28-
import {
29-
getJournalEntryForToday,
30-
saveJournalEntry,
31-
} from "@/lib/journal-storage";
3232

3333
export function DailyQuizForm() {
3434
const [answers, setAnswers] = useState<DailyQuizAnswers>(
@@ -44,19 +44,23 @@ export function DailyQuizForm() {
4444

4545
useEffect(() => {
4646
async function loadDailyCheckIn() {
47-
const existingSubmission = getDailyQuizSubmission();
48-
const existingJournal = await getJournalEntryForToday();
49-
50-
if (existingSubmission?.date === getTodayDateKey()) {
51-
setSubmission(existingSubmission);
52-
setAnswers(existingSubmission.answers);
53-
}
47+
try {
48+
const existingEntry = await getDailyEntryForToday();
5449

55-
if (existingJournal) {
56-
setJournal(existingJournal.content);
50+
if (existingEntry) {
51+
setSubmission(existingEntry);
52+
setAnswers(existingEntry.answers);
53+
setJournal(existingEntry.journal);
54+
}
55+
} catch (loadError) {
56+
setError(
57+
loadError instanceof Error
58+
? loadError.message
59+
: "Could not load today's check-in.",
60+
);
61+
} finally {
62+
setIsReady(true);
5763
}
58-
59-
setIsReady(true);
6064
}
6165

6266
void loadDailyCheckIn();
@@ -84,9 +88,8 @@ export function DailyQuizForm() {
8488
setError(null);
8589

8690
try {
87-
const savedSubmission = saveDailyQuizSubmission(answers);
88-
await saveJournalEntry(journal);
89-
setSubmission(savedSubmission);
91+
const savedEntry = await saveDailyEntry(answers, journal);
92+
setSubmission(savedEntry);
9093
} catch (submitError) {
9194
setError(
9295
submitError instanceof Error
@@ -106,18 +109,77 @@ export function DailyQuizForm() {
106109

107110
return (
108111
<div className="flex flex-col gap-6">
109-
<div className="flex items-center justify-between">
110-
<Badge>Today&apos;s check-in</Badge>
111-
<Badge variant={isCompleted ? "default" : "outline"}>
112-
{isCompleted ? "Completed" : "Not completed"}
113-
</Badge>
114-
</div>
115-
116-
<Card>
112+
{isCompleted && submission ? (
113+
<>
114+
<Card className="border-primary/40 bg-primary/10">
115+
<CardContent className="flex items-start gap-4 pt-6">
116+
<div className="rounded-full bg-primary/15 p-2.5">
117+
<CheckCircle2
118+
aria-hidden="true"
119+
className="h-7 w-7 text-primary"
120+
/>
121+
</div>
122+
<div className="space-y-1">
123+
<p className="text-lg font-semibold tracking-tight">
124+
Today&apos;s quiz is complete
125+
</p>
126+
<p className="text-sm text-muted-foreground">
127+
Your wellness check-in and journal are saved for today. You
128+
can review your answers below, and come back tomorrow for
129+
your next quiz.
130+
</p>
131+
</div>
132+
</CardContent>
133+
</Card>
134+
135+
<Card>
136+
<CardHeader>
137+
<CardTitle className="text-base">Your pet today</CardTitle>
138+
<CardDescription>
139+
Based on the wellness check-in you already submitted.
140+
</CardDescription>
141+
</CardHeader>
142+
<CardContent className="flex flex-col items-center gap-4">
143+
<PixelAvatar mood={submission.condition.mood} size="md" />
144+
<div className="grid w-full grid-cols-3 gap-2 text-center text-sm">
145+
<div className="rounded-lg border bg-background px-3 py-2">
146+
<p className="text-muted-foreground">Mood</p>
147+
<p className="font-medium capitalize">
148+
{submission.condition.mood}
149+
</p>
150+
</div>
151+
<div className="rounded-lg border bg-background px-3 py-2">
152+
<p className="text-muted-foreground">Energy</p>
153+
<p className="font-medium">
154+
{submission.condition.energy}/{WELLNESS_SCALE_MAX}
155+
</p>
156+
</div>
157+
<div className="rounded-lg border bg-background px-3 py-2">
158+
<p className="text-muted-foreground">Health</p>
159+
<p className="font-medium">
160+
{submission.condition.health}/{WELLNESS_SCALE_MAX}
161+
</p>
162+
</div>
163+
</div>
164+
</CardContent>
165+
</Card>
166+
</>
167+
) : (
168+
<div className="flex items-center justify-between">
169+
<Badge>Today&apos;s check-in</Badge>
170+
<Badge variant="outline">Not completed</Badge>
171+
</div>
172+
)}
173+
174+
<Card className={isCompleted ? "opacity-90" : undefined}>
117175
<CardHeader>
118-
<CardTitle className="text-base">Wellness</CardTitle>
176+
<CardTitle className="text-base">
177+
{isCompleted ? "Your answers today" : "Wellness"}
178+
</CardTitle>
119179
<CardDescription>
120-
Sliders from 1 to 5 for how you&apos;re doing today.
180+
{isCompleted
181+
? "These fields are locked until tomorrow's quiz."
182+
: "Rate your wellness from 1 to 5. Sleep length uses hours."}
121183
</CardDescription>
122184
</CardHeader>
123185
<CardContent className="space-y-5">
@@ -146,6 +208,10 @@ export function DailyQuizForm() {
146208
id="sleep-length"
147209
label="How long did you sleep?"
148210
value={answers.sleepLength}
211+
min={SLEEP_HOURS_MIN}
212+
max={SLEEP_HOURS_MAX}
213+
step={SLEEP_HOURS_STEP}
214+
formatValue={formatSleepHours}
149215
disabled={isCompleted}
150216
onChange={(value) => updateAnswer("sleepLength", value)}
151217
/>
@@ -159,11 +225,13 @@ export function DailyQuizForm() {
159225
</CardContent>
160226
</Card>
161227

162-
<Card>
228+
<Card className={isCompleted ? "opacity-90" : undefined}>
163229
<CardHeader>
164230
<CardTitle className="text-base">Daily journal</CardTitle>
165231
<CardDescription>
166-
Write about your day. Saved separately from your quiz answers.
232+
{isCompleted
233+
? "Your journal entry for today."
234+
: "Write about your day."}
167235
</CardDescription>
168236
</CardHeader>
169237
<CardContent className="space-y-3">
@@ -183,37 +251,11 @@ export function DailyQuizForm() {
183251

184252
{error ? <p className="text-sm text-red-500">{error}</p> : null}
185253

186-
{isCompleted && submission ? (
187-
<Card>
188-
<CardContent className="flex flex-col items-center gap-4 pt-6">
189-
<PixelAvatar mood={submission.condition.mood} size="md" />
190-
<div className="grid w-full grid-cols-3 gap-2 text-center text-sm">
191-
<div className="rounded-lg border px-3 py-2">
192-
<p className="text-muted-foreground">Mood</p>
193-
<p className="font-medium capitalize">
194-
{submission.condition.mood}
195-
</p>
196-
</div>
197-
<div className="rounded-lg border px-3 py-2">
198-
<p className="text-muted-foreground">Energy</p>
199-
<p className="font-medium">
200-
{submission.condition.energy}/{WELLNESS_SCALE_MAX}
201-
</p>
202-
</div>
203-
<div className="rounded-lg border px-3 py-2">
204-
<p className="text-muted-foreground">Health</p>
205-
<p className="font-medium">
206-
{submission.condition.health}/{WELLNESS_SCALE_MAX}
207-
</p>
208-
</div>
209-
</div>
210-
</CardContent>
211-
</Card>
212-
) : (
254+
{!isCompleted ? (
213255
<Button className="w-full" disabled={!canSubmit} onClick={handleSubmit}>
214256
{isSubmitting ? "Saving..." : "Complete daily quiz"}
215257
</Button>
216-
)}
258+
) : null}
217259
</div>
218260
);
219261
}

components/daily-quiz/daily-quiz-link-button.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,12 @@ export function DailyQuizLinkButton() {
1212
const [isReady, setIsReady] = useState(false);
1313

1414
useEffect(() => {
15-
setIsCompleted(hasCompletedDailyQuizToday());
16-
setIsReady(true);
15+
async function loadStatus() {
16+
setIsCompleted(await hasCompletedDailyQuizToday());
17+
setIsReady(true);
18+
}
19+
20+
void loadStatus();
1721
}, []);
1822

1923
if (!isReady || isCompleted) {

0 commit comments

Comments
 (0)