|
|
@@ -1,11 +1,11 @@
|
|
|
"use client";
|
|
|
|
|
|
import * as React from "react";
|
|
|
+import dynamic from "next/dynamic";
|
|
|
import { Calendar as CalendarIcon, X } from "lucide-react";
|
|
|
|
|
|
import { cn } from "@/lib/utils";
|
|
|
|
|
|
-import { Calendar } from "@/components/ui/calendar";
|
|
|
import { Badge } from "@/components/ui/badge";
|
|
|
import { Button } from "@/components/ui/button";
|
|
|
import { Input } from "@/components/ui/input";
|
|
|
@@ -15,9 +15,32 @@ import {
|
|
|
PopoverContent,
|
|
|
PopoverTrigger,
|
|
|
} from "@/components/ui/popover";
|
|
|
+import { Skeleton } from "@/components/ui/skeleton";
|
|
|
|
|
|
import { useSearchDateRangePicker } from "@/lib/frontend/search/useSearchDateRangePicker";
|
|
|
|
|
|
+function CalendarLoading() {
|
|
|
+ return (
|
|
|
+ <div className="space-y-3">
|
|
|
+ <div className="flex gap-4">
|
|
|
+ <Skeleton className="h-72 w-72" />
|
|
|
+ <Skeleton className="h-72 w-72" />
|
|
|
+ </div>
|
|
|
+ <p className="text-xs text-muted-foreground text-center">
|
|
|
+ Kalender lädt…
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+const Calendar = dynamic(
|
|
|
+ () => import("@/components/ui/calendar").then((m) => m.Calendar),
|
|
|
+ {
|
|
|
+ ssr: false,
|
|
|
+ loading: CalendarLoading,
|
|
|
+ },
|
|
|
+);
|
|
|
+
|
|
|
export default function SearchDateRangePicker({
|
|
|
from,
|
|
|
to,
|
|
|
@@ -44,6 +67,7 @@ export default function SearchDateRangePicker({
|
|
|
calendarSelected,
|
|
|
calendarModifiers,
|
|
|
calendarModifiersClassNames,
|
|
|
+ isRangeInvalid,
|
|
|
handlePickDay,
|
|
|
handleClearFrom,
|
|
|
handleClearTo,
|
|
|
@@ -56,6 +80,9 @@ export default function SearchDateRangePicker({
|
|
|
isSubmitting,
|
|
|
});
|
|
|
|
|
|
+ const fromInputId = React.useId();
|
|
|
+ const toInputId = React.useId();
|
|
|
+
|
|
|
const activeInputClass =
|
|
|
"border-blue-600 bg-blue-50 dark:border-blue-900 dark:bg-blue-950";
|
|
|
|
|
|
@@ -71,7 +98,7 @@ export default function SearchDateRangePicker({
|
|
|
disabled={disabled}
|
|
|
className={cn(
|
|
|
"w-[240px] justify-between font-normal",
|
|
|
- !from && !to ? "text-muted-foreground" : ""
|
|
|
+ !from && !to ? "text-muted-foreground" : "",
|
|
|
)}
|
|
|
title="Zeitraum auswählen"
|
|
|
>
|
|
|
@@ -84,9 +111,10 @@ export default function SearchDateRangePicker({
|
|
|
<div className="w-fit space-y-4 p-4">
|
|
|
<div className="grid grid-cols-2 gap-4">
|
|
|
<div className="space-y-1">
|
|
|
- <Label>Von</Label>
|
|
|
+ <Label htmlFor={fromInputId}>Von</Label>
|
|
|
<div className="relative">
|
|
|
<Input
|
|
|
+ id={fromInputId}
|
|
|
ref={fromRef}
|
|
|
readOnly
|
|
|
disabled={disabled}
|
|
|
@@ -94,7 +122,7 @@ export default function SearchDateRangePicker({
|
|
|
placeholder="TT.MM.JJJJ"
|
|
|
className={cn(
|
|
|
"pr-8",
|
|
|
- activeField === "from" ? activeInputClass : ""
|
|
|
+ activeField === "from" ? activeInputClass : "",
|
|
|
)}
|
|
|
onFocus={() => setActiveField("from")}
|
|
|
onClick={() => setActiveField("from")}
|
|
|
@@ -114,9 +142,10 @@ export default function SearchDateRangePicker({
|
|
|
</div>
|
|
|
|
|
|
<div className="space-y-1">
|
|
|
- <Label>Bis</Label>
|
|
|
+ <Label htmlFor={toInputId}>Bis</Label>
|
|
|
<div className="relative">
|
|
|
<Input
|
|
|
+ id={toInputId}
|
|
|
ref={toRef}
|
|
|
readOnly
|
|
|
disabled={disabled}
|
|
|
@@ -124,7 +153,7 @@ export default function SearchDateRangePicker({
|
|
|
placeholder="TT.MM.JJJJ"
|
|
|
className={cn(
|
|
|
"pr-8",
|
|
|
- activeField === "to" ? activeInputClass : ""
|
|
|
+ activeField === "to" ? activeInputClass : "",
|
|
|
)}
|
|
|
onFocus={() => setActiveField("to")}
|
|
|
onClick={() => setActiveField("to")}
|
|
|
@@ -157,6 +186,12 @@ export default function SearchDateRangePicker({
|
|
|
onDayClick={handlePickDay}
|
|
|
/>
|
|
|
|
|
|
+ {isRangeInvalid ? (
|
|
|
+ <p className="text-xs text-destructive text-center">
|
|
|
+ Das Startdatum darf nicht nach dem Enddatum liegen.
|
|
|
+ </p>
|
|
|
+ ) : null}
|
|
|
+
|
|
|
<div className="space-y-2">
|
|
|
<div className="text-sm text-muted-foreground">Schnellwahl</div>
|
|
|
|
|
|
@@ -211,6 +246,7 @@ export default function SearchDateRangePicker({
|
|
|
Zurücksetzen
|
|
|
</Button>
|
|
|
</div>
|
|
|
+
|
|
|
<p className="text-xs text-muted-foreground text-center">
|
|
|
Tipp: Für einen einzelnen Tag setzen Sie <b>Von</b> und <b>Bis</b>{" "}
|
|
|
auf dasselbe Datum.
|