init
This commit is contained in:
@@ -14,6 +14,8 @@ import {
|
||||
isSameMonth,
|
||||
isSameDay,
|
||||
isToday,
|
||||
isAfter,
|
||||
startOfDay,
|
||||
} from "date-fns";
|
||||
import { pl } from "date-fns/locale";
|
||||
import { Activity, ChevronLeft, ChevronRight, Dumbbell, Sparkles } from "lucide-react";
|
||||
@@ -64,9 +66,16 @@ export function DashboardAnalysisCard({ analyses, runs, workouts }: Props) {
|
||||
const [currentMonth, setCurrentMonth] = useState(() => new Date());
|
||||
const [selectedDate, setSelectedDate] = useState<Date>(() => new Date());
|
||||
|
||||
function hasAnalysis(date: Date) {
|
||||
return byDay.has(dayKey(date));
|
||||
}
|
||||
const runDays = useMemo(
|
||||
() => new Set(runs.map((r) => dayKey(new Date(r.startTime)))),
|
||||
[runs]
|
||||
);
|
||||
const workoutDays = useMemo(
|
||||
() => new Set(workouts.map((w) => dayKey(new Date(w.date)))),
|
||||
[workouts]
|
||||
);
|
||||
|
||||
const todayStart = startOfDay(new Date());
|
||||
|
||||
const monthStart = startOfMonth(currentMonth);
|
||||
const monthEnd = endOfMonth(monthStart);
|
||||
@@ -142,12 +151,17 @@ export function DashboardAnalysisCard({ analyses, runs, workouts }: Props) {
|
||||
|
||||
<div className="grid grid-cols-7 gap-1">
|
||||
{days.map((d, i) => {
|
||||
const key = dayKey(d);
|
||||
const inMonth = isSameMonth(d, monthStart);
|
||||
const has = hasAnalysis(d);
|
||||
const today = isToday(d);
|
||||
const selectable = has || today;
|
||||
const future = isAfter(startOfDay(d), todayStart);
|
||||
const selectable = !future;
|
||||
const selected = isSameDay(d, selectedDate);
|
||||
|
||||
const hasRun = runDays.has(key);
|
||||
const hasWorkout = workoutDays.has(key);
|
||||
const hasAnalysis = byDay.has(key);
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
@@ -159,21 +173,37 @@ export function DashboardAnalysisCard({ analyses, runs, workouts }: Props) {
|
||||
!inMonth && "opacity-30",
|
||||
selectable && !selected && "cursor-pointer text-fg hover:bg-accent/20",
|
||||
selected && "bg-accent font-semibold text-fg",
|
||||
!selectable && "cursor-default text-fg/40",
|
||||
!selectable && "cursor-not-allowed text-fg/30",
|
||||
today && !selected && "ring-1 ring-accent/50",
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(" ")}
|
||||
>
|
||||
{d.getDate()}
|
||||
{has && !selected && (
|
||||
<span className="absolute bottom-0.5 left-1/2 h-1 w-1 -translate-x-1/2 rounded-full bg-accent" />
|
||||
{!selected && (hasRun || hasWorkout || hasAnalysis) && (
|
||||
<span className="absolute bottom-0.5 left-1/2 flex -translate-x-1/2 gap-0.5">
|
||||
{hasRun && <span className="h-1 w-1 rounded-full bg-[#5b9bd5]" />}
|
||||
{hasWorkout && <span className="h-1 w-1 rounded-full bg-[#70ad47]" />}
|
||||
{hasAnalysis && <span className="h-1 w-1 rounded-full bg-accent" />}
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div className="mt-3 flex flex-wrap items-center gap-x-3 gap-y-1 text-[11px] text-fg/55">
|
||||
<span className="flex items-center gap-1">
|
||||
<span className="h-1.5 w-1.5 rounded-full bg-[#5b9bd5]" /> Bieg
|
||||
</span>
|
||||
<span className="flex items-center gap-1">
|
||||
<span className="h-1.5 w-1.5 rounded-full bg-[#70ad47]" /> Siłownia
|
||||
</span>
|
||||
<span className="flex items-center gap-1">
|
||||
<span className="h-1.5 w-1.5 rounded-full bg-accent" /> Analiza
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="mt-4 flex flex-col gap-1.5">
|
||||
<p className="text-xs font-medium text-fg/50">
|
||||
Treningi · {format(selectedDate, "d MMM yyyy", { locale: pl })}
|
||||
@@ -250,7 +280,7 @@ export function DashboardAnalysisCard({ analyses, runs, workouts }: Props) {
|
||||
</p>
|
||||
) : (
|
||||
<p className="text-sm text-fg/60">
|
||||
Wybierz dzień oznaczony kropką, aby zobaczyć analizę z tego dnia.
|
||||
Brak analizy AI dla {format(selectedDate, "d MMMM yyyy", { locale: pl })}.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user