Files
proof-of-work/workout-planner/app/main/workouts/page.tsx
T
2026-02-28 09:27:26 -06:00

173 lines
5.9 KiB
TypeScript

import { redirect } from "next/navigation";
import Link from "next/link";
import { Plus, Activity, Upload } from "lucide-react";
import { getCurrentUser } from "@/lib/auth";
import { getWorkouts } from "@/lib/db/workouts";
import WorkoutCard from "@/components/workouts/WorkoutCard";
interface PageProps {
searchParams: { q?: string; dateFrom?: string; dateTo?: string };
}
export const metadata = {
title: "Workout History",
description: "View your workout history",
};
export default async function WorkoutsPage({ searchParams }: PageProps) {
const user = await getCurrentUser();
if (!user) {
redirect("/auth/login");
}
// Parse search params
const query = searchParams.q || "";
const dateFrom = searchParams.dateFrom
? new Date(searchParams.dateFrom)
: undefined;
const dateTo = searchParams.dateTo
? new Date(searchParams.dateTo)
: undefined;
// Fetch workouts
const workouts = await getWorkouts(user.id, {
query,
dateFrom,
dateTo,
limit: 50,
});
return (
<div className="min-h-screen bg-[#0A0A0A]">
{/* Header */}
<div className="border-b border-zinc-800 sticky top-0 z-40">
<div className="max-w-2xl mx-auto px-4 py-4 sm:py-6">
<div className="flex items-center justify-between">
<h1 className="text-2xl sm:text-3xl font-bold text-white">
Workout History
</h1>
<Link
href="/main/import"
className="p-2 hover:bg-zinc-900 rounded-lg text-zinc-400 hover:text-white transition"
title="Import workouts from CSV"
>
<Upload className="w-5 h-5" />
</Link>
</div>
</div>
</div>
<div className="max-w-2xl mx-auto px-4 py-6">
{/* Search and filters */}
<form className="mb-6 space-y-4">
{/* Search bar */}
<div>
<input
type="text"
name="q"
placeholder="Search workouts..."
defaultValue={query}
className="w-full px-4 py-3 border border-zinc-700 bg-zinc-800 rounded-lg focus:outline-none focus:ring-2 focus:ring-white text-white placeholder-zinc-500 text-base"
/>
</div>
{/* Date range */}
<div className="grid grid-cols-2 gap-3 sm:gap-4">
<div>
<label className="block text-sm text-zinc-400 mb-1">From</label>
<input
type="date"
name="dateFrom"
defaultValue={searchParams.dateFrom || ""}
className="w-full px-4 py-2 border border-zinc-700 bg-zinc-800 rounded-lg focus:outline-none focus:ring-2 focus:ring-white text-white text-base"
/>
</div>
<div>
<label className="block text-sm text-zinc-400 mb-1">To</label>
<input
type="date"
name="dateTo"
defaultValue={searchParams.dateTo || ""}
className="w-full px-4 py-2 border border-zinc-700 bg-zinc-800 rounded-lg focus:outline-none focus:ring-2 focus:ring-white text-white text-base"
/>
</div>
</div>
{/* Submit buttons */}
<div className="flex gap-2">
<button
type="submit"
className="flex-1 px-4 py-2 bg-white text-black rounded-lg font-medium hover:bg-gray-100 touch-target"
>
Filter
</button>
<Link
href="/main/workouts"
className="flex-1 px-4 py-2 bg-zinc-800 text-white rounded-lg font-medium hover:bg-zinc-700 text-center touch-target"
>
Clear
</Link>
</div>
</form>
{/* Workout list */}
{workouts.length === 0 ? (
<div className="text-center py-12">
<div className="flex justify-center mb-4">
<Activity className="w-12 h-12 text-zinc-600" />
</div>
<h2 className="text-lg font-semibold text-white mb-2">
No workouts yet
</h2>
<p className="text-zinc-400 mb-6">
{query || dateFrom || dateTo
? "No workouts match your filters. Try adjusting your search."
: "Start tracking your fitness journey by logging your first workout."}
</p>
<Link
href="/main/workouts/new"
className="inline-flex items-center gap-2 px-6 py-3 bg-white text-black rounded-lg font-semibold hover:bg-gray-100 touch-target"
>
<Plus className="w-5 h-5" />
Log Your First Workout
</Link>
</div>
) : (
<div className="space-y-3 pb-20 sm:pb-6">
{workouts.map((workout) => (
<WorkoutCard key={workout.id} workout={workout} />
))}
</div>
)}
</div>
{/* Floating action button for mobile, regular button for desktop */}
{workouts.length > 0 && (
<>
{/* Mobile FAB */}
<div className="fixed bottom-6 right-6 sm:hidden">
<Link
href="/main/workouts/new"
className="flex items-center justify-center w-14 h-14 bg-white text-black rounded-full shadow-lg hover:bg-gray-100 active:bg-gray-200 touch-target"
aria-label="Log new workout"
>
<Plus className="w-6 h-6" />
</Link>
</div>
{/* Desktop button */}
<div className="hidden sm:block fixed bottom-6 right-6">
<Link
href="/main/workouts/new"
className="flex items-center gap-2 px-6 py-3 bg-white text-black rounded-lg font-semibold hover:bg-gray-100 shadow-lg"
>
<Plus className="w-5 h-5" />
Log Workout
</Link>
</div>
</>
)}
</div>
);
}