Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
c75ea75
feat: enhance homepage with open source section and versioning
Bana0615 Jan 16, 2026
3949ce2
feat: implement multi-tiered challenge system on homepage
Bana0615 Jan 16, 2026
c35b048
fix(lint): resolve TypeScript ESLint issues
Bana0615 Jan 16, 2026
6186c3f
feat: add 'How It Works' section to homepage
Bana0615 Jan 16, 2026
9537e87
feat: add methodology and persona guide to homepage
Bana0615 Jan 16, 2026
7726167
refactor: update OpenSource section to focus on community and contrib…
Bana0615 Jan 16, 2026
7cc810d
feat: implement Product Timeline (Changelog) page
Bana0615 Jan 22, 2026
1edde64
chore: update SEO metadata and brand positioning
Bana0615 Jan 22, 2026
69e552d
feat: add home navigation and update app button logic in Header
Bana0615 Jan 22, 2026
608ee85
feat: implement privacy policy and global footer legal section
Bana0615 Jan 22, 2026
51836ae
docs: implement Terms of Service with medical and trademark disclaimers
Bana0615 Jan 22, 2026
41e0e09
feat: implement dynamic challenge selection and multi-tier tracking l…
Bana0615 Jan 22, 2026
1280f3e
feat: integrate custom challenge tier and theme system into home page
Bana0615 Jan 22, 2026
ab17680
feat: add Bluesky and Facebook links to footer
Bana0615 Jan 23, 2026
c0a28b9
feat: redesign dashboard cards and implement global data reset
Bana0615 Jan 23, 2026
6147780
fix: refine challenge detail layout and error handling
Bana0615 Jan 23, 2026
33af204
fix: wrap Header settings in Suspense to resolve build error
Bana0615 Jan 23, 2026
504bee5
feat: refactor challenge setup into modular components and enhance ru…
Bana0615 Jan 23, 2026
2b35777
chore: Updated calculations and changelog
Bana0615 Jan 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
{
"name": "grit",
"version": "1.0.0",
"version": "1.5.0",
"private": true,
"scripts": {
"dev": "next dev --turbopack",
"dev": "next dev",
"dev:turbo": "next dev --turbopack",
"build": "next build && npm run sitemap",
"start": "next start",
"lint": "next lint",
Expand Down
74 changes: 41 additions & 33 deletions src/app/app/challenge/page.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,25 @@
'use client';

import React, { useEffect, useState, Suspense } from 'react';
import { useSearchParams } from 'next/navigation';
import {
ChallengeProvider,
useChallengeState,
useChallengeDispatch,
} from '@/context/ChallengeContext';
import { useSearchParams, useRouter } from 'next/navigation';
import { useChallengeState, useChallengeDispatch } from '@/context/ChallengeContext';
import { getChallengeById } from '@/lib/db';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faHome, faExclamationCircle } from '@fortawesome/free-solid-svg-icons';
import DailyDashboard from '@/components/features/dashboard/DailyDashboard';
import Header from '@/components/layout/Header';
import Footer from '@/components/layout/Footer';
import SettingsModal from '@/components/ui/SettingsModal';
import Notification from '@/components/ui/Notification';
import type { NotificationProps } from '@/components/ui/Notification';
import CompletionModal from '@/components/ui/CompletionModal';
import ChallengeStatusBanner from '@/components/ui/ChallengeStatusBanner';

const ChallengeDetailContent = () => {
const searchParams = useSearchParams();
const router = useRouter();
const id = searchParams.get('id');

const { challenge, isLoading } = useChallengeState();
const dispatch = useChallengeDispatch();
const [isSettingsOpen, setIsSettingsOpen] = useState(false);
const [isCompletionModalOpen, setIsCompletionModalOpen] = useState(false);
const [notification, setNotification] = useState<Omit<NotificationProps, 'onClose'> | null>(null);

useEffect(() => {
const fetchChallenge = async () => {
Expand All @@ -48,31 +42,49 @@ const ChallengeDetailContent = () => {

if (isLoading) {
return (
<div className="flex items-center justify-center min-h-screen">
<p className="text-2xl font-orbitron">Loading Challenge...</p>
<div className="flex flex-col min-h-screen bg-[var(--color-background)]">
<Header />
<main className="flex-grow flex items-center justify-center">
<p className="text-2xl font-orbitron animate-pulse">Loading Challenge...</p>
</main>
<Footer />
</div>
);
}

if (!challenge) {
return (
<div className="flex items-center justify-center min-h-screen">
<p className="text-2xl font-orbitron">Challenge not found or ID is missing.</p>
<div className="flex flex-col min-h-screen bg-[var(--color-background)]">
<Header />
<main className="flex-grow flex flex-col items-center justify-center p-6 text-center">
<div className="bg-[var(--color-surface)] p-8 rounded-2xl shadow-xl max-w-md w-full border border-[var(--color-background)]">
<FontAwesomeIcon
icon={faExclamationCircle}
className="text-4xl text-[var(--color-text-muted)] mb-4"
/>
<h2 className="text-2xl font-bold font-orbitron mb-2">Challenge Not Found</h2>
<p className="text-[var(--color-text-muted)] mb-6">
We couldn&apos;t locate the challenge you are looking for. It may have been deleted or
the ID is incorrect.
</p>
<button
onClick={() => router.push('/app/')}
className="bg-[var(--color-primary)] hover:bg-[var(--color-primary-hover)] text-white font-bold py-3 px-6 cursor-pointer rounded-lg transition-colors w-full flex items-center justify-center gap-2">
<FontAwesomeIcon icon={faHome} />
Return to Dashboard
</button>
</div>
</main>
<Footer />
</div>
);
}

return (
<div className="flex flex-col min-h-screen">
{notification && (
<Notification
type={notification.type}
title={notification.title}
message={notification.message}
onClose={() => setNotification(null)}
/>
)}
<Header onSettingsClick={() => setIsSettingsOpen(true)} />
<div className="flex flex-col min-h-screen bg-[var(--color-background)]">
{/* Header now manages Settings internally */}
<Header />

<main className="flex-grow">
{challenge.status === 'completed' && (
<div className="container mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 mt-8">
Expand All @@ -84,14 +96,12 @@ const ChallengeDetailContent = () => {
</button>
</div>
)}

<DailyDashboard onFinishChallenge={() => setIsCompletionModalOpen(true)} />
</main>

<Footer />
<SettingsModal
isOpen={isSettingsOpen}
onClose={() => setIsSettingsOpen(false)}
showNotification={setNotification}
/>

<CompletionModal
isOpen={isCompletionModalOpen}
onClose={() => setIsCompletionModalOpen(false)}
Expand All @@ -105,9 +115,7 @@ const ChallengeDetailContent = () => {
export default function ChallengeDetailPage() {
return (
<Suspense fallback={<div>Loading...</div>}>
<ChallengeProvider>
<ChallengeDetailContent />
</ChallengeProvider>
<ChallengeDetailContent />
</Suspense>
);
}
Loading