fix: post-purchase crash in CelebrationOverlay (read of null current)
Card read useCelebrationStore(s=>s.current)! but AnimatePresence keeps it mounted through the exit animation; after dismiss() sets current=null it re-rendered and threw "Cannot read properties of null (reading 'levelAfter')", crashing the page after every purchase/XP/daily celebration. Pass the celebration as a prop so the exiting card keeps its data. Verified: tsc + next build clean; web rebuilt on :1500. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
import { AnimatePresence, motion } from "framer-motion";
|
import { AnimatePresence, motion } from "framer-motion";
|
||||||
import { Coins, Sparkles, Star, TrendingUp } from "lucide-react";
|
import { Coins, Sparkles, Star, TrendingUp } from "lucide-react";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { useCelebrationStore } from "@/lib/celebration-store";
|
import { useCelebrationStore, type Celebration } from "@/lib/celebration-store";
|
||||||
import { useI18n } from "@/lib/i18n";
|
import { useI18n } from "@/lib/i18n";
|
||||||
import { sound } from "@/lib/sound";
|
import { sound } from "@/lib/sound";
|
||||||
import { stickerPackForAchievement } from "@/lib/online/gamification";
|
import { stickerPackForAchievement } from "@/lib/online/gamification";
|
||||||
@@ -45,15 +45,17 @@ export function CelebrationOverlay() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{current && <Card key={current.id} />}
|
{current && <Card key={current.id} c={current} />}
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function Card() {
|
// Takes the celebration as a PROP (not from the store) so it keeps its data while
|
||||||
|
// AnimatePresence runs the exit animation after dismiss() sets `current` to null.
|
||||||
|
function Card({ c }: { c: Celebration }) {
|
||||||
const { t, locale } = useI18n();
|
const { t, locale } = useI18n();
|
||||||
const current = useCelebrationStore((s) => s.current)!;
|
|
||||||
const dismiss = useCelebrationStore((s) => s.dismiss);
|
const dismiss = useCelebrationStore((s) => s.dismiss);
|
||||||
|
const current = c;
|
||||||
const leveled = (current.levelAfter ?? 0) > (current.levelBefore ?? 0);
|
const leveled = (current.levelAfter ?? 0) > (current.levelBefore ?? 0);
|
||||||
const xp = useCountUp(current.xpGained ?? 0, 900, current.variant === "xp");
|
const xp = useCountUp(current.xpGained ?? 0, 900, current.variant === "xp");
|
||||||
const coins = useCountUp(current.coins ?? 0, 1000, (current.coins ?? 0) > 0);
|
const coins = useCountUp(current.coins ?? 0, 1000, (current.coins ?? 0) > 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user