f165ae52e6
continuous-integration/drone/push Build is passing
Mobile Responsiveness: - Fix headers on all Focus Tools pages (responsive text sizes, proper spacing) - Fix BodyDoublingLobby form grid (stacks on mobile) - Add shrink-0 and min-w-0 to prevent flex overflow issues AI Chat Improvements: - Add labelName parameter to createTask tool for easier label assignment - Auto-match or create labels when labelName is provided - Improve system prompt to act immediately without confirmation - Clearer instructions about using tools and handling labels - Better support for Ollama models with function calling
394 lines
21 KiB
TypeScript
394 lines
21 KiB
TypeScript
import { useTranslation } from 'react-i18next';
|
|
import { useQuery } from '@tanstack/react-query';
|
|
import { useADHDMode, ADHDSettingsPanel, EnergyCheckIn } from '@/components/adhd';
|
|
import { User, Task } from '@shared/schema';
|
|
import { Brain, Zap, Focus, Users, Battery, TrendingUp, ArrowLeft, HelpCircle, Clock, Coffee, Sparkles, Timer, Split } from 'lucide-react';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
|
import {
|
|
Accordion,
|
|
AccordionContent,
|
|
AccordionItem,
|
|
AccordionTrigger,
|
|
} from "@/components/ui/accordion";
|
|
import { useLocation } from 'wouter';
|
|
import { useState } from 'react';
|
|
|
|
export default function ADHDDashboardPage() {
|
|
const { t } = useTranslation();
|
|
const [, setLocation] = useLocation();
|
|
const { isEnabled, settings } = useADHDMode();
|
|
const [showEnergyCheckIn, setShowEnergyCheckIn] = useState(false);
|
|
|
|
const { data: user } = useQuery<User>({
|
|
queryKey: ['/api/user'],
|
|
});
|
|
|
|
const { data: tasks = [] } = useQuery<Task[]>({
|
|
queryKey: ['/api/tasks'],
|
|
});
|
|
|
|
const { data: breakStats } = useQuery({
|
|
queryKey: ['/api/user/break-stats'],
|
|
enabled: isEnabled,
|
|
});
|
|
|
|
const { data: energyHistory } = useQuery({
|
|
queryKey: ['/api/energy/history'],
|
|
enabled: isEnabled,
|
|
});
|
|
|
|
const completedToday = tasks.filter(t => {
|
|
if (t.status !== 'done' || !t.updatedAt) return false;
|
|
const today = new Date();
|
|
const updated = new Date(t.updatedAt);
|
|
return updated.toDateString() === today.toDateString();
|
|
}).length;
|
|
|
|
const quickWins = tasks.filter(t =>
|
|
t.status !== 'done' &&
|
|
t.estimatedDuration &&
|
|
t.estimatedDuration <= 15
|
|
).length;
|
|
|
|
const features = [
|
|
{
|
|
icon: Zap,
|
|
title: t('adhd.quickWins.title'),
|
|
description: t('adhd.quickWins.description'),
|
|
path: '/adhd/quick-wins',
|
|
color: 'from-yellow-400 to-orange-500',
|
|
stat: `${quickWins} ${t('adhd.dashboard.available', 'available')}`,
|
|
},
|
|
{
|
|
icon: Focus,
|
|
title: t('adhd.singleTask.title'),
|
|
description: t('adhd.singleTask.description'),
|
|
path: '/adhd/single-task',
|
|
color: 'from-blue-400 to-indigo-500',
|
|
stat: t('adhd.dashboard.focusMode', 'Focus mode'),
|
|
},
|
|
{
|
|
icon: Users,
|
|
title: t('adhd.bodyDoubling.title'),
|
|
description: t('adhd.bodyDoubling.description'),
|
|
path: '/adhd/body-doubling',
|
|
color: 'from-green-400 to-teal-500',
|
|
stat: t('adhd.dashboard.coworking', 'Co-working'),
|
|
},
|
|
];
|
|
|
|
return (
|
|
<div className="max-w-6xl mx-auto space-y-6">
|
|
<div className="flex items-center gap-3 sm:gap-4 mb-6">
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
onClick={() => setLocation('/')}
|
|
className="shrink-0"
|
|
>
|
|
<ArrowLeft className="h-5 w-5" />
|
|
</Button>
|
|
<div className="flex items-center gap-2 sm:gap-3 min-w-0">
|
|
<div className="p-2 sm:p-3 rounded-xl bg-gradient-to-br from-purple-400 to-pink-500 text-white shrink-0">
|
|
<Brain className="h-5 w-5 sm:h-6 sm:w-6" />
|
|
</div>
|
|
<div className="min-w-0">
|
|
<h1 className="text-xl sm:text-2xl font-bold truncate">{t('adhd.dashboard.title', 'ADHD Dashboard')}</h1>
|
|
<p className="text-sm sm:text-base text-muted-foreground truncate">{t('adhd.dashboard.subtitle', 'Tools designed for how your brain works')}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Stats Row */}
|
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
|
<Card>
|
|
<CardContent className="p-4">
|
|
<div className="flex items-center gap-3">
|
|
<div className="p-2 rounded-lg bg-green-100 dark:bg-green-900/30">
|
|
<TrendingUp className="h-5 w-5 text-green-600 dark:text-green-400" />
|
|
</div>
|
|
<div>
|
|
<p className="text-2xl font-bold">{completedToday}</p>
|
|
<p className="text-xs text-muted-foreground">{t('adhd.dashboard.completedToday', 'Done today')}</p>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardContent className="p-4">
|
|
<div className="flex items-center gap-3">
|
|
<div className="p-2 rounded-lg bg-blue-100 dark:bg-blue-900/30">
|
|
<Battery className="h-5 w-5 text-blue-600 dark:text-blue-400" />
|
|
</div>
|
|
<div>
|
|
<p className="text-2xl font-bold capitalize">{user?.currentEnergyLevel || '-'}</p>
|
|
<p className="text-xs text-muted-foreground">{t('adhd.dashboard.energyLevel', 'Energy')}</p>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardContent className="p-4">
|
|
<div className="flex items-center gap-3">
|
|
<div className="p-2 rounded-lg bg-yellow-100 dark:bg-yellow-900/30">
|
|
<Zap className="h-5 w-5 text-yellow-600 dark:text-yellow-400" />
|
|
</div>
|
|
<div>
|
|
<p className="text-2xl font-bold">{quickWins}</p>
|
|
<p className="text-xs text-muted-foreground">{t('adhd.dashboard.quickWins', 'Quick wins')}</p>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardContent className="p-4">
|
|
<div className="flex items-center gap-3">
|
|
<div className="p-2 rounded-lg bg-purple-100 dark:bg-purple-900/30">
|
|
<Brain className="h-5 w-5 text-purple-600 dark:text-purple-400" />
|
|
</div>
|
|
<div>
|
|
<p className="text-2xl font-bold">{user?.currentStreak || 0}</p>
|
|
<p className="text-xs text-muted-foreground">{t('adhd.dashboard.streak', 'Day streak')}</p>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
|
|
{/* Energy Check-in Button */}
|
|
{isEnabled && settings.energyCheckInsEnabled && !user?.todayEnergyCheckedIn && (
|
|
<Card className="border-2 border-dashed border-primary/50 bg-primary/5">
|
|
<CardContent className="p-4 flex items-center justify-between">
|
|
<div>
|
|
<p className="font-medium">{t('adhd.energy.checkInReminder', 'How are you feeling today?')}</p>
|
|
<p className="text-sm text-muted-foreground">{t('adhd.energy.checkInBenefit', 'Track your energy to get better task suggestions')}</p>
|
|
</div>
|
|
<Button onClick={() => setShowEnergyCheckIn(true)}>
|
|
{t('adhd.energy.checkIn', 'Check In')}
|
|
</Button>
|
|
</CardContent>
|
|
</Card>
|
|
)}
|
|
|
|
{/* Feature Cards */}
|
|
<div className="grid md:grid-cols-3 gap-4">
|
|
{features.map((feature) => (
|
|
<Card
|
|
key={feature.path}
|
|
className="cursor-pointer hover:shadow-lg transition-all hover:-translate-y-1"
|
|
onClick={() => setLocation(feature.path)}
|
|
>
|
|
<CardHeader>
|
|
<div className={`w-12 h-12 rounded-xl bg-gradient-to-br ${feature.color} flex items-center justify-center mb-2`}>
|
|
<feature.icon className="h-6 w-6 text-white" />
|
|
</div>
|
|
<CardTitle className="text-lg">{feature.title}</CardTitle>
|
|
<CardDescription>{feature.description}</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<p className="text-sm font-medium text-primary">{feature.stat}</p>
|
|
</CardContent>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
|
|
{/* Settings Panel */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>{t('adhd.settings.title', 'ADHD Settings')}</CardTitle>
|
|
<CardDescription>{t('adhd.settings.description', 'Customize your ADHD-friendly experience')}</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<ADHDSettingsPanel />
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Collapsible Help Section */}
|
|
<Card>
|
|
<Accordion type="single" collapsible className="w-full">
|
|
<AccordionItem value="help" className="border-none">
|
|
<AccordionTrigger className="px-6 py-4 hover:no-underline">
|
|
<div className="flex items-center gap-3">
|
|
<HelpCircle className="h-5 w-5 text-primary" />
|
|
<span className="font-semibold">{t('adhd.dashboard.helpTitle', 'How Focus Tools Help You')}</span>
|
|
</div>
|
|
</AccordionTrigger>
|
|
<AccordionContent className="px-6 pb-6">
|
|
<p className="text-muted-foreground mb-6">
|
|
{t('adhd.dashboard.helpIntro', 'These tools are designed around how your brain works, not against it. Each feature addresses a specific challenge and provides practical strategies to help you get things done.')}
|
|
</p>
|
|
|
|
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
|
|
{/* Quick Wins */}
|
|
<div className="p-4 rounded-lg bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800">
|
|
<div className="flex items-center gap-2 mb-2">
|
|
<Zap className="h-4 w-4 text-yellow-600 dark:text-yellow-400" />
|
|
<h4 className="font-medium">{t('adhd.dashboard.help.quickWins.title', 'Quick Wins')}</h4>
|
|
</div>
|
|
<p className="text-xs text-muted-foreground mb-2">
|
|
<strong>{t('adhd.dashboard.help.why', 'Why')}:</strong> {t('adhd.dashboard.help.quickWins.why', 'Starting tasks feels overwhelming when everything seems big.')}
|
|
</p>
|
|
<p className="text-xs text-muted-foreground mb-2">
|
|
<strong>{t('adhd.dashboard.help.how', 'How')}:</strong> {t('adhd.dashboard.help.quickWins.how', 'Shows only tasks under 15 minutes. Small wins build momentum and dopamine.')}
|
|
</p>
|
|
<p className="text-xs text-muted-foreground">
|
|
<strong>{t('adhd.dashboard.help.usage', 'Use it')}:</strong> {t('adhd.dashboard.help.quickWins.usage', 'Open Quick Wins when you feel stuck or need to build momentum.')}
|
|
</p>
|
|
</div>
|
|
|
|
{/* Single Task Focus */}
|
|
<div className="p-4 rounded-lg bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800">
|
|
<div className="flex items-center gap-2 mb-2">
|
|
<Focus className="h-4 w-4 text-blue-600 dark:text-blue-400" />
|
|
<h4 className="font-medium">{t('adhd.dashboard.help.singleTask.title', 'Single Task Focus')}</h4>
|
|
</div>
|
|
<p className="text-xs text-muted-foreground mb-2">
|
|
<strong>{t('adhd.dashboard.help.why', 'Why')}:</strong> {t('adhd.dashboard.help.singleTask.why', 'Task lists are overwhelming. Seeing everything makes it hard to start anything.')}
|
|
</p>
|
|
<p className="text-xs text-muted-foreground mb-2">
|
|
<strong>{t('adhd.dashboard.help.how', 'How')}:</strong> {t('adhd.dashboard.help.singleTask.how', 'Shows only ONE task at a time. No distractions, no choices, just focus.')}
|
|
</p>
|
|
<p className="text-xs text-muted-foreground">
|
|
<strong>{t('adhd.dashboard.help.usage', 'Use it')}:</strong> {t('adhd.dashboard.help.singleTask.usage', 'When you have many tasks and feel paralyzed by choice.')}
|
|
</p>
|
|
</div>
|
|
|
|
{/* 5-Minute Starter */}
|
|
<div className="p-4 rounded-lg bg-orange-50 dark:bg-orange-900/20 border border-orange-200 dark:border-orange-800">
|
|
<div className="flex items-center gap-2 mb-2">
|
|
<Clock className="h-4 w-4 text-orange-600 dark:text-orange-400" />
|
|
<h4 className="font-medium">{t('adhd.dashboard.help.fiveMinute.title', '5-Minute Starter')}</h4>
|
|
</div>
|
|
<p className="text-xs text-muted-foreground mb-2">
|
|
<strong>{t('adhd.dashboard.help.why', 'Why')}:</strong> {t('adhd.dashboard.help.fiveMinute.why', 'Getting started is the hardest part. Commitment feels impossible.')}
|
|
</p>
|
|
<p className="text-xs text-muted-foreground mb-2">
|
|
<strong>{t('adhd.dashboard.help.how', 'How')}:</strong> {t('adhd.dashboard.help.fiveMinute.how', 'Commit to just 5 minutes. Often, starting leads to continuing naturally.')}
|
|
</p>
|
|
<p className="text-xs text-muted-foreground">
|
|
<strong>{t('adhd.dashboard.help.usage', 'Use it')}:</strong> {t('adhd.dashboard.help.fiveMinute.usage', 'For tasks you keep avoiding. Just 5 minutes, then decide if you continue.')}
|
|
</p>
|
|
</div>
|
|
|
|
{/* Visual Timer */}
|
|
<div className="p-4 rounded-lg bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800">
|
|
<div className="flex items-center gap-2 mb-2">
|
|
<Timer className="h-4 w-4 text-red-600 dark:text-red-400" />
|
|
<h4 className="font-medium">{t('adhd.dashboard.help.visualTimer.title', 'Visual Timer')}</h4>
|
|
</div>
|
|
<p className="text-xs text-muted-foreground mb-2">
|
|
<strong>{t('adhd.dashboard.help.why', 'Why')}:</strong> {t('adhd.dashboard.help.visualTimer.why', 'Time blindness makes it hard to feel time passing.')}
|
|
</p>
|
|
<p className="text-xs text-muted-foreground mb-2">
|
|
<strong>{t('adhd.dashboard.help.how', 'How')}:</strong> {t('adhd.dashboard.help.visualTimer.how', 'A visual countdown shows time disappearing, making it tangible.')}
|
|
</p>
|
|
<p className="text-xs text-muted-foreground">
|
|
<strong>{t('adhd.dashboard.help.usage', 'Use it')}:</strong> {t('adhd.dashboard.help.visualTimer.usage', 'Set timers for work sessions. The visual helps maintain awareness.')}
|
|
</p>
|
|
</div>
|
|
|
|
{/* Break Reminders */}
|
|
<div className="p-4 rounded-lg bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800">
|
|
<div className="flex items-center gap-2 mb-2">
|
|
<Coffee className="h-4 w-4 text-green-600 dark:text-green-400" />
|
|
<h4 className="font-medium">{t('adhd.dashboard.help.breaks.title', 'Break Reminders')}</h4>
|
|
</div>
|
|
<p className="text-xs text-muted-foreground mb-2">
|
|
<strong>{t('adhd.dashboard.help.why', 'Why')}:</strong> {t('adhd.dashboard.help.breaks.why', 'Hyperfocus makes you forget basic needs like rest, food, water.')}
|
|
</p>
|
|
<p className="text-xs text-muted-foreground mb-2">
|
|
<strong>{t('adhd.dashboard.help.how', 'How')}:</strong> {t('adhd.dashboard.help.breaks.how', 'Gentle reminders interrupt hyperfocus before burnout.')}
|
|
</p>
|
|
<p className="text-xs text-muted-foreground">
|
|
<strong>{t('adhd.dashboard.help.usage', 'Use it')}:</strong> {t('adhd.dashboard.help.breaks.usage', 'Enable in settings. Take the breaks even when you feel productive.')}
|
|
</p>
|
|
</div>
|
|
|
|
{/* Energy Tracking */}
|
|
<div className="p-4 rounded-lg bg-purple-50 dark:bg-purple-900/20 border border-purple-200 dark:border-purple-800">
|
|
<div className="flex items-center gap-2 mb-2">
|
|
<Battery className="h-4 w-4 text-purple-600 dark:text-purple-400" />
|
|
<h4 className="font-medium">{t('adhd.dashboard.help.energy.title', 'Energy Tracking')}</h4>
|
|
</div>
|
|
<p className="text-xs text-muted-foreground mb-2">
|
|
<strong>{t('adhd.dashboard.help.why', 'Why')}:</strong> {t('adhd.dashboard.help.energy.why', 'Energy fluctuates unpredictably. Fighting low energy wastes time.')}
|
|
</p>
|
|
<p className="text-xs text-muted-foreground mb-2">
|
|
<strong>{t('adhd.dashboard.help.how', 'How')}:</strong> {t('adhd.dashboard.help.energy.how', 'Track your energy to match tasks to your current state.')}
|
|
</p>
|
|
<p className="text-xs text-muted-foreground">
|
|
<strong>{t('adhd.dashboard.help.usage', 'Use it')}:</strong> {t('adhd.dashboard.help.energy.usage', 'Check in daily. Do hard tasks when high, easy tasks when low.')}
|
|
</p>
|
|
</div>
|
|
|
|
{/* Body Doubling */}
|
|
<div className="p-4 rounded-lg bg-teal-50 dark:bg-teal-900/20 border border-teal-200 dark:border-teal-800">
|
|
<div className="flex items-center gap-2 mb-2">
|
|
<Users className="h-4 w-4 text-teal-600 dark:text-teal-400" />
|
|
<h4 className="font-medium">{t('adhd.dashboard.help.bodyDoubling.title', 'Body Doubling')}</h4>
|
|
</div>
|
|
<p className="text-xs text-muted-foreground mb-2">
|
|
<strong>{t('adhd.dashboard.help.why', 'Why')}:</strong> {t('adhd.dashboard.help.bodyDoubling.why', 'Working alone feels impossible. Presence of others helps focus.')}
|
|
</p>
|
|
<p className="text-xs text-muted-foreground mb-2">
|
|
<strong>{t('adhd.dashboard.help.how', 'How')}:</strong> {t('adhd.dashboard.help.bodyDoubling.how', 'Virtual co-working sessions simulate having someone nearby.')}
|
|
</p>
|
|
<p className="text-xs text-muted-foreground">
|
|
<strong>{t('adhd.dashboard.help.usage', 'Use it')}:</strong> {t('adhd.dashboard.help.bodyDoubling.usage', 'Join a session when working from home feels isolating.')}
|
|
</p>
|
|
</div>
|
|
|
|
{/* Task Breakdown */}
|
|
<div className="p-4 rounded-lg bg-indigo-50 dark:bg-indigo-900/20 border border-indigo-200 dark:border-indigo-800">
|
|
<div className="flex items-center gap-2 mb-2">
|
|
<Split className="h-4 w-4 text-indigo-600 dark:text-indigo-400" />
|
|
<h4 className="font-medium">{t('adhd.dashboard.help.taskBreakdown.title', 'AI Task Breakdown')}</h4>
|
|
</div>
|
|
<p className="text-xs text-muted-foreground mb-2">
|
|
<strong>{t('adhd.dashboard.help.why', 'Why')}:</strong> {t('adhd.dashboard.help.taskBreakdown.why', 'Big tasks feel impossible to start when you cannot see the steps.')}
|
|
</p>
|
|
<p className="text-xs text-muted-foreground mb-2">
|
|
<strong>{t('adhd.dashboard.help.how', 'How')}:</strong> {t('adhd.dashboard.help.taskBreakdown.how', 'AI breaks large tasks into small, actionable subtasks automatically.')}
|
|
</p>
|
|
<p className="text-xs text-muted-foreground">
|
|
<strong>{t('adhd.dashboard.help.usage', 'Use it')}:</strong> {t('adhd.dashboard.help.taskBreakdown.usage', 'Click breakdown on any overwhelming task to get clear next steps.')}
|
|
</p>
|
|
</div>
|
|
|
|
{/* Hyperfocus Protection */}
|
|
<div className="p-4 rounded-lg bg-pink-50 dark:bg-pink-900/20 border border-pink-200 dark:border-pink-800">
|
|
<div className="flex items-center gap-2 mb-2">
|
|
<Sparkles className="h-4 w-4 text-pink-600 dark:text-pink-400" />
|
|
<h4 className="font-medium">{t('adhd.dashboard.help.hyperfocus.title', 'Hyperfocus Protection')}</h4>
|
|
</div>
|
|
<p className="text-xs text-muted-foreground mb-2">
|
|
<strong>{t('adhd.dashboard.help.why', 'Why')}:</strong> {t('adhd.dashboard.help.hyperfocus.why', 'Hyperfocus can make you lose hours on one thing while neglecting others.')}
|
|
</p>
|
|
<p className="text-xs text-muted-foreground mb-2">
|
|
<strong>{t('adhd.dashboard.help.how', 'How')}:</strong> {t('adhd.dashboard.help.hyperfocus.how', 'Alerts when you spend too long on a single task.')}
|
|
</p>
|
|
<p className="text-xs text-muted-foreground">
|
|
<strong>{t('adhd.dashboard.help.usage', 'Use it')}:</strong> {t('adhd.dashboard.help.hyperfocus.usage', 'Enable in settings. When alerted, save your progress and decide consciously.')}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</AccordionContent>
|
|
</AccordionItem>
|
|
</Accordion>
|
|
</Card>
|
|
|
|
{/* Energy Check-in Modal */}
|
|
{showEnergyCheckIn && (
|
|
<EnergyCheckIn
|
|
onClose={() => setShowEnergyCheckIn(false)}
|
|
onSubmit={() => setShowEnergyCheckIn(false)}
|
|
/>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|