feat: Show elapsed toggle in Favorites

This commit is contained in:
Matej Stieranka 2025-06-28 21:29:56 +02:00
parent e41c2b9fc2
commit 5510bdee5e
5 changed files with 126 additions and 8 deletions

View file

@ -19,6 +19,7 @@
"@radix-ui/react-select": "^2.2.5",
"@radix-ui/react-separator": "^1.1.7",
"@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-switch": "^1.2.5",
"@radix-ui/react-tooltip": "^1.2.7",
"cheerio": "^1.1.0",
"class-variance-authority": "^0.7.1",

31
pnpm-lock.yaml generated
View file

@ -29,6 +29,9 @@ dependencies:
'@radix-ui/react-slot':
specifier: ^1.2.3
version: 1.2.3(@types/react@19.1.8)(react@19.1.0)
'@radix-ui/react-switch':
specifier: ^1.2.5
version: 1.2.5(@types/react-dom@19.1.6)(@types/react@19.1.8)(react-dom@19.1.0)(react@19.1.0)
'@radix-ui/react-tooltip':
specifier: ^1.2.7
version: 1.2.7(@types/react-dom@19.1.6)(@types/react@19.1.8)(react-dom@19.1.0)(react@19.1.0)
@ -1532,6 +1535,32 @@ packages:
react: 19.1.0
dev: false
/@radix-ui/react-switch@1.2.5(@types/react-dom@19.1.6)(@types/react@19.1.8)(react-dom@19.1.0)(react@19.1.0):
resolution: {integrity: sha512-5ijLkak6ZMylXsaImpZ8u4Rlf5grRmoc0p0QeX9VJtlrM4f5m3nCTX8tWga/zOA8PZYIR/t0p2Mnvd7InrJ6yQ==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
dependencies:
'@radix-ui/primitive': 1.1.2
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@19.1.0)
'@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@19.1.0)
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6)(@types/react@19.1.8)(react-dom@19.1.0)(react@19.1.0)
'@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.8)(react@19.1.0)
'@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.8)(react@19.1.0)
'@radix-ui/react-use-size': 1.1.1(@types/react@19.1.8)(react@19.1.0)
'@types/react': 19.1.8
'@types/react-dom': 19.1.6(@types/react@19.1.8)
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
dev: false
/@radix-ui/react-tooltip@1.2.7(@types/react-dom@19.1.6)(@types/react@19.1.8)(react-dom@19.1.0)(react@19.1.0):
resolution: {integrity: sha512-Ap+fNYwKTYJ9pzqW+Xe2HtMRbQ/EeWkj2qykZ6SuEV4iS/o1bZI5ssJbk4D2r8XuDuOBVz/tIx2JObtuqU+5Zw==}
peerDependencies:
@ -1635,7 +1664,7 @@ packages:
/@radix-ui/react-use-previous@1.1.1(@types/react@19.1.8)(react@19.1.0):
resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==}
peerDependencies:
'@types/react': '*'
'@types/react': 19.1.2
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':

View file

@ -1,18 +1,38 @@
import { EventList } from "@/components/EventList";
import { ShowElapsedSwitch } from "@/components/ShowElapsedSwitch";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
import { getEventsByIds } from "@/db";
import { cookies } from "next/headers";
export default async function FavoritesPage() {
interface FavoritesPageProps {
searchParams: Promise<{ showElapsed?: string }>;
}
export default async function FavoritesPage({
searchParams,
}: FavoritesPageProps) {
const showElapsed = (await searchParams).showElapsed === "true";
const cookieStore = await cookies();
const favoritesCookie = cookieStore.get("favorites")?.value || "[]";
const favoritesArray: number[] = JSON.parse(favoritesCookie);
const favorites = await getEventsByIds(favoritesArray);
const filteredFavorites = favorites.filter((event) => {
if (showElapsed) return true;
const now = new Date();
return event.startTime > now || event.endTime > now;
});
return (
<div className="flex flex-col items-center justify-items-center p-8 pb-20 gap-4 sm:p-20 w-full">
<h1 className="text-3xl font-bold mb-4 w-full">Oblíbené</h1>
<div className="flex flex-col sm:flex-row justify-between items-center w-full gap-2 mb-4">
<h1 className="text-3xl font-bold">Oblíbené</h1>
<ShowElapsedSwitch defaultValue={false} />
</div>
<main className="flex flex-col gap-8 w-full">
<EventList events={favorites} showDate showLine />
<EventList events={filteredFavorites} showDate showLine />
</main>
</div>
);

View file

@ -0,0 +1,37 @@
"use client";
import { useRouter, useSearchParams } from "next/navigation";
import { Label } from "./ui/label";
import { Switch } from "./ui/switch";
import { useMemo } from "react";
export const ShowElapsedSwitch = ({
defaultValue = false,
}: {
defaultValue?: boolean;
}) => {
const searchParams = useSearchParams();
const router = useRouter();
const showElapsed = useMemo(() => {
if (searchParams.get("showElapsed") === "true") {
return true;
}
if (searchParams.get("showElapsed") === "false") {
return false;
}
return defaultValue;
}, [searchParams, defaultValue]);
function setShowElapsed(showElapsed: boolean) {
const params = new URLSearchParams(searchParams.toString());
params.set("showElapsed", showElapsed ? "true" : "false");
router.push(`?${params.toString()}`);
}
return (
<div className='flex items-center gap-2'>
<Switch name="showElapsed" onClick={() => setShowElapsed(!showElapsed)} />
<Label htmlFor="airplane-mode">Zobrazit proběhlé události</Label>
</div>
);
};

View file

@ -0,0 +1,31 @@
"use client"
import * as React from "react"
import * as SwitchPrimitive from "@radix-ui/react-switch"
import { cn } from "@/lib/utils"
function Switch({
className,
...props
}: React.ComponentProps<typeof SwitchPrimitive.Root>) {
return (
<SwitchPrimitive.Root
data-slot="switch"
className={cn(
"peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
className
)}
{...props}
>
<SwitchPrimitive.Thumb
data-slot="switch-thumb"
className={cn(
"bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-4 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0"
)}
/>
</SwitchPrimitive.Root>
)
}
export { Switch }