Refactor various components for improved UI consistency and functionality; update layout styles, enhance user interactions, and introduce reset button functionality in forms.
This commit is contained in:
parent
1baca2997a
commit
c87a7238a7
14 changed files with 150 additions and 275 deletions
|
|
@ -190,7 +190,7 @@ export const AreaRiservataLayoutUserView = ({
|
|||
isAdmin
|
||||
/>
|
||||
|
||||
<div className="mx-4 my-3 flex-1 overflow-auto">
|
||||
<div className="mx-2 my-3 flex-1 overflow-auto lg:mx-4">
|
||||
<UserViewHeader />
|
||||
|
||||
{children}
|
||||
|
|
|
|||
|
|
@ -134,6 +134,7 @@ export const MultiSelect = ({
|
|||
control: () =>
|
||||
cn(
|
||||
"mt-2 w-full rounded-lg h-min-[42px] bg-card shadow-xs outline-hidden text-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
|
||||
disabled && "bg-muted opacity-50 cursor-not-allowed",
|
||||
),
|
||||
input: () => cn("*:ring-0 focus:*:ring-0"),
|
||||
menu: () =>
|
||||
|
|
|
|||
|
|
@ -169,21 +169,6 @@ const DocSection = () => {
|
|||
const { data, updateServizioAnnunci } = useServizioAnnuncio();
|
||||
|
||||
const utils = api.useUtils();
|
||||
// const { mutate: updateServizio } = api.servizio.UpdateConfermaDoc.useMutation(
|
||||
// {
|
||||
// onError: (error) => {
|
||||
// toast.error(error.message);
|
||||
// },
|
||||
// onSuccess: async () => {
|
||||
// await utils.servizio.getAllServizioAnnunci.invalidate({ userId });
|
||||
// await utils.servizio.getServizio.invalidate({
|
||||
// servizioId,
|
||||
// });
|
||||
|
||||
// toast.success("Dati salvati con successo");
|
||||
// },
|
||||
// },
|
||||
// );
|
||||
|
||||
const { data: files, isLoading } = api.storage.getAll.useQuery();
|
||||
|
||||
|
|
@ -622,6 +607,7 @@ const StabileSection = () => {
|
|||
1000,
|
||||
[value],
|
||||
);
|
||||
//TODO selettore per pack consulenza
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-2 rounded-md border border-border bg-muted p-2 sm:flex-row">
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ export const AdminContratto = () => {
|
|||
aria-label="Open Contratto Section"
|
||||
className="w-fit"
|
||||
size="sm"
|
||||
variant={data.doc_contratto_added ? "success" : "secondary"}
|
||||
variant={data.doc_contratto_added ? "success" : "orange"}
|
||||
>
|
||||
{data.doc_contratto_added ? <CircleCheck /> : <Wrench />}
|
||||
Contratto
|
||||
|
|
|
|||
|
|
@ -134,12 +134,11 @@ export const UserActions = () => {
|
|||
<>
|
||||
<div className="flex w-full flex-col flex-wrap gap-2 sm:flex-row">
|
||||
<ContattiProprietarioModal />
|
||||
{ConfermaUtente
|
||||
? !data.hasConfermaAdmin && <ConfermaInLavorazioneModal />
|
||||
: ContattiSbloccati && <ConfermaAnnuncioModal />}
|
||||
|
||||
{ContattiSbloccati && !ConfermaUtente && <ConfermaAnnuncioModal />}
|
||||
{ConfermaUtente && !data.hasConfermaAdmin && (
|
||||
<ConfermaInLavorazioneModal />
|
||||
)}
|
||||
{AccettatoConferma && (
|
||||
{AccettatoConferma ? (
|
||||
<Link
|
||||
aria-label="Conferma immobile"
|
||||
href={`/servizio/riapri-conferma/${servizioId}/${annuncioId}`}
|
||||
|
|
@ -149,8 +148,8 @@ export const UserActions = () => {
|
|||
Rivedi la conferma
|
||||
</Button>
|
||||
</Link>
|
||||
)}
|
||||
{ConfermaLavorata &&
|
||||
) : (
|
||||
ConfermaLavorata &&
|
||||
(data.doc_conferma_ref ? (
|
||||
<Link
|
||||
aria-label="Conferma immobile"
|
||||
|
|
@ -181,7 +180,8 @@ export const UserActions = () => {
|
|||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
))}
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
|
||||
{data.accettato_conferma_at != null && <PostConfermaSection />}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { Toolbox } from "lucide-react";
|
||||
import Image from "next/image";
|
||||
import {
|
||||
AdminActions,
|
||||
|
|
@ -10,22 +11,21 @@ import { cn, formatCurrency } from "~/lib/utils";
|
|||
import { useTranslation } from "~/providers/I18nProvider";
|
||||
import { useServizio, useServizioAnnuncio } from "~/providers/ServizioProvider";
|
||||
import type { AnnuncioRicerca } from "~/server/controllers/annunci.controller";
|
||||
import { Button } from "../ui/button";
|
||||
import {
|
||||
Collapsible,
|
||||
CollapsibleContent,
|
||||
CollapsibleTrigger,
|
||||
} from "../ui/collapsible";
|
||||
import { AnnuncioDettaglio, TipoBadge } from "./annuncio_dettaglio";
|
||||
|
||||
export const AnnuncioCard = ({
|
||||
className,
|
||||
confirming,
|
||||
}: {
|
||||
className?: string;
|
||||
confirming?: boolean;
|
||||
}) => {
|
||||
export const AnnuncioCard = ({ className }: { className?: string }) => {
|
||||
const { isAdmin } = useServizio();
|
||||
const { data } = useServizioAnnuncio();
|
||||
|
||||
return (
|
||||
<BasicAnnuncioCard
|
||||
className={className}
|
||||
confirming={confirming}
|
||||
data={{
|
||||
...data,
|
||||
modificato_il: data.modificato_il ? new Date(data.modificato_il) : null,
|
||||
|
|
@ -33,18 +33,63 @@ export const AnnuncioCard = ({
|
|||
? new Date(data.media_updated_at)
|
||||
: null,
|
||||
}}
|
||||
interactions={isAdmin ? <AdminActions /> : <UserActions />}
|
||||
interactions={
|
||||
isAdmin ? (
|
||||
<div className="flex flex-col gap-2">
|
||||
<Collapsible className="space-y-2">
|
||||
<CollapsibleTrigger>
|
||||
<Button variant="outline">
|
||||
<Toolbox />
|
||||
<span>Azioni Utente</span>
|
||||
</Button>
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent className="rounded-md border border-border bg-muted p-2">
|
||||
<UserActions />
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
|
||||
<AdminActions />
|
||||
</div>
|
||||
) : (
|
||||
<UserActions />
|
||||
)
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const BasicAnnuncioCard = ({
|
||||
interactions,
|
||||
className,
|
||||
data,
|
||||
}: {
|
||||
interactions?: React.ReactNode;
|
||||
className?: string;
|
||||
data: AnnuncioRicerca;
|
||||
}) => {
|
||||
return (
|
||||
<Card className={cn("w-full gap-2 border-white py-3", className)}>
|
||||
<CardHeader className="flex flex-row flex-wrap items-center justify-between space-y-0 px-3 pb-2">
|
||||
<CardTitle className="text-2xl">Annuncio {data.codice}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="px-3">
|
||||
<div
|
||||
className={cn("@container flex w-full flex-col gap-4")}
|
||||
id="container"
|
||||
>
|
||||
<AnnuncioDisplay data={data} />
|
||||
<div className="flex w-full flex-col gap-4">{interactions}</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export const AnnuncioDisplay = ({
|
||||
data,
|
||||
confirming,
|
||||
className,
|
||||
}: {
|
||||
data: AnnuncioRicerca;
|
||||
confirming?: boolean;
|
||||
className?: string;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
|
@ -53,7 +98,6 @@ export const AnnuncioDisplay = ({
|
|||
<div
|
||||
className={cn(
|
||||
"grid @md:grid-cols-[12rem_1fr] grid-cols-[7rem_1fr] gap-x-4 gap-y-2 rounded-md md:max-w-3xl md:border md:border-white md:bg-[#e6e9ec]/50 lg:gap-x-4 xl:gap-x-6 dark:md:border-primary dark:md:bg-card",
|
||||
confirming && "xl:w-1/2",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
|
|
@ -103,42 +147,3 @@ export const AnnuncioDisplay = ({
|
|||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const BasicAnnuncioCard = ({
|
||||
interactions,
|
||||
className,
|
||||
data,
|
||||
confirming,
|
||||
}: {
|
||||
interactions?: React.ReactNode;
|
||||
className?: string;
|
||||
data: AnnuncioRicerca;
|
||||
confirming?: boolean;
|
||||
}) => {
|
||||
return (
|
||||
<Card className={cn("w-full gap-2 border-white py-3", className)}>
|
||||
<CardHeader className="flex flex-row flex-wrap items-center justify-between space-y-0 px-3 pb-2">
|
||||
<CardTitle className="text-2xl">Annuncio {data.codice}</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="px-3">
|
||||
<div
|
||||
className={cn(
|
||||
"@container flex w-full flex-col gap-4",
|
||||
confirming && "xl:flex-row xl:gap-6",
|
||||
)}
|
||||
id="container"
|
||||
>
|
||||
<AnnuncioDisplay confirming={confirming} data={data} />
|
||||
<div
|
||||
className={cn(
|
||||
"flex w-full flex-col gap-4",
|
||||
confirming && "xl:w-1/2",
|
||||
)}
|
||||
>
|
||||
{interactions}
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -285,10 +285,7 @@ export const ServizioContent = () => {
|
|||
servizioId={servizio.servizio_id}
|
||||
userId={userId}
|
||||
>
|
||||
<AnnuncioCard
|
||||
className="rounded-md border-primary"
|
||||
confirming
|
||||
/>
|
||||
<AnnuncioCard className="rounded-md border-primary" />
|
||||
</ServizioAnnuncioProvider>
|
||||
);
|
||||
})}
|
||||
|
|
|
|||
|
|
@ -6,12 +6,14 @@ import {
|
|||
ChevronUp,
|
||||
ClockAlert,
|
||||
Cog,
|
||||
ExternalLink,
|
||||
Info,
|
||||
Plus,
|
||||
SlidersHorizontal,
|
||||
Trash2,
|
||||
UserCircle,
|
||||
} from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import {
|
||||
|
|
@ -60,6 +62,7 @@ import { cn, formatCurrency } from "~/lib/utils";
|
|||
import { useServizio } from "~/providers/ServizioProvider";
|
||||
import type { AnnunciId } from "~/schemas/public/Annunci";
|
||||
import type { ServizioServizioId } from "~/schemas/public/Servizio";
|
||||
import TipologiaPosizioneEnum from "~/schemas/public/TipologiaPosizioneEnum";
|
||||
import type { UsersId } from "~/schemas/public/Users";
|
||||
import { api } from "~/utils/api";
|
||||
import { Confirm } from "../confirm";
|
||||
|
|
@ -131,9 +134,9 @@ const ServizioInfos = () => {
|
|||
</Button>
|
||||
)}
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent className="mb-4 flex w-full flex-col gap-8 rounded-md border bg-card p-2 sm:items-start sm:gap-4">
|
||||
<CollapsibleContent className="mb-4 flex w-full flex-col gap-4 rounded-md border bg-card p-2 sm:items-start sm:gap-6">
|
||||
<ServizioBasicActions />
|
||||
<div className="flex w-full flex-col gap-8 sm:flex-row sm:items-start">
|
||||
<div className="flex w-full flex-col gap-4 sm:flex-row sm:items-start sm:gap-6">
|
||||
<div className="flex flex-2 flex-col gap-2 sm:w-1/2">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
|
|
@ -173,7 +176,7 @@ const ServizioBasicActions = ({ className }: { className?: string }) => {
|
|||
|
||||
if (isAdmin || canUserEdit) {
|
||||
return (
|
||||
<div className={cn("flex flex-wrap items-center gap-3", className)}>
|
||||
<div className={cn("flex flex-wrap items-center gap-2", className)}>
|
||||
<EditParametri />
|
||||
<InterruzioneServizio />
|
||||
</div>
|
||||
|
|
@ -234,6 +237,27 @@ export const ServizioPacksInfos = () => {
|
|||
<span className="font-medium">{packs.saldo.message}</span>
|
||||
)}
|
||||
</div>
|
||||
{servizio.tipologia === TipologiaPosizioneEnum.Stabile && (
|
||||
<div className="flex flex-1 flex-col gap-2 rounded-md bg-secondary/50 p-2">
|
||||
<>
|
||||
<span className="font-medium">Consulenza</span>
|
||||
<span className="text-muted-foreground text-sm">
|
||||
Il prezzo della consulenza varia in base alla tipologia
|
||||
contrattuale.{" "}
|
||||
</span>
|
||||
<span className="font-semibold">
|
||||
<Link
|
||||
className="flex items-center gap-2 underline underline-offset-2"
|
||||
href={"/prezzi#contratti"}
|
||||
target="_blank"
|
||||
>
|
||||
<span>Vedi prezzi contratti</span>
|
||||
<ExternalLink className="size-4 stroke-foreground" />
|
||||
</Link>
|
||||
</span>
|
||||
</>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -390,7 +414,7 @@ const InterruzioneServizio = () => {
|
|||
servizio.annunci.some((a) => a.user_confirmed_at !== null))
|
||||
}
|
||||
>
|
||||
<ClockAlert /> <span>Richiedi Interruzione</span>
|
||||
<ClockAlert /> <span>Interruzione</span>
|
||||
</Button>
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogContent>
|
||||
|
|
|
|||
|
|
@ -1,169 +0,0 @@
|
|||
"use client";
|
||||
|
||||
import { type Label as LabelPrimitive, Slot as SlotPrimitive } from "radix-ui";
|
||||
import * as React from "react";
|
||||
|
||||
import {
|
||||
Controller,
|
||||
type ControllerProps,
|
||||
type FieldPath,
|
||||
type FieldValues,
|
||||
FormProvider,
|
||||
useFormContext,
|
||||
useFormState,
|
||||
} from "react-hook-form";
|
||||
import { Label } from "~/components/ui/label";
|
||||
import { cn } from "~/lib/utils";
|
||||
|
||||
const Form = FormProvider;
|
||||
|
||||
type FormFieldContextValue<
|
||||
TFieldValues extends FieldValues = FieldValues,
|
||||
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
||||
> = {
|
||||
name: TName;
|
||||
};
|
||||
|
||||
const FormFieldContext = React.createContext<FormFieldContextValue>(
|
||||
{} as FormFieldContextValue,
|
||||
);
|
||||
|
||||
const FormField = <
|
||||
TFieldValues extends FieldValues = FieldValues,
|
||||
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
||||
>({
|
||||
...props
|
||||
}: ControllerProps<TFieldValues, TName>) => {
|
||||
return (
|
||||
<FormFieldContext.Provider value={{ name: props.name }}>
|
||||
<Controller {...props} />
|
||||
</FormFieldContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
const useFormField = () => {
|
||||
const fieldContext = React.useContext(FormFieldContext);
|
||||
const itemContext = React.useContext(FormItemContext);
|
||||
const { getFieldState } = useFormContext();
|
||||
const formState = useFormState({ name: fieldContext.name });
|
||||
const fieldState = getFieldState(fieldContext.name, formState);
|
||||
|
||||
if (!fieldContext) {
|
||||
throw new Error("useFormField should be used within <FormField>");
|
||||
}
|
||||
|
||||
const { id } = itemContext;
|
||||
|
||||
return {
|
||||
formDescriptionId: `${id}-form-item-description`,
|
||||
formItemId: `${id}-form-item`,
|
||||
formMessageId: `${id}-form-item-message`,
|
||||
id,
|
||||
name: fieldContext.name,
|
||||
...fieldState,
|
||||
};
|
||||
};
|
||||
|
||||
type FormItemContextValue = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
const FormItemContext = React.createContext<FormItemContextValue>(
|
||||
{} as FormItemContextValue,
|
||||
);
|
||||
|
||||
function FormItem({ className, ...props }: React.ComponentProps<"div">) {
|
||||
const id = React.useId();
|
||||
|
||||
return (
|
||||
<FormItemContext.Provider value={{ id }}>
|
||||
<div
|
||||
className={cn("grid gap-2", className)}
|
||||
data-slot="form-item"
|
||||
{...props}
|
||||
/>
|
||||
</FormItemContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
function FormLabel({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof LabelPrimitive.Root>) {
|
||||
const { error, formItemId } = useFormField();
|
||||
|
||||
return (
|
||||
<Label
|
||||
className={cn("data-[error=true]:text-destructive", className)}
|
||||
data-error={!!error}
|
||||
data-slot="form-label"
|
||||
htmlFor={formItemId}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function FormControl({
|
||||
...props
|
||||
}: React.ComponentProps<typeof SlotPrimitive.Slot>) {
|
||||
const { error, formItemId, formDescriptionId, formMessageId } =
|
||||
useFormField();
|
||||
|
||||
return (
|
||||
<SlotPrimitive.Slot
|
||||
aria-describedby={
|
||||
!error
|
||||
? `${formDescriptionId}`
|
||||
: `${formDescriptionId} ${formMessageId}`
|
||||
}
|
||||
aria-invalid={!!error}
|
||||
data-slot="form-control"
|
||||
id={formItemId}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function FormDescription({ className, ...props }: React.ComponentProps<"p">) {
|
||||
const { formDescriptionId } = useFormField();
|
||||
|
||||
return (
|
||||
<p
|
||||
className={cn("text-muted-foreground text-sm", className)}
|
||||
data-slot="form-description"
|
||||
id={formDescriptionId}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function FormMessage({ className, ...props }: React.ComponentProps<"p">) {
|
||||
const { error, formMessageId } = useFormField();
|
||||
const body = error ? String(error?.message ?? "") : props.children;
|
||||
|
||||
if (!body) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<p
|
||||
className={cn("text-destructive text-sm", className)}
|
||||
data-slot="form-message"
|
||||
id={formMessageId}
|
||||
{...props}
|
||||
>
|
||||
{body}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
export {
|
||||
useFormField,
|
||||
Form,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormMessage,
|
||||
FormField,
|
||||
};
|
||||
|
|
@ -27,7 +27,7 @@ function Slider({
|
|||
return (
|
||||
<SliderPrimitive.Root
|
||||
className={cn(
|
||||
"relative flex w-full touch-none select-none items-center data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col data-[disabled]:opacity-50",
|
||||
"relative flex w-full touch-none select-none items-center data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col data-disabled:opacity-50",
|
||||
className,
|
||||
)}
|
||||
data-slot="slider"
|
||||
|
|
@ -39,7 +39,7 @@ function Slider({
|
|||
>
|
||||
<SliderPrimitive.Track
|
||||
className={cn(
|
||||
"relative grow overflow-hidden rounded-full bg-muted data-[orientation=horizontal]:h-1.5 data-[orientation=vertical]:h-full data-[orientation=horizontal]:w-full data-[orientation=vertical]:w-1.5",
|
||||
"relative grow cursor-pointer overflow-hidden rounded-full bg-muted data-[orientation=horizontal]:h-1.5 data-[orientation=vertical]:h-full data-[orientation=horizontal]:w-full data-[orientation=vertical]:w-1.5",
|
||||
)}
|
||||
data-slot="slider-track"
|
||||
>
|
||||
|
|
@ -54,7 +54,7 @@ function Slider({
|
|||
{Array.from({ length: _values.length }, (_, index) => (
|
||||
<SliderPrimitive.Thumb
|
||||
className={cn(
|
||||
"block size-4 shrink-0 rounded-full border border-primary bg-background shadow-sm ring-ring/50 transition-[color,box-shadow] hover:ring-4 focus-visible:outline-hidden focus-visible:ring-4 disabled:pointer-events-none disabled:opacity-50",
|
||||
"block size-4 shrink-0 cursor-pointer rounded-full border border-primary bg-background shadow-sm ring-ring/50 transition-[color,box-shadow] hover:ring-4 focus-visible:outline-hidden focus-visible:ring-4 disabled:pointer-events-none disabled:opacity-50",
|
||||
thumbClassName,
|
||||
)}
|
||||
data-slot="slider-thumb"
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import { useZodForm } from "~/lib/zodForm";
|
|||
import { useTranslation } from "~/providers/I18nProvider";
|
||||
import type { Servizio } from "~/schemas/public/Servizio";
|
||||
import TipologiaPosizioneEnum from "~/schemas/public/TipologiaPosizioneEnum";
|
||||
import { FieldResetButton } from "./comps";
|
||||
|
||||
const Schema = z
|
||||
.object({
|
||||
|
|
@ -228,13 +229,9 @@ export const FormNewServizio = ({
|
|||
{t.parametri.dalmese_label}...
|
||||
</FormLabel>
|
||||
{field.value !== null && !initialData && (
|
||||
<button
|
||||
className="text-sm"
|
||||
<FieldResetButton
|
||||
onClick={() => form.setValue("entromese", null)}
|
||||
type="button"
|
||||
>
|
||||
Reset
|
||||
</button>
|
||||
/>
|
||||
)}
|
||||
|
||||
<FormMessage />
|
||||
|
|
@ -253,6 +250,7 @@ export const FormNewServizio = ({
|
|||
elementId="select-mesi"
|
||||
elementName="entro_mese"
|
||||
isMulti={false}
|
||||
key={field.value}
|
||||
onValueChange={(value) => {
|
||||
field.onChange(
|
||||
value.value !== "" ? parseInt(value.value) : null,
|
||||
|
|
@ -274,17 +272,19 @@ export const FormNewServizio = ({
|
|||
render={({ field }) => (
|
||||
<FormItem className="w-full">
|
||||
<div className="flex flex-wrap items-center gap-x-2">
|
||||
<FormLabel htmlFor="permanenza">
|
||||
<FormLabel
|
||||
className={cn(
|
||||
tipologia !== TipologiaPosizioneEnum.Transitorio &&
|
||||
"opacity-50",
|
||||
)}
|
||||
htmlFor="permanenza"
|
||||
>
|
||||
{t.parametri.permanenza_label}
|
||||
</FormLabel>
|
||||
{field.value !== null && !initialData && (
|
||||
<button
|
||||
className="text-sm"
|
||||
<FieldResetButton
|
||||
onClick={() => form.setValue("permanenza", null)}
|
||||
type="button"
|
||||
>
|
||||
Reset
|
||||
</button>
|
||||
/>
|
||||
)}
|
||||
<FormMessage />
|
||||
</div>
|
||||
|
|
@ -303,6 +303,7 @@ export const FormNewServizio = ({
|
|||
elementId="permanenza"
|
||||
elementName="permanenza"
|
||||
isMulti={false}
|
||||
key={field.value}
|
||||
onValueChange={(value) => {
|
||||
field.onChange(
|
||||
value.value !== "" ? parseInt(value.value) : null,
|
||||
|
|
@ -314,7 +315,11 @@ export const FormNewServizio = ({
|
|||
placeholder="Seleziona..."
|
||||
/>
|
||||
</FormControl>
|
||||
<FormDescription>{t.parametri.permanenza_desc}</FormDescription>
|
||||
{tipologia === TipologiaPosizioneEnum.Transitorio && (
|
||||
<FormDescription>
|
||||
{t.parametri.permanenza_desc}
|
||||
</FormDescription>
|
||||
)}
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -639,7 +639,13 @@ export const FormNewServizioAcquisto = ({
|
|||
render={({ field }) => (
|
||||
<FormItem className="w-full">
|
||||
<div className="flex flex-wrap items-center gap-x-2">
|
||||
<FormLabel htmlFor="permanenza">
|
||||
<FormLabel
|
||||
className={cn(
|
||||
tipologia !== TipologiaPosizioneEnum.Transitorio &&
|
||||
"opacity-50",
|
||||
)}
|
||||
htmlFor="permanenza"
|
||||
>
|
||||
{t.parametri.permanenza_label}
|
||||
</FormLabel>
|
||||
<FormMessage />
|
||||
|
|
@ -673,9 +679,11 @@ export const FormNewServizioAcquisto = ({
|
|||
placeholder="Seleziona..."
|
||||
/>
|
||||
</FormControl>
|
||||
{tipologia === TipologiaPosizioneEnum.Transitorio && (
|
||||
<FormDescription>
|
||||
{t.parametri.permanenza_desc}
|
||||
</FormDescription>
|
||||
)}
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ export const ProfileFormAnagrafica = ({
|
|||
<FormControl>
|
||||
<Button
|
||||
className={cn(
|
||||
"h-[42px] w-full pl-3 text-left font-medium",
|
||||
"h-10.5 w-full 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",
|
||||
)}
|
||||
|
|
|
|||
18
apps/infoalloggi/src/forms/comps.tsx
Normal file
18
apps/infoalloggi/src/forms/comps.tsx
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import { RefreshCcw } from "lucide-react";
|
||||
import { cn } from "~/lib/utils";
|
||||
|
||||
export const FieldResetButton = (
|
||||
props: React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
) => {
|
||||
const { className, ...rest } = props;
|
||||
return (
|
||||
<button
|
||||
{...rest}
|
||||
className={cn("flex items-center gap-2 text-sm leading-none", className)}
|
||||
type="button"
|
||||
>
|
||||
Reset
|
||||
<RefreshCcw className="size-3.5" />
|
||||
</button>
|
||||
);
|
||||
};
|
||||
Loading…
Add table
Reference in a new issue