added windows notifications and have avatar health/energy update with task completion

This commit is contained in:
masongga
2026-05-24 00:11:23 -06:00
parent 25fb5499c1
commit dfafba0c94
12 changed files with 842 additions and 33 deletions

View File

@@ -1,7 +1,7 @@
"use client";
import Link from "next/link";
import { useEffect, useState } from "react";
import { useCallback, useEffect, useState } from "react";
import { PixelAvatar } from "@/components/avatar/pixel-avatar";
import { Badge } from "@/components/ui/badge";
@@ -15,10 +15,12 @@ import {
WELLNESS_SCALE_MAX,
type AvatarCondition,
} from "@/lib/avatar-state";
import { HABIT_PET_DATA_UPDATED_EVENT } from "@/lib/app-events";
import {
getAvatarConditionForToday,
hasCompletedDailyQuizToday,
} from "@/lib/daily-quiz-storage";
import { getCompletedHabitLabelsForToday } from "@/lib/habits-storage";
import { routes } from "@/lib/routes";
export function AvatarStatusCard() {
@@ -26,19 +28,32 @@ export function AvatarStatusCard() {
defaultAvatarCondition,
);
const [hasCheckedInToday, setHasCheckedInToday] = useState(false);
const [completedTaskCount, setCompletedTaskCount] = useState(0);
const [isReady, setIsReady] = useState(false);
useEffect(() => {
async function loadStatus() {
const checkedIn = await hasCompletedDailyQuizToday();
setHasCheckedInToday(checkedIn);
setCondition((await getAvatarConditionForToday()) ?? defaultAvatarCondition);
setIsReady(true);
}
const loadStatus = useCallback(async () => {
const [checkedIn, nextCondition, completedLabels] = await Promise.all([
hasCompletedDailyQuizToday(),
getAvatarConditionForToday(),
getCompletedHabitLabelsForToday(),
]);
void loadStatus();
setHasCheckedInToday(checkedIn);
setCondition(nextCondition ?? defaultAvatarCondition);
setCompletedTaskCount(completedLabels.length);
setIsReady(true);
}, []);
useEffect(() => {
void loadStatus();
window.addEventListener(HABIT_PET_DATA_UPDATED_EVENT, loadStatus);
return () => {
window.removeEventListener(HABIT_PET_DATA_UPDATED_EVENT, loadStatus);
};
}, [loadStatus]);
if (!isReady) {
return (
<Card>
@@ -68,8 +83,12 @@ export function AvatarStatusCard() {
</div>
<p className="text-center text-sm text-muted-foreground">
{hasCheckedInToday
? "Your pet is reacting to today's wellness check-in and journal."
: "Complete today's quiz to update your pet's mood, energy, and health."}
? completedTaskCount > 0
? `Your pet reacts to today's quiz and ${completedTaskCount} completed task${completedTaskCount === 1 ? "" : "s"}. Meals, hydration, sleep, and relaxing habits boost health and mood.`
: "Your pet is reacting to today's wellness check-in. Complete habits to boost mood, energy, and health."
: completedTaskCount > 0
? "Complete today's quiz for a full wellness read, then keep completing habits to boost your pet."
: "Complete today's quiz to update your pet's mood, energy, and health."}
</p>
{!hasCheckedInToday ? (
<Button asChild className="w-full">