From b37a7ffc5b19f7330050970ebac7f949a89812a2 Mon Sep 17 00:00:00 2001 From: Pinapelz Date: Mon, 3 Aug 2026 17:37:22 -0700 Subject: feat: group streaks - maintain completion streaks as a group - join via a provided code, streaks increment when you guess correctly --- src/components/Result/index.styled.ts | 33 +++++++++++++++++++ src/components/Result/index.tsx | 61 +++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) (limited to 'src/components/Result') diff --git a/src/components/Result/index.styled.ts b/src/components/Result/index.styled.ts index 3b2d33d..9b502f7 100644 --- a/src/components/Result/index.styled.ts +++ b/src/components/Result/index.styled.ts @@ -36,3 +36,36 @@ export const TimeToNext = styled.h4` color: var(--cl-gray-6); margin-top: 16px; `; + +export const GroupStatus = styled.div` + margin-top: 14px; + padding: 10px 12px; + border: 1px solid var(--cl-gray-4); + border-radius: 6px; + width: 100%; + max-width: 560px; +`; + +export const GroupHeading = styled.h4` + font-family: "Roboto Mono", monospace; + font-size: 0.85rem; + font-weight: 700; + color: var(--cl-white); + margin: 0 0 6px 0; +`; + +export const GroupMeta = styled.p` + font-family: "Roboto Mono", monospace; + font-size: 0.8rem; + font-weight: 400; + color: var(--cl-gray-7); + margin: 0; + + strong { + color: var(--cl-green-6); + } + + & + & { + margin-top: 6px; + } +`; diff --git a/src/components/Result/index.tsx b/src/components/Result/index.tsx index 94a59cf..3f35933 100644 --- a/src/components/Result/index.tsx +++ b/src/components/Result/index.tsx @@ -11,6 +11,11 @@ import { MiniYouTubePlayer } from "../MiniYouTubePlayer"; import * as Styled from "./index.styled"; import { theme } from "../../constants"; import GuessDistributionChart from '../Chart'; +import { + getGroupDailyStatus, + getStoredGroupMembership, + GroupDailyStatus, +} from "../../helpers/group"; interface SolutionProps { didGuess: boolean; @@ -106,6 +111,7 @@ export function Result({ onPlayAgain, }: Props) { const [timeLeftStr, setTimeLeftStr] = useState(''); + const [groupStatus, setGroupStatus] = React.useState(null); React.useEffect(() => { const updateTimeLeft = () => { @@ -133,6 +139,37 @@ export function Result({ const isUnlimited = mode === "unlimited"; const chartMode = mode === "dailyMV" ? "dailyMV" : "daily"; + React.useEffect(() => { + if (isUnlimited) { + setGroupStatus(null); + return; + } + + const membership = getStoredGroupMembership(); + if (!membership) { + setGroupStatus(null); + return; + } + + let cancelled = false; + + getGroupDailyStatus(membership.groupId, sessionDate, chartMode) + .then((status) => { + if (!cancelled) { + setGroupStatus(status); + } + }) + .catch(() => { + if (!cancelled) { + setGroupStatus(null); + } + }); + + return () => { + cancelled = true; + }; + }, [isUnlimited, sessionDate, chartMode]); + if (didGuess) { const textForTry = ["Perfect!", "Wow!", "Super!", "Congrats!", "Nice!"]; @@ -157,6 +194,18 @@ export function Result({ {!isUnlimited && } + {groupStatus && ( + + {groupStatus.groupName} + + Group streak: {groupStatus.currentStreak} + + + Finished today: {groupStatus.finishedUsers.length > 0 ? groupStatus.finishedUsers.join(", ") : "No one yet"} + + + )} + {isUnlimited && onPlayAgain ? (