Refactor date input components across forms to use DateInput instead of Popover with Calendar for improved usability and consistency
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
parent
76718d5647
commit
20e50d5c6d
16 changed files with 124 additions and 1085 deletions
|
|
@ -39,7 +39,8 @@
|
|||
"@radix-ui/react-tooltip",
|
||||
"@radix-ui/react-popover",
|
||||
"@radix-ui/react-toggle-group",
|
||||
"tailwindcss"
|
||||
"tailwindcss",
|
||||
"@hookform/devtools"
|
||||
],
|
||||
"project": [
|
||||
"src/**",
|
||||
|
|
|
|||
40
apps/infoalloggi/package-lock.json
generated
40
apps/infoalloggi/package-lock.json
generated
|
|
@ -69,7 +69,6 @@
|
|||
"radix-ui": "^1.4.3",
|
||||
"react": "^19.2.3",
|
||||
"react-colorful": "^5.6.1",
|
||||
"react-day-picker": "^9.14.0",
|
||||
"react-dom": "^19.2.3",
|
||||
"react-hook-form": "^7.72.1",
|
||||
"react-hot-toast": "^2.5.2",
|
||||
|
|
@ -594,10 +593,6 @@
|
|||
"node": ">=20.19.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@date-fns/tz": {
|
||||
"version": "1.4.1",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@discoveryjs/json-ext": {
|
||||
"version": "0.5.7",
|
||||
"license": "MIT",
|
||||
|
|
@ -5867,15 +5862,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@tabby_ai/hijri-converter": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@tabby_ai/hijri-converter/-/hijri-converter-1.0.5.tgz",
|
||||
"integrity": "sha512-r5bClKrcIusDoo049dSL8CawnHR6mRdDwhlQuIgZRNty68q0x8k3Lf1BtPAMxRf/GgnHBnIO4ujd3+GQdLWzxQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/forms": {
|
||||
"version": "0.5.11",
|
||||
"license": "MIT",
|
||||
|
|
@ -7701,10 +7687,6 @@
|
|||
"url": "https://github.com/sponsors/kossnocorp"
|
||||
}
|
||||
},
|
||||
"node_modules/date-fns-jalali": {
|
||||
"version": "4.1.0-0",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/debounce": {
|
||||
"version": "2.2.0",
|
||||
"dev": true,
|
||||
|
|
@ -11709,28 +11691,6 @@
|
|||
"react-dom": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-day-picker": {
|
||||
"version": "9.14.0",
|
||||
"resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-9.14.0.tgz",
|
||||
"integrity": "sha512-tBaoDWjPwe0M5pGrum4H0SR6Lyk+BO9oHnp9JbKpGKW2mlraNPgP9BMfsg5pWpwrssARmeqk7YBl2oXutZTaHA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@date-fns/tz": "^1.4.1",
|
||||
"@tabby_ai/hijri-converter": "1.0.5",
|
||||
"date-fns": "^4.1.0",
|
||||
"date-fns-jalali": "4.1.0-0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/gpbl"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dom": {
|
||||
"version": "19.2.3",
|
||||
"license": "MIT",
|
||||
|
|
|
|||
|
|
@ -84,7 +84,6 @@
|
|||
"radix-ui": "^1.4.3",
|
||||
"react": "^19.2.3",
|
||||
"react-colorful": "^5.6.1",
|
||||
"react-day-picker": "^9.14.0",
|
||||
"react-dom": "^19.2.3",
|
||||
"react-hook-form": "^7.72.1",
|
||||
"react-hot-toast": "^2.5.2",
|
||||
|
|
@ -160,4 +159,4 @@
|
|||
"axios": "^1.16.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
27
apps/infoalloggi/src/components/custom_ui/inputDate.tsx
Normal file
27
apps/infoalloggi/src/components/custom_ui/inputDate.tsx
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import type React from "react";
|
||||
import Input from "~/components/ui/input";
|
||||
|
||||
interface DateInputProps
|
||||
extends Omit<
|
||||
React.InputHTMLAttributes<HTMLInputElement>,
|
||||
"type" | "value" | "onChange"
|
||||
> {
|
||||
value: Date | null;
|
||||
onChange: (date: Date | null) => void;
|
||||
}
|
||||
|
||||
export const DateInput = ({ value, onChange, ...rest }: DateInputProps) => {
|
||||
return (
|
||||
<Input
|
||||
{...rest}
|
||||
onChange={(e) => {
|
||||
const date = new Date(e.currentTarget.value);
|
||||
if (!Number.isNaN(date.getTime())) {
|
||||
onChange(date);
|
||||
}
|
||||
}}
|
||||
type="date"
|
||||
value={value?.toISOString().split("T")[0] || ""}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
import { format } from "date-fns";
|
||||
import { it } from "date-fns/locale";
|
||||
import { CalendarIcon, Check, SlidersHorizontal } from "lucide-react";
|
||||
import { Check, SlidersHorizontal } from "lucide-react"
|
||||
import { useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import { z } from "zod/v4";
|
||||
|
|
@ -23,10 +22,10 @@ import {
|
|||
FormLabel,
|
||||
FormMessage,
|
||||
} from "~/components/custom_ui/form";
|
||||
import { DateInput } from "~/components/custom_ui/inputDate";
|
||||
import { MultiSelect, UnpackOptions } from "~/components/custom_ui/multiselect";
|
||||
import { Badge } from "~/components/ui/badge";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { Calendar } from "~/components/ui/calendar";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
|
|
@ -36,11 +35,6 @@ import {
|
|||
DialogTrigger,
|
||||
} from "~/components/ui/dialog";
|
||||
import { Label } from "~/components/ui/label";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "~/components/ui/popover";
|
||||
import { Slider } from "~/components/ui/slider";
|
||||
import { Switch } from "~/components/ui/switch";
|
||||
import { FieldResetButton } from "~/forms/comps";
|
||||
|
|
@ -526,42 +520,12 @@ const FormServizio = ({
|
|||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<FormControl>
|
||||
<Button
|
||||
className={cn(
|
||||
"h-10 w-full bg-card pl-3 text-left font-medium",
|
||||
!field.value && "text-muted-foreground",
|
||||
"rounded-lg border border-neutral-300 shadow-xs outline-hidden file:border-0 file:bg-transparent file:font-medium file:text-sm disabled:cursor-not-allowed disabled:opacity-50 dark:focus:border-transparent",
|
||||
)}
|
||||
id="scadenza_motivazione_transitoria"
|
||||
variant={"outline"}
|
||||
>
|
||||
{field.value ? (
|
||||
format(field.value, "PPP", {
|
||||
locale: it,
|
||||
})
|
||||
) : (
|
||||
<span>{t.anagrafica.scegli_data}</span>
|
||||
)}
|
||||
<CalendarIcon className="ml-auto size-4 opacity-50" />
|
||||
</Button>
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent align="end" className="w-auto p-0">
|
||||
<Calendar
|
||||
autoFocus
|
||||
captionLayout="dropdown"
|
||||
defaultMonth={field.value || new Date()}
|
||||
endMonth={new Date(2050, 12)}
|
||||
locale={it}
|
||||
mode="single"
|
||||
onSelect={field.onChange}
|
||||
selected={field.value || undefined}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<DateInput
|
||||
id="scadenza_motivazione_transitoria"
|
||||
onChange={field.onChange}
|
||||
placeholder={t.anagrafica.scegli_data}
|
||||
value={field.value || new Date()}
|
||||
/>
|
||||
)}
|
||||
<FormDescription>
|
||||
es. scadenza contratto di lavoro, fine corso di studi, ecc.
|
||||
|
|
|
|||
|
|
@ -1,532 +0,0 @@
|
|||
"use client";
|
||||
|
||||
import { differenceInCalendarDays } from "date-fns";
|
||||
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||
import {
|
||||
type Dispatch,
|
||||
type HTMLAttributes,
|
||||
type ReactNode,
|
||||
type SetStateAction,
|
||||
type TableHTMLAttributes,
|
||||
useCallback,
|
||||
useMemo,
|
||||
useState,
|
||||
} from "react";
|
||||
import {
|
||||
DayPicker,
|
||||
type DayPickerProps,
|
||||
labelNext,
|
||||
labelPrevious,
|
||||
useDayPicker,
|
||||
} from "react-day-picker";
|
||||
import { Button, buttonVariants } from "~/components/ui/button";
|
||||
import { cn } from "~/lib/utils";
|
||||
|
||||
type CalendarProps = DayPickerProps & {
|
||||
/**
|
||||
* In the year view, the number of years to display at once.
|
||||
* @default 12
|
||||
*/
|
||||
yearRange?: number;
|
||||
|
||||
/**
|
||||
* Wether to show the year switcher in the caption.
|
||||
* @default true
|
||||
*/
|
||||
showYearSwitcher?: boolean;
|
||||
|
||||
monthsClassName?: string;
|
||||
monthCaptionClassName?: string;
|
||||
weekdaysClassName?: string;
|
||||
weekdayClassName?: string;
|
||||
monthClassName?: string;
|
||||
captionClassName?: string;
|
||||
captionLabelClassName?: string;
|
||||
buttonNextClassName?: string;
|
||||
buttonPreviousClassName?: string;
|
||||
navClassName?: string;
|
||||
monthGridClassName?: string;
|
||||
weekClassName?: string;
|
||||
dayClassName?: string;
|
||||
dayButtonClassName?: string;
|
||||
rangeStartClassName?: string;
|
||||
rangeEndClassName?: string;
|
||||
selectedClassName?: string;
|
||||
todayClassName?: string;
|
||||
outsideClassName?: string;
|
||||
disabledClassName?: string;
|
||||
rangeMiddleClassName?: string;
|
||||
hiddenClassName?: string;
|
||||
};
|
||||
|
||||
type NavView = "days" | "years";
|
||||
|
||||
/**
|
||||
* A custom calendar component built on top of react-day-picker.
|
||||
* @param props The props for the calendar.
|
||||
* @default yearRange 12
|
||||
* @returns
|
||||
*/
|
||||
function Calendar({
|
||||
className,
|
||||
showOutsideDays = true,
|
||||
showYearSwitcher = true,
|
||||
yearRange = 12,
|
||||
numberOfMonths,
|
||||
...props
|
||||
}: CalendarProps) {
|
||||
const [navView, setNavView] = useState<NavView>("days");
|
||||
const [displayYears, setDisplayYears] = useState<{
|
||||
from: number;
|
||||
to: number;
|
||||
}>(
|
||||
useMemo(() => {
|
||||
const currentYear = new Date().getFullYear();
|
||||
return {
|
||||
from: currentYear - Math.floor(yearRange / 2 - 1),
|
||||
to: currentYear + Math.ceil(yearRange / 2),
|
||||
};
|
||||
}, [yearRange]),
|
||||
);
|
||||
|
||||
const { onPrevClick, startMonth, endMonth } = props;
|
||||
|
||||
const columnsDisplayed = navView === "years" ? 1 : numberOfMonths;
|
||||
|
||||
const _monthsClassName = cn("relative flex", props.monthsClassName);
|
||||
const _monthCaptionClassName = cn(
|
||||
"relative mx-10 flex h-7 items-center justify-center",
|
||||
props.monthCaptionClassName,
|
||||
);
|
||||
const _weekdaysClassName = cn("flex flex-row", props.weekdaysClassName);
|
||||
const _weekdayClassName = cn(
|
||||
"w-8 text-sm font-normal text-muted-foreground",
|
||||
props.weekdayClassName,
|
||||
);
|
||||
const _monthClassName = cn("w-full", props.monthClassName);
|
||||
const _captionClassName = cn(
|
||||
"relative flex items-center justify-center pt-1",
|
||||
props.captionClassName,
|
||||
);
|
||||
const _captionLabelClassName = cn(
|
||||
"truncate text-sm font-medium",
|
||||
props.captionLabelClassName,
|
||||
props.captionLayout === "dropdown" &&
|
||||
"flex items-center text-sm font-medium border border-neutral-200 rounded-md px-2 py-1",
|
||||
);
|
||||
const buttonNavClassName = buttonVariants({
|
||||
className:
|
||||
"absolute size-7 bg-transparent p-0 opacity-50 hover:opacity-100",
|
||||
variant: "outline",
|
||||
});
|
||||
const _buttonNextClassName = cn(
|
||||
buttonNavClassName,
|
||||
"right-0",
|
||||
props.buttonNextClassName,
|
||||
);
|
||||
const _buttonPreviousClassName = cn(
|
||||
buttonNavClassName,
|
||||
"left-0",
|
||||
props.buttonPreviousClassName,
|
||||
);
|
||||
const _navClassName = cn("flex items-start", props.navClassName);
|
||||
const _monthGridClassName = cn("mx-auto mt-4", props.monthGridClassName);
|
||||
const _weekClassName = cn("mt-2 flex w-max items-start", props.weekClassName);
|
||||
const _dayClassName = cn(
|
||||
"flex size-8 flex-1 items-center justify-center p-0 text-sm",
|
||||
props.dayClassName,
|
||||
);
|
||||
const _dayButtonClassName = cn(
|
||||
buttonVariants({ variant: "ghost" }),
|
||||
"size-8 rounded-md p-0 font-normal transition-none aria-selected:opacity-100",
|
||||
props.dayButtonClassName,
|
||||
);
|
||||
const buttonRangeClassName =
|
||||
"bg-accent [&>button]:bg-primary [&>button]:text-primary-foreground [&>button]:hover:bg-primary [&>button]:hover:text-primary-foreground";
|
||||
const _rangeStartClassName = cn(
|
||||
buttonRangeClassName,
|
||||
"rounded-s-md",
|
||||
props.rangeStartClassName,
|
||||
);
|
||||
const _rangeEndClassName = cn(
|
||||
buttonRangeClassName,
|
||||
"rounded-e-md",
|
||||
props.rangeEndClassName,
|
||||
);
|
||||
const _rangeMiddleClassName = cn(
|
||||
"bg-accent !text-foreground [&>button]:bg-transparent [&>button]:!text-foreground [&>button]:hover:bg-transparent [&>button]:hover:!text-foreground",
|
||||
props.rangeMiddleClassName,
|
||||
);
|
||||
const _selectedClassName = cn(
|
||||
"[&>button]:bg-primary [&>button]:text-primary-foreground [&>button]:hover:bg-primary [&>button]:hover:text-primary-foreground",
|
||||
props.selectedClassName,
|
||||
);
|
||||
const _todayClassName = cn(
|
||||
"[&>button]:bg-accent [&>button]:text-accent-foreground",
|
||||
props.todayClassName,
|
||||
);
|
||||
const _outsideClassName = cn(
|
||||
"text-muted-foreground opacity-50 aria-selected:bg-accent/50 aria-selected:text-muted-foreground aria-selected:opacity-30",
|
||||
props.outsideClassName,
|
||||
);
|
||||
const _disabledClassName = cn(
|
||||
"text-muted-foreground opacity-50",
|
||||
props.disabledClassName,
|
||||
);
|
||||
const _hiddenClassName = cn("invisible flex-1", props.hiddenClassName);
|
||||
|
||||
const _dropdownOverrideClassName = cn("rounded-md p-2 shadow-xs bg-card");
|
||||
|
||||
return (
|
||||
<DayPicker
|
||||
className={cn("p-3", className)}
|
||||
classNames={{
|
||||
button_next: _buttonNextClassName,
|
||||
button_previous: _buttonPreviousClassName,
|
||||
caption: _captionClassName,
|
||||
caption_label: _captionLabelClassName,
|
||||
day: _dayClassName,
|
||||
day_button: _dayButtonClassName,
|
||||
disabled: _disabledClassName,
|
||||
hidden: _hiddenClassName,
|
||||
month: _monthClassName,
|
||||
month_caption: _monthCaptionClassName,
|
||||
month_grid: _monthGridClassName,
|
||||
months: _monthsClassName,
|
||||
months_dropdown: _dropdownOverrideClassName,
|
||||
nav: _navClassName,
|
||||
outside: _outsideClassName,
|
||||
range_end: _rangeEndClassName,
|
||||
range_middle: _rangeMiddleClassName,
|
||||
range_start: _rangeStartClassName,
|
||||
selected: _selectedClassName,
|
||||
today: _todayClassName,
|
||||
week: _weekClassName,
|
||||
weekday: _weekdayClassName,
|
||||
weekdays: _weekdaysClassName,
|
||||
years_dropdown: _dropdownOverrideClassName,
|
||||
}}
|
||||
components={{
|
||||
// Dropdown: (props) => (
|
||||
// <Dropdown className={_dropdownOverrideClassName} {...props} />
|
||||
// ),
|
||||
|
||||
CaptionLabel: (props) => (
|
||||
<CaptionLabel
|
||||
displayYears={displayYears}
|
||||
navView={navView}
|
||||
setNavView={setNavView}
|
||||
showYearSwitcher={showYearSwitcher}
|
||||
{...props}
|
||||
/>
|
||||
),
|
||||
Chevron: ({ orientation }) => {
|
||||
const Icon = orientation === "left" ? ChevronLeft : ChevronRight;
|
||||
return <Icon className="size-4" />;
|
||||
},
|
||||
MonthGrid: ({ className, children, ...props }) => (
|
||||
<MonthGrid
|
||||
className={className}
|
||||
displayYears={displayYears}
|
||||
endMonth={endMonth}
|
||||
navView={navView}
|
||||
setNavView={setNavView}
|
||||
startMonth={startMonth}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</MonthGrid>
|
||||
),
|
||||
Nav: ({ className }) => (
|
||||
<Nav
|
||||
className={className}
|
||||
displayYears={displayYears}
|
||||
endMonth={endMonth}
|
||||
navView={navView}
|
||||
onPrevClick={onPrevClick}
|
||||
setDisplayYears={setDisplayYears}
|
||||
startMonth={startMonth}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
numberOfMonths={columnsDisplayed}
|
||||
showOutsideDays={showOutsideDays}
|
||||
style={{
|
||||
width: `${248.8 * (columnsDisplayed ?? 1)}px`,
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Calendar.displayName = "Calendar";
|
||||
|
||||
function Nav({
|
||||
className,
|
||||
navView,
|
||||
startMonth,
|
||||
endMonth,
|
||||
displayYears,
|
||||
setDisplayYears,
|
||||
onPrevClick,
|
||||
onNextClick,
|
||||
}: {
|
||||
className?: string;
|
||||
navView: NavView;
|
||||
startMonth?: Date;
|
||||
endMonth?: Date;
|
||||
displayYears: { from: number; to: number };
|
||||
setDisplayYears: Dispatch<SetStateAction<{ from: number; to: number }>>;
|
||||
onPrevClick?: (date: Date) => void;
|
||||
onNextClick?: (date: Date) => void;
|
||||
}) {
|
||||
const { nextMonth, previousMonth, goToMonth } = useDayPicker();
|
||||
|
||||
const isPreviousDisabled = (() => {
|
||||
if (navView === "years") {
|
||||
return (
|
||||
(startMonth &&
|
||||
differenceInCalendarDays(
|
||||
new Date(displayYears.from - 1, 0, 1),
|
||||
startMonth,
|
||||
) < 0) ||
|
||||
(endMonth &&
|
||||
differenceInCalendarDays(
|
||||
new Date(displayYears.from - 1, 0, 1),
|
||||
endMonth,
|
||||
) > 0)
|
||||
);
|
||||
}
|
||||
return !previousMonth;
|
||||
})();
|
||||
|
||||
const isNextDisabled = (() => {
|
||||
if (navView === "years") {
|
||||
return (
|
||||
(startMonth &&
|
||||
differenceInCalendarDays(
|
||||
new Date(displayYears.to + 1, 0, 1),
|
||||
startMonth,
|
||||
) < 0) ||
|
||||
(endMonth &&
|
||||
differenceInCalendarDays(
|
||||
new Date(displayYears.to + 1, 0, 1),
|
||||
endMonth,
|
||||
) > 0)
|
||||
);
|
||||
}
|
||||
return !nextMonth;
|
||||
})();
|
||||
|
||||
const handlePreviousClick = useCallback(() => {
|
||||
if (!previousMonth) return;
|
||||
if (navView === "years") {
|
||||
setDisplayYears((prev) => ({
|
||||
from: prev.from - (prev.to - prev.from + 1),
|
||||
to: prev.to - (prev.to - prev.from + 1),
|
||||
}));
|
||||
onPrevClick?.(
|
||||
new Date(
|
||||
displayYears.from - (displayYears.to - displayYears.from),
|
||||
0,
|
||||
1,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
goToMonth(previousMonth);
|
||||
onPrevClick?.(previousMonth);
|
||||
}, [previousMonth, goToMonth]);
|
||||
|
||||
const handleNextClick = useCallback(() => {
|
||||
if (!nextMonth) return;
|
||||
if (navView === "years") {
|
||||
setDisplayYears((prev) => ({
|
||||
from: prev.from + (prev.to - prev.from + 1),
|
||||
to: prev.to + (prev.to - prev.from + 1),
|
||||
}));
|
||||
onNextClick?.(
|
||||
new Date(
|
||||
displayYears.from + (displayYears.to - displayYears.from),
|
||||
0,
|
||||
1,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
goToMonth(nextMonth);
|
||||
onNextClick?.(nextMonth);
|
||||
}, [goToMonth, nextMonth]);
|
||||
return (
|
||||
<nav className={cn("flex items-center", className)}>
|
||||
<Button
|
||||
aria-label={
|
||||
navView === "years"
|
||||
? `Go to the previous ${
|
||||
displayYears.to - displayYears.from + 1
|
||||
} years`
|
||||
: labelPrevious(previousMonth)
|
||||
}
|
||||
className="absolute left-0 size-7 bg-transparent p-0 opacity-80 hover:opacity-100"
|
||||
disabled={isPreviousDisabled}
|
||||
onClick={handlePreviousClick}
|
||||
tabIndex={isPreviousDisabled ? undefined : -1}
|
||||
type="button"
|
||||
variant="outline"
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
aria-label={
|
||||
navView === "years"
|
||||
? `Go to the next ${displayYears.to - displayYears.from + 1} years`
|
||||
: labelNext(nextMonth)
|
||||
}
|
||||
className="absolute right-0 size-7 bg-transparent p-0 opacity-80 hover:opacity-100"
|
||||
disabled={isNextDisabled}
|
||||
onClick={handleNextClick}
|
||||
tabIndex={isNextDisabled ? undefined : -1}
|
||||
type="button"
|
||||
variant="outline"
|
||||
>
|
||||
<ChevronRight className="size-4" />
|
||||
</Button>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
|
||||
function CaptionLabel({
|
||||
children,
|
||||
showYearSwitcher,
|
||||
navView,
|
||||
setNavView,
|
||||
displayYears,
|
||||
...props
|
||||
}: {
|
||||
showYearSwitcher?: boolean;
|
||||
navView: NavView;
|
||||
setNavView: Dispatch<SetStateAction<NavView>>;
|
||||
displayYears: { from: number; to: number };
|
||||
} & HTMLAttributes<HTMLSpanElement>) {
|
||||
if (!showYearSwitcher) return <span {...props}>{children}</span>;
|
||||
return (
|
||||
<Button
|
||||
className="h-7 w-full truncate font-medium text-sm"
|
||||
onClick={() => setNavView((prev) => (prev === "days" ? "years" : "days"))}
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
>
|
||||
{navView === "days"
|
||||
? children
|
||||
: `${displayYears.from} - ${displayYears.to}`}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
function MonthGrid({
|
||||
className,
|
||||
children,
|
||||
displayYears,
|
||||
startMonth,
|
||||
endMonth,
|
||||
navView,
|
||||
setNavView,
|
||||
...props
|
||||
}: {
|
||||
className?: string;
|
||||
children: ReactNode;
|
||||
displayYears: { from: number; to: number };
|
||||
startMonth?: Date;
|
||||
endMonth?: Date;
|
||||
navView: NavView;
|
||||
setNavView: Dispatch<SetStateAction<NavView>>;
|
||||
} & TableHTMLAttributes<HTMLTableElement>) {
|
||||
if (navView === "years") {
|
||||
return (
|
||||
<YearGrid
|
||||
className={className}
|
||||
displayYears={displayYears}
|
||||
endMonth={endMonth}
|
||||
navView={navView}
|
||||
setNavView={setNavView}
|
||||
startMonth={startMonth}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<table className={className} {...props}>
|
||||
{children}
|
||||
</table>
|
||||
);
|
||||
}
|
||||
|
||||
function YearGrid({
|
||||
className,
|
||||
displayYears,
|
||||
startMonth,
|
||||
endMonth,
|
||||
setNavView,
|
||||
navView,
|
||||
...props
|
||||
}: {
|
||||
className?: string;
|
||||
displayYears: { from: number; to: number };
|
||||
startMonth?: Date;
|
||||
endMonth?: Date;
|
||||
setNavView: Dispatch<SetStateAction<NavView>>;
|
||||
navView: NavView;
|
||||
} & HTMLAttributes<HTMLDivElement>) {
|
||||
const { goToMonth, selected } = useDayPicker();
|
||||
|
||||
return (
|
||||
<div className={cn("grid grid-cols-4 gap-y-2", className)} {...props}>
|
||||
{Array.from(
|
||||
{ length: displayYears.to - displayYears.from + 1 },
|
||||
(_, i) => {
|
||||
const isBefore =
|
||||
differenceInCalendarDays(
|
||||
new Date(displayYears.from + i, 11, 31),
|
||||
// biome-ignore lint/style/noNonNullAssertion: <exists>
|
||||
startMonth!,
|
||||
) < 0;
|
||||
|
||||
const isAfter =
|
||||
differenceInCalendarDays(
|
||||
new Date(displayYears.from + i, 0, 0),
|
||||
// biome-ignore lint/style/noNonNullAssertion: <exists>
|
||||
endMonth!,
|
||||
) > 0;
|
||||
|
||||
const isDisabled = isBefore || isAfter;
|
||||
return (
|
||||
<Button
|
||||
className={cn(
|
||||
"h-7 w-full font-normal text-foreground text-sm",
|
||||
displayYears.from + i === new Date().getFullYear() &&
|
||||
"bg-accent font-medium text-accent-foreground",
|
||||
)}
|
||||
disabled={navView === "years" ? isDisabled : undefined}
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: <index is acceptable here>
|
||||
key={i}
|
||||
onClick={() => {
|
||||
setNavView("days");
|
||||
goToMonth(
|
||||
new Date(
|
||||
displayYears.from + i,
|
||||
(selected as Date | undefined)?.getMonth() ?? 0,
|
||||
),
|
||||
);
|
||||
}}
|
||||
variant="ghost"
|
||||
>
|
||||
{displayYears.from + i}
|
||||
</Button>
|
||||
);
|
||||
},
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export { Calendar };
|
||||
|
|
@ -1,7 +1,4 @@
|
|||
import { format } from "date-fns";
|
||||
import { it } from "date-fns/locale";
|
||||
import {
|
||||
CalendarIcon,
|
||||
CodeSquare,
|
||||
Eye,
|
||||
Printer,
|
||||
|
|
@ -24,13 +21,13 @@ import {
|
|||
FormMessage,
|
||||
} from "~/components/custom_ui/form";
|
||||
import { NumberInput } from "~/components/custom_ui/InputNumber";
|
||||
import { DateInput } from "~/components/custom_ui/inputDate";
|
||||
import { DualInputLayout } from "~/components/custom_ui/inputLayouts";
|
||||
import {
|
||||
type ListOption,
|
||||
MultiSelect,
|
||||
} from "~/components/custom_ui/multiselect";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { Calendar } from "~/components/ui/calendar";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card";
|
||||
import Input from "~/components/ui/input";
|
||||
import { PhoneInput } from "~/components/ui/phone-input";
|
||||
|
|
@ -55,7 +52,6 @@ import { FieldResetButton } from "~/forms/comps";
|
|||
import { filteredCaratteristiche } from "~/hooks/schedaAnnuncioUtils";
|
||||
import { NullableStringOnChange } from "~/lib/form_utils";
|
||||
import { getStorageUrl } from "~/lib/storage_utils";
|
||||
import { cn } from "~/lib/utils";
|
||||
import { useZodForm } from "~/lib/zodForm";
|
||||
import { StatusBadge } from "~/pages/area-riservata/admin/edit-annuncio/[id]";
|
||||
import { useTranslation } from "~/providers/I18nProvider";
|
||||
|
|
@ -1178,42 +1174,12 @@ export const AnnuncioEditForm = ({ data }: { data: AnnunciWithMedia }) => {
|
|||
</Button>
|
||||
)}
|
||||
</div>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<FormControl>
|
||||
<Button
|
||||
className={cn(
|
||||
"h-10 w-full bg-card pl-3 text-left font-medium",
|
||||
!field.value && "text-muted-foreground",
|
||||
"rounded-lg border border-neutral-300 shadow-xs outline-hidden file:border-0 file:bg-transparent file:font-medium file:text-sm disabled:cursor-not-allowed disabled:opacity-50 dark:focus:border-transparent",
|
||||
)}
|
||||
id="disponibile_da"
|
||||
variant={"outline"}
|
||||
>
|
||||
{field.value ? (
|
||||
format(field.value, "PPP", {
|
||||
locale: it,
|
||||
})
|
||||
) : (
|
||||
<span>Scegli</span>
|
||||
)}
|
||||
<CalendarIcon className="ml-auto size-4 opacity-50" />
|
||||
</Button>
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent align="end" className="w-auto p-0">
|
||||
<Calendar
|
||||
autoFocus
|
||||
captionLayout="dropdown"
|
||||
defaultMonth={field.value || undefined}
|
||||
endMonth={new Date(2050, 12)}
|
||||
locale={it}
|
||||
mode="single"
|
||||
onSelect={field.onChange}
|
||||
selected={field.value || undefined}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<DateInput
|
||||
id="disponibile_da"
|
||||
onChange={field.onChange}
|
||||
placeholder="Seleziona data"
|
||||
value={field.value}
|
||||
/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
import { format } from "date-fns";
|
||||
import { it } from "date-fns/locale";
|
||||
import { CalendarIcon, Trash2 } from "lucide-react";
|
||||
import { Trash2 } from "lucide-react";
|
||||
import toast from "react-hot-toast";
|
||||
import { z } from "zod/v4";
|
||||
import { Confirm } from "~/components/confirm";
|
||||
|
|
@ -18,14 +16,9 @@ import {
|
|||
FormLabel,
|
||||
FormMessage,
|
||||
} from "~/components/custom_ui/form";
|
||||
import { DateInput } from "~/components/custom_ui/inputDate";
|
||||
import { MultiSelect } from "~/components/custom_ui/multiselect";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { Calendar } from "~/components/ui/calendar";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "~/components/ui/popover";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
|
|
@ -35,7 +28,7 @@ import {
|
|||
} from "~/components/ui/select";
|
||||
import { Switch } from "~/components/ui/switch";
|
||||
import { PAYMENT_TYPES, type PaymentType } from "~/i18n/stripe";
|
||||
import { cn, formatCurrency } from "~/lib/utils";
|
||||
import { formatCurrency } from "~/lib/utils";
|
||||
import { useZodForm } from "~/lib/zodForm";
|
||||
import { orderTypeEnum } from "~/schemas/public/OrderTypeEnum";
|
||||
import type { Ordini } from "~/schemas/public/Ordini";
|
||||
|
|
@ -212,42 +205,12 @@ export const FormEditOrder = ({ prezziario, data, close }: FormProps) => {
|
|||
<FormLabel htmlFor="created_at">Data Ordine</FormLabel>
|
||||
<FormMessage />
|
||||
</div>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<FormControl>
|
||||
<Button
|
||||
className={cn(
|
||||
"h-10 w-full bg-card pl-3 text-left font-medium",
|
||||
!field.value && "text-muted-foreground",
|
||||
"rounded-lg border border-neutral-300 shadow-xs outline-hidden file:border-0 file:bg-transparent file:font-medium file:text-sm disabled:cursor-not-allowed disabled:opacity-50 dark:focus:border-transparent",
|
||||
)}
|
||||
id="created_at"
|
||||
variant={"outline"}
|
||||
>
|
||||
{field.value ? (
|
||||
format(field.value, "PPP", {
|
||||
locale: it,
|
||||
})
|
||||
) : (
|
||||
<span>Scegli data</span>
|
||||
)}
|
||||
<CalendarIcon className="ml-auto size-4 opacity-50" />
|
||||
</Button>
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent align="end" className="w-auto p-0">
|
||||
<Calendar
|
||||
autoFocus
|
||||
captionLayout="dropdown"
|
||||
defaultMonth={new Date()}
|
||||
endMonth={new Date(2050, 12)}
|
||||
locale={it}
|
||||
mode="single"
|
||||
onSelect={field.onChange}
|
||||
selected={field.value || undefined}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<DateInput
|
||||
id="created_at"
|
||||
onChange={field.onChange}
|
||||
placeholder="Seleziona data"
|
||||
value={field.value}
|
||||
/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { format } from "date-fns";
|
||||
import { it } from "date-fns/locale";
|
||||
import { ChevronDownIcon } from "lucide-react";
|
||||
import { z } from "zod";
|
||||
import { Confirm } from "~/components/confirm";
|
||||
import {
|
||||
|
|
@ -11,14 +10,9 @@ import {
|
|||
FormLabel,
|
||||
FormMessage,
|
||||
} from "~/components/custom_ui/form";
|
||||
import { DateInput } from "~/components/custom_ui/inputDate";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { Calendar } from "~/components/ui/calendar";
|
||||
import Input from "~/components/ui/input";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "~/components/ui/popover";
|
||||
import { Textarea } from "~/components/ui/textarea";
|
||||
import { useZodForm } from "~/lib/zodForm";
|
||||
import { useTranslation } from "~/providers/I18nProvider";
|
||||
|
|
@ -77,34 +71,12 @@ export const FormEditQueueMail = ({
|
|||
<FormMessage />
|
||||
</div>
|
||||
<FormControl>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
className="w-full justify-between bg-card font-normal"
|
||||
id="date-picker-optional"
|
||||
variant="outline"
|
||||
>
|
||||
{field.value
|
||||
? format(field.value, "PPP", { locale: it })
|
||||
: "Seleziona data"}
|
||||
<ChevronDownIcon />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent
|
||||
align="start"
|
||||
className="w-auto overflow-hidden p-0"
|
||||
>
|
||||
<Calendar
|
||||
captionLayout="dropdown"
|
||||
defaultMonth={field.value}
|
||||
mode="single"
|
||||
onSelect={(date) => {
|
||||
field.onChange(date);
|
||||
}}
|
||||
selected={field.value}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<DateInput
|
||||
id="date-picker-optional"
|
||||
onChange={field.onChange}
|
||||
placeholder="Seleziona data"
|
||||
value={field.value}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
import { format } from "date-fns";
|
||||
import { enUS, it } from "date-fns/locale";
|
||||
import { CalendarIcon, X } from "lucide-react";
|
||||
import { X } from "lucide-react";
|
||||
import { z } from "zod/v4";
|
||||
import { Counter } from "~/components/counter";
|
||||
import {
|
||||
|
|
@ -12,14 +10,9 @@ import {
|
|||
FormLabel,
|
||||
FormMessage,
|
||||
} from "~/components/custom_ui/form";
|
||||
import { DateInput } from "~/components/custom_ui/inputDate";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { Calendar } from "~/components/ui/calendar";
|
||||
import { Label } from "~/components/ui/label";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "~/components/ui/popover";
|
||||
import { Switch } from "~/components/ui/switch";
|
||||
import { cn } from "~/lib/utils";
|
||||
import { useZodForm } from "~/lib/zodForm";
|
||||
|
|
@ -80,8 +73,6 @@ export const FormEditServizio = ({
|
|||
defaultValues: defaultValues,
|
||||
});
|
||||
|
||||
const DatePickerLocale = locale === "it" ? it : enUS;
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form className="space-y-8 px-0.5" onSubmit={form.handleSubmit(onSubmit)}>
|
||||
|
|
@ -168,42 +159,12 @@ export const FormEditServizio = ({
|
|||
</FormLabel>
|
||||
<FormMessage />
|
||||
</div>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<FormControl>
|
||||
<Button
|
||||
className={cn(
|
||||
"h-10 w-full bg-card pl-3 text-left font-medium",
|
||||
!field.value && "text-muted-foreground",
|
||||
"rounded-lg border border-neutral-300 shadow-xs outline-hidden file:border-0 file:bg-transparent file:font-medium file:text-sm disabled:cursor-not-allowed disabled:opacity-50 dark:focus:border-transparent",
|
||||
)}
|
||||
id="decorrenza"
|
||||
variant={"outline"}
|
||||
>
|
||||
{field.value ? (
|
||||
format(field.value, "PPP", {
|
||||
locale: DatePickerLocale,
|
||||
})
|
||||
) : (
|
||||
<span>{t.anagrafica.scegli_data}</span>
|
||||
)}
|
||||
<CalendarIcon className="ml-auto size-4 opacity-50" />
|
||||
</Button>
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent align="end" className="w-auto p-0">
|
||||
<Calendar
|
||||
autoFocus
|
||||
captionLayout="dropdown"
|
||||
defaultMonth={field.value || new Date()}
|
||||
endMonth={new Date(2050, 12)}
|
||||
locale={DatePickerLocale}
|
||||
mode="single"
|
||||
onSelect={field.onChange}
|
||||
selected={field.value || undefined}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<DateInput
|
||||
id="decorrenza"
|
||||
onChange={field.onChange}
|
||||
placeholder={t.anagrafica.scegli_data}
|
||||
value={field.value}
|
||||
/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
import { format, isAfter } from "date-fns";
|
||||
import { it } from "date-fns/locale";
|
||||
import { ChevronDownIcon } from "lucide-react";
|
||||
import { useEffect } from "react";
|
||||
import { useFormContext, useWatch } from "react-hook-form";
|
||||
import { z } from "zod/v4";
|
||||
|
|
@ -12,15 +10,10 @@ import {
|
|||
FormLabel,
|
||||
FormMessage,
|
||||
} from "~/components/custom_ui/form";
|
||||
import { DateInput } from "~/components/custom_ui/inputDate";
|
||||
import { MultiSelect } from "~/components/custom_ui/multiselect";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { Calendar } from "~/components/ui/calendar";
|
||||
import Input from "~/components/ui/input";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "~/components/ui/popover";
|
||||
import { useZodForm } from "~/lib/zodForm";
|
||||
import {
|
||||
type MailsTemplates,
|
||||
|
|
@ -137,34 +130,12 @@ export const FormAddCodaEmail = ({ submitMutation }: FormProps) => {
|
|||
<FormMessage />
|
||||
</div>
|
||||
<FormControl>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
className="w-full justify-between bg-card font-normal"
|
||||
id="date-picker-optional"
|
||||
variant="outline"
|
||||
>
|
||||
{field.value
|
||||
? format(field.value, "PPP", { locale: it })
|
||||
: "Seleziona data"}
|
||||
<ChevronDownIcon />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent
|
||||
align="start"
|
||||
className="w-auto overflow-hidden p-0"
|
||||
>
|
||||
<Calendar
|
||||
captionLayout="dropdown"
|
||||
defaultMonth={field.value}
|
||||
mode="single"
|
||||
onSelect={(date) => {
|
||||
field.onChange(date);
|
||||
}}
|
||||
selected={field.value}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<DateInput
|
||||
id="date-picker-optional"
|
||||
onChange={field.onChange}
|
||||
placeholder="Seleziona data"
|
||||
value={field.value}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
import { format } from "date-fns";
|
||||
import { it } from "date-fns/locale";
|
||||
import { CalendarIcon } from "lucide-react";
|
||||
import toast from "react-hot-toast";
|
||||
import { z } from "zod/v4";
|
||||
import {
|
||||
|
|
@ -17,14 +14,9 @@ import {
|
|||
FormLabel,
|
||||
FormMessage,
|
||||
} from "~/components/custom_ui/form";
|
||||
import { DateInput } from "~/components/custom_ui/inputDate";
|
||||
import { MultiSelect } from "~/components/custom_ui/multiselect";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { Calendar } from "~/components/ui/calendar";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "~/components/ui/popover";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
|
|
@ -34,7 +26,7 @@ import {
|
|||
} from "~/components/ui/select";
|
||||
import { Switch } from "~/components/ui/switch";
|
||||
import { PAYMENT_TYPES } from "~/i18n/stripe";
|
||||
import { cn, formatCurrency } from "~/lib/utils";
|
||||
import { formatCurrency } from "~/lib/utils";
|
||||
import { useZodForm } from "~/lib/zodForm";
|
||||
import { orderTypeEnum } from "~/schemas/public/OrderTypeEnum";
|
||||
import { paymentStatusEnum } from "~/schemas/public/PaymentStatusEnum";
|
||||
|
|
@ -195,42 +187,12 @@ export const FormNewOrder = ({
|
|||
<FormLabel htmlFor="created_at">Data Ordine</FormLabel>
|
||||
<FormMessage />
|
||||
</div>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<FormControl>
|
||||
<Button
|
||||
className={cn(
|
||||
"h-10 w-full bg-card pl-3 text-left font-medium",
|
||||
!field.value && "text-muted-foreground",
|
||||
"rounded-lg border border-neutral-300 shadow-xs outline-hidden file:border-0 file:bg-transparent file:font-medium file:text-sm disabled:cursor-not-allowed disabled:opacity-50 dark:focus:border-transparent",
|
||||
)}
|
||||
id="created_at"
|
||||
variant={"outline"}
|
||||
>
|
||||
{field.value ? (
|
||||
format(field.value, "PPP", {
|
||||
locale: it,
|
||||
})
|
||||
) : (
|
||||
<span>Scegli data</span>
|
||||
)}
|
||||
<CalendarIcon className="ml-auto size-4 opacity-50" />
|
||||
</Button>
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent align="end" className="w-auto p-0">
|
||||
<Calendar
|
||||
autoFocus
|
||||
captionLayout="dropdown"
|
||||
defaultMonth={new Date()}
|
||||
endMonth={new Date(2050, 12)}
|
||||
locale={it}
|
||||
mode="single"
|
||||
onSelect={field.onChange}
|
||||
selected={field.value || undefined}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<DateInput
|
||||
id="created_at"
|
||||
onChange={field.onChange}
|
||||
placeholder="Seleziona data"
|
||||
value={field.value}
|
||||
/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
import { differenceInYears, format } from "date-fns";
|
||||
import { enUS, it } from "date-fns/locale";
|
||||
import { CalendarIcon } from "lucide-react";
|
||||
import { differenceInYears } from "date-fns";
|
||||
import { type Control, useWatch } from "react-hook-form";
|
||||
import toast from "react-hot-toast";
|
||||
import { z } from "zod/v4";
|
||||
|
|
@ -12,15 +10,10 @@ import {
|
|||
FormLabel,
|
||||
FormMessage,
|
||||
} from "~/components/custom_ui/form";
|
||||
import { DateInput } from "~/components/custom_ui/inputDate";
|
||||
import { MultiSelect } from "~/components/custom_ui/multiselect";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { Calendar } from "~/components/ui/calendar";
|
||||
import Input from "~/components/ui/input";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "~/components/ui/popover";
|
||||
import { Separator } from "~/components/ui/separator";
|
||||
import { Switch } from "~/components/ui/switch";
|
||||
import {
|
||||
|
|
@ -33,7 +26,6 @@ import {
|
|||
checkFiscalCodeValidity,
|
||||
NullableStringOnChange,
|
||||
} from "~/lib/form_utils";
|
||||
import { cn } from "~/lib/utils";
|
||||
import { useZodForm } from "~/lib/zodForm";
|
||||
import { useCatasto } from "~/providers/CatastoProvider";
|
||||
import { useTranslation } from "~/providers/I18nProvider";
|
||||
|
|
@ -135,7 +127,6 @@ export const ProfileFormAnagrafica = ({
|
|||
admin_override: false,
|
||||
};
|
||||
const { locale, t } = useTranslation();
|
||||
const DatePickerLocale = locale === "it" ? it : enUS;
|
||||
z.config(z.locales[locale]());
|
||||
|
||||
const form = useZodForm(schema, {
|
||||
|
|
@ -184,42 +175,12 @@ export const ProfileFormAnagrafica = ({
|
|||
</FormLabel>
|
||||
<FormMessage />
|
||||
</div>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<FormControl>
|
||||
<Button
|
||||
className={cn(
|
||||
"h-10 w-full bg-card pl-3 text-left font-medium",
|
||||
!field.value && "text-muted-foreground",
|
||||
"rounded-lg border border-neutral-300 shadow-xs outline-hidden file:border-0 file:bg-transparent file:font-medium file:text-sm disabled:cursor-not-allowed disabled:opacity-50 dark:focus:border-transparent",
|
||||
)}
|
||||
id="data_nascita"
|
||||
variant={"outline"}
|
||||
>
|
||||
{field.value ? (
|
||||
format(field.value, "PPP", {
|
||||
locale: DatePickerLocale,
|
||||
})
|
||||
) : (
|
||||
<span>{t.anagrafica.scegli_data}</span>
|
||||
)}
|
||||
<CalendarIcon className="ml-auto size-4 opacity-50" />
|
||||
</Button>
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent align="end" className="w-auto p-0">
|
||||
<Calendar
|
||||
autoFocus
|
||||
captionLayout="dropdown"
|
||||
defaultMonth={field.value || undefined}
|
||||
endMonth={new Date()}
|
||||
locale={DatePickerLocale}
|
||||
mode="single"
|
||||
onSelect={field.onChange}
|
||||
selected={field.value || undefined}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<DateInput
|
||||
id="data_nascita"
|
||||
onChange={field.onChange}
|
||||
placeholder={t.anagrafica.scegli_data}
|
||||
value={field.value}
|
||||
/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { add, format, formatDuration, intervalToDuration } from "date-fns";
|
||||
import { add, formatDuration, intervalToDuration } from "date-fns";
|
||||
import { it } from "date-fns/locale";
|
||||
import { CalendarIcon, Trash2 } from "lucide-react";
|
||||
import { Trash2 } from "lucide-react";
|
||||
import { z } from "zod/v4";
|
||||
import { Confirm } from "~/components/confirm";
|
||||
import {
|
||||
|
|
@ -11,15 +11,9 @@ import {
|
|||
FormLabel,
|
||||
FormMessage,
|
||||
} from "~/components/custom_ui/form";
|
||||
import { DateInput } from "~/components/custom_ui/inputDate";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { Calendar } from "~/components/ui/calendar";
|
||||
import Input from "~/components/ui/input";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "~/components/ui/popover";
|
||||
import { cn } from "~/lib/utils";
|
||||
import { useZodForm } from "~/lib/zodForm";
|
||||
import { useTranslation } from "~/providers/I18nProvider";
|
||||
import type { Rinnovi } from "~/schemas/public/Rinnovi";
|
||||
|
|
@ -91,46 +85,16 @@ export const FormRinnovo = ({
|
|||
<FormLabel htmlFor="decorrenza">Decorrenza</FormLabel>
|
||||
<FormMessage />
|
||||
</div>
|
||||
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<FormControl>
|
||||
<Button
|
||||
className={cn(
|
||||
"h-10 w-full bg-card pl-3 text-left font-medium",
|
||||
!field.value && "text-muted-foreground",
|
||||
"rounded-lg border border-neutral-300 shadow-xs outline-hidden file:border-0 file:bg-transparent file:font-medium file:text-sm disabled:cursor-not-allowed disabled:opacity-50 dark:focus:border-transparent",
|
||||
)}
|
||||
id="decorrenza"
|
||||
variant={"outline"}
|
||||
>
|
||||
{field.value ? (
|
||||
format(field.value, "PPP", {
|
||||
locale: it,
|
||||
})
|
||||
) : (
|
||||
<span>{t.anagrafica.scegli_data}</span>
|
||||
)}
|
||||
<CalendarIcon className="ml-auto size-4 opacity-50" />
|
||||
</Button>
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent align="end" className="w-auto p-0">
|
||||
<Calendar
|
||||
autoFocus
|
||||
captionLayout="dropdown"
|
||||
defaultMonth={field.value || new Date()}
|
||||
endMonth={new Date(2050, 12)}
|
||||
locale={it}
|
||||
mode="single"
|
||||
onSelect={field.onChange}
|
||||
selected={field.value || undefined}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<DateInput
|
||||
id="decorrenza"
|
||||
onChange={field.onChange}
|
||||
placeholder={t.anagrafica.scegli_data}
|
||||
value={field.value}
|
||||
/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="scadenza"
|
||||
|
|
@ -140,43 +104,12 @@ export const FormRinnovo = ({
|
|||
<FormLabel htmlFor="scadenza">Scadenza</FormLabel>
|
||||
<FormMessage />
|
||||
</div>
|
||||
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<FormControl>
|
||||
<Button
|
||||
className={cn(
|
||||
"h-10 w-full bg-card pl-3 text-left font-medium",
|
||||
!field.value && "text-muted-foreground",
|
||||
"rounded-lg border border-neutral-300 shadow-xs outline-hidden file:border-0 file:bg-transparent file:font-medium file:text-sm disabled:cursor-not-allowed disabled:opacity-50 dark:focus:border-transparent",
|
||||
)}
|
||||
id="scadenza"
|
||||
variant={"outline"}
|
||||
>
|
||||
{field.value ? (
|
||||
format(field.value, "PPP", {
|
||||
locale: it,
|
||||
})
|
||||
) : (
|
||||
<span>{t.anagrafica.scegli_data}</span>
|
||||
)}
|
||||
<CalendarIcon className="ml-auto size-4 opacity-50" />
|
||||
</Button>
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent align="end" className="w-auto p-0">
|
||||
<Calendar
|
||||
autoFocus
|
||||
captionLayout="dropdown"
|
||||
defaultMonth={field.value || new Date()}
|
||||
endMonth={new Date(2050, 12)}
|
||||
locale={it}
|
||||
mode="single"
|
||||
onSelect={field.onChange}
|
||||
selected={field.value || undefined}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<DateInput
|
||||
id="scadenza"
|
||||
onChange={field.onChange}
|
||||
placeholder={t.anagrafica.scegli_data}
|
||||
value={field.value}
|
||||
/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
"use client";
|
||||
import { format } from "date-fns";
|
||||
import { enUS, it } from "date-fns/locale";
|
||||
import { CalendarIcon, Check, HelpCircleIcon, Mail } from "lucide-react";
|
||||
import { Check, HelpCircleIcon, Mail } from "lucide-react";
|
||||
import { useRouter } from "next/router";
|
||||
import { type Control, useWatch } from "react-hook-form";
|
||||
import toast from "react-hot-toast";
|
||||
|
|
@ -17,10 +15,10 @@ import {
|
|||
FormMessage,
|
||||
} from "~/components/custom_ui/form";
|
||||
import InputWIcon from "~/components/custom_ui/input-icon";
|
||||
import { DateInput } from "~/components/custom_ui/inputDate";
|
||||
import { MultiSelect, UnpackOptions } from "~/components/custom_ui/multiselect";
|
||||
import { Badge } from "~/components/ui/badge";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { Calendar } from "~/components/ui/calendar";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
|
|
@ -31,11 +29,6 @@ import {
|
|||
import Input from "~/components/ui/input";
|
||||
import { Label } from "~/components/ui/label";
|
||||
import { PhoneInput } from "~/components/ui/phone-input";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "~/components/ui/popover";
|
||||
import { Separator } from "~/components/ui/separator";
|
||||
import { Slider } from "~/components/ui/slider";
|
||||
import { Switch } from "~/components/ui/switch";
|
||||
|
|
@ -291,7 +284,6 @@ export const FormServizioAcquisto = ({
|
|||
const form = useZodForm(form_schema, {
|
||||
defaultValues: defaultValues,
|
||||
});
|
||||
const DatePickerLocale = locale === "it" ? it : enUS;
|
||||
const { mutate } = api.servizio.processServizioOnboard.useMutation({
|
||||
onError: (error) => {
|
||||
toast.error(`Errore invio dati: ${error.message}`, {
|
||||
|
|
@ -734,42 +726,12 @@ export const FormServizioAcquisto = ({
|
|||
</FormLabel>
|
||||
<FormMessage />
|
||||
</div>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<FormControl>
|
||||
<Button
|
||||
className={cn(
|
||||
"h-10 w-full bg-card pl-3 text-left font-medium",
|
||||
!field.value && "text-muted-foreground",
|
||||
"rounded-lg border border-neutral-300 shadow-xs outline-hidden file:border-0 file:bg-transparent file:font-medium file:text-sm disabled:cursor-not-allowed disabled:opacity-50 dark:focus:border-transparent",
|
||||
)}
|
||||
id="scadenza_motivazione_transitoria"
|
||||
variant={"outline"}
|
||||
>
|
||||
{field.value ? (
|
||||
format(field.value, "PPP", {
|
||||
locale: it,
|
||||
})
|
||||
) : (
|
||||
<span>{t.anagrafica.scegli_data}</span>
|
||||
)}
|
||||
<CalendarIcon className="ml-auto size-4 opacity-50" />
|
||||
</Button>
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent align="end" className="w-auto p-0">
|
||||
<Calendar
|
||||
autoFocus
|
||||
captionLayout="dropdown"
|
||||
defaultMonth={field.value || new Date()}
|
||||
endMonth={new Date(2050, 12)}
|
||||
locale={it}
|
||||
mode="single"
|
||||
onSelect={field.onChange}
|
||||
selected={field.value || undefined}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<DateInput
|
||||
id="scadenza_motivazione_transitoria"
|
||||
onChange={field.onChange}
|
||||
placeholder={t.anagrafica.scegli_data}
|
||||
value={field.value}
|
||||
/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
|
@ -908,42 +870,12 @@ export const FormServizioAcquisto = ({
|
|||
</FormLabel>
|
||||
<FormMessage />
|
||||
</div>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<FormControl>
|
||||
<Button
|
||||
className={cn(
|
||||
"h-10 w-full bg-card pl-3 text-left font-medium",
|
||||
!field.value && "text-muted-foreground",
|
||||
"rounded-lg border border-neutral-300 shadow-xs outline-hidden file:border-0 file:bg-transparent file:font-medium file:text-sm disabled:cursor-not-allowed disabled:opacity-50 dark:focus:border-transparent",
|
||||
)}
|
||||
id="dataNascita"
|
||||
variant={"outline"}
|
||||
>
|
||||
{field.value ? (
|
||||
format(field.value, "PPP", {
|
||||
locale: DatePickerLocale,
|
||||
})
|
||||
) : (
|
||||
<span>{t.anagrafica.scegli_data}</span>
|
||||
)}
|
||||
<CalendarIcon className="ml-auto size-4 opacity-50" />
|
||||
</Button>
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent align="end" className="w-auto p-0">
|
||||
<Calendar
|
||||
autoFocus
|
||||
captionLayout="dropdown"
|
||||
defaultMonth={field.value}
|
||||
endMonth={new Date()}
|
||||
locale={DatePickerLocale}
|
||||
mode="single"
|
||||
onSelect={field.onChange}
|
||||
selected={field.value}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<DateInput
|
||||
id="dataNascita"
|
||||
onChange={field.onChange}
|
||||
placeholder={t.anagrafica.scegli_data}
|
||||
value={field.value}
|
||||
/>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -6,14 +6,13 @@ import type { ComponentProps, ReactElement, ReactNode } from "react";
|
|||
import { Toaster } from "react-hot-toast";
|
||||
import "~/styles/globals.css";
|
||||
import { ThemeProvider as NextThemesProvider } from "next-themes";
|
||||
import NextNProgress from "nextjs-progressbar";
|
||||
import { NuqsAdapter } from "nuqs/adapters/next/pages";
|
||||
import { Layout } from "~/components/Layout";
|
||||
import { I18nProvider } from "~/providers/I18nProvider";
|
||||
import { SessionProvider } from "~/providers/SessionProvider";
|
||||
import { api } from "~/utils/api";
|
||||
import { inter } from "~/utils/fonts";
|
||||
import "react-day-picker/dist/style.css";
|
||||
import NextNProgress from "nextjs-progressbar";
|
||||
import { NuqsAdapter } from "nuqs/adapters/next/pages";
|
||||
|
||||
type ThemeProviderProps = ComponentProps<typeof NextThemesProvider>;
|
||||
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue