feat: implement lazy loading for CardAnnuncio component; add skeleton loading state and enhance InputNumber component with height prop
This commit is contained in:
parent
f64597cc32
commit
3dc0bccb58
18 changed files with 199 additions and 154 deletions
|
|
@ -10,7 +10,8 @@ import {
|
|||
} from "lucide-react";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { useState } from "react";
|
||||
import { type RefObject, useEffect, useRef, useState } from "react";
|
||||
import { useIntersection } from "react-use";
|
||||
import { ImageFlbk } from "~/components/ImageWithFallback";
|
||||
import {
|
||||
Carousel,
|
||||
|
|
@ -30,15 +31,77 @@ import { camereTesti, handleConsegna } from "~/lib/annuncio_details";
|
|||
import { cn, formatCurrency } from "~/lib/utils";
|
||||
import { useTranslation } from "~/providers/I18nProvider";
|
||||
import type { AnnuncioRicerca } from "~/server/controllers/annunci.controller";
|
||||
|
||||
import { Badge } from "./ui/badge";
|
||||
import { Skeleton } from "./ui/skeleton";
|
||||
import { VideoPlayer } from "./videoPlayer";
|
||||
|
||||
type CardAnnuncioProps = AnnuncioRicerca & {
|
||||
className?: string;
|
||||
noLink?: boolean;
|
||||
onlyFirstImage?: boolean;
|
||||
eager?: boolean;
|
||||
};
|
||||
|
||||
export const LazyCardAnnuncio = (props: CardAnnuncioProps) => {
|
||||
const { eager = false } = props;
|
||||
const intersectionRef = useRef<HTMLDivElement>(null);
|
||||
const hasRenderedRef = useRef(eager);
|
||||
const [shouldRender, setShouldRender] = useState(eager);
|
||||
|
||||
const intersection = useIntersection(
|
||||
intersectionRef as RefObject<HTMLElement>,
|
||||
{
|
||||
root: null,
|
||||
rootMargin: "300px",
|
||||
threshold: 0.01,
|
||||
},
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
!hasRenderedRef.current &&
|
||||
intersection &&
|
||||
intersection.intersectionRatio > 0
|
||||
) {
|
||||
hasRenderedRef.current = true;
|
||||
setShouldRender(true);
|
||||
}
|
||||
}, [intersection]);
|
||||
|
||||
return (
|
||||
<div className="min-h-[31.1rem]" ref={intersectionRef}>
|
||||
{shouldRender ? <CardAnnuncio {...props} /> : <SkeletonCardAnnuncio />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const SkeletonCardAnnuncio = () => {
|
||||
return (
|
||||
<div className="h-[31.1rem] rounded-md bg-white p-2 outline outline-neutral-300 hover:outline-neutral-600">
|
||||
<div className="flex h-full flex-col gap-2 p-2">
|
||||
<Skeleton className="h-64 w-full rounded-t-md" />
|
||||
<div className="flex flex-col gap-2">
|
||||
<Skeleton className="h-8 w-full rounded-md" />
|
||||
|
||||
<div className="flex flex-row justify-between gap-3 px-4">
|
||||
<Skeleton className="h-10 w-full rounded-md" />
|
||||
<Skeleton className="h-10 w-full rounded-md" />
|
||||
</div>
|
||||
<div className="flex h-[8.5rem] flex-col justify-between">
|
||||
<Skeleton className="h-20 w-full rounded-md" />
|
||||
|
||||
<div className="flex h-9 items-center justify-around gap-1.5">
|
||||
<Skeleton className="size-full rounded-md" />
|
||||
<Skeleton className="size-full rounded-md" />
|
||||
<Skeleton className="size-full rounded-md" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export const CardAnnuncio = ({
|
||||
id,
|
||||
codice,
|
||||
|
|
@ -81,7 +144,7 @@ export const CardAnnuncio = ({
|
|||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"relative h-[31.1rem] rounded-md bg-white shadow-neutral-100 shadow-sm outline outline-neutral-300 hover:shadow-md hover:outline-neutral-600",
|
||||
"relative h-[31.1rem] rounded-md bg-white outline outline-neutral-300 hover:outline-neutral-600",
|
||||
className,
|
||||
)}
|
||||
id={`card-annuncio-${id}`}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { ChevronDown, ChevronUp } from "lucide-react";
|
||||
import { forwardRef, useCallback, useEffect, useRef, useState } from "react";
|
||||
import { NumericFormat, type NumericFormatProps } from "react-number-format";
|
||||
import { cn } from "~/lib/utils";
|
||||
import { Button } from "../ui/button";
|
||||
import { Input } from "../ui/input";
|
||||
|
||||
|
|
@ -18,6 +19,7 @@ export interface NumberInputProps
|
|||
onValueChange?: (value: number | undefined) => void;
|
||||
fixedDecimalScale?: boolean;
|
||||
decimalScale?: number;
|
||||
height?: string;
|
||||
}
|
||||
|
||||
export const NumberInput = forwardRef<HTMLInputElement, NumberInputProps>(
|
||||
|
|
@ -35,6 +37,8 @@ export const NumberInput = forwardRef<HTMLInputElement, NumberInputProps>(
|
|||
suffix,
|
||||
prefix,
|
||||
value: controlledValue,
|
||||
className,
|
||||
height = "h-9",
|
||||
...props
|
||||
},
|
||||
externalRef,
|
||||
|
|
@ -117,10 +121,14 @@ export const NumberInput = forwardRef<HTMLInputElement, NumberInputProps>(
|
|||
};
|
||||
|
||||
return (
|
||||
<div className="flex items-center">
|
||||
<div className={cn("flex items-stretch", height)}>
|
||||
<NumericFormat
|
||||
allowNegative={min < 0}
|
||||
className="relative rounded-r-none [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none"
|
||||
className={cn(
|
||||
"relative rounded-r-none [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none",
|
||||
height,
|
||||
className,
|
||||
)}
|
||||
customInput={Input}
|
||||
decimalScale={decimalScale}
|
||||
fixedDecimalScale={fixedDecimalScale}
|
||||
|
|
@ -138,10 +146,10 @@ export const NumberInput = forwardRef<HTMLInputElement, NumberInputProps>(
|
|||
{...props}
|
||||
/>
|
||||
|
||||
<div className="flex flex-col">
|
||||
<div className="flex flex-col self-stretch">
|
||||
<Button
|
||||
aria-label="Increase value"
|
||||
className="h-5 rounded-l-none rounded-br-none border-input border-b-[0.5px] border-l-0 px-2 focus-visible:relative"
|
||||
className="h-1/2 rounded-l-none rounded-br-none border-input border-b-[0.5px] border-l-0 px-2 focus-visible:relative"
|
||||
disabled={value === max}
|
||||
onClick={handleIncrement}
|
||||
variant="outline"
|
||||
|
|
@ -150,7 +158,7 @@ export const NumberInput = forwardRef<HTMLInputElement, NumberInputProps>(
|
|||
</Button>
|
||||
<Button
|
||||
aria-label="Decrease value"
|
||||
className="h-5 rounded-l-none rounded-tr-none border-input border-t-[0.5px] border-l-0 px-2 focus-visible:relative"
|
||||
className="h-1/2 rounded-l-none rounded-tr-none border-input border-t-[0.5px] border-l-0 px-2 focus-visible:relative"
|
||||
disabled={value === min}
|
||||
onClick={handleDecrement}
|
||||
variant="outline"
|
||||
|
|
|
|||
|
|
@ -54,6 +54,8 @@ export const ConfermaAnnuncioModal = () => {
|
|||
const { t } = useTranslation();
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
//TODO need to show messaggio in alert dialog after invio conferma about adeguamento saldo e permanenza based on doc presented
|
||||
|
||||
const needsDocuments =
|
||||
!servizio.skipDocMotivazione &&
|
||||
!servizio.doc_motivazione &&
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ export const HeroSvg = (props: SVGProps<SVGSVGElement>) => (
|
|||
height={500}
|
||||
width={500}
|
||||
>
|
||||
<title>hero</title>
|
||||
<title>Infoalloggi.it</title>
|
||||
<path
|
||||
d="m240.441 54.013-137.11 137.098V362.3h285.188V202.08L240.441 54.013Z"
|
||||
fill="#EAEAEA"
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ export const AnnuncioEditForm = ({ data }: { data: AnnunciWithImages }) => {
|
|||
className="mt-3 grid flex-1 items-start gap-4 p-2 sm:px-4 sm:py-0 md:gap-8"
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
>
|
||||
<div className="mx-auto grid w-full max-w-7xl flex-1 auto-rows-max gap-4">
|
||||
<div className="mx-auto grid w-full flex-1 auto-rows-max gap-4">
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<h1 className="whitespace-nowrap font-semibold text-2xl tracking-tight">
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
import { keepPreviousData } from "@tanstack/react-query";
|
||||
import {
|
||||
ChevronDown,
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
ChevronsLeft,
|
||||
ChevronUp,
|
||||
Filter,
|
||||
FilterX,
|
||||
|
|
@ -17,7 +14,7 @@ import { useCallback, useEffect, useMemo, useState } from "react";
|
|||
import { AccordionComp } from "~/components/accordionComp";
|
||||
import { MapSection } from "~/components/annunci_map";
|
||||
import { CTA_TipologiaModal } from "~/components/annunci_tutorial";
|
||||
import { CardAnnuncio } from "~/components/annuncio_card";
|
||||
import { LazyCardAnnuncio } from "~/components/annuncio_card";
|
||||
import { CodiceBox } from "~/components/codiceRicerca";
|
||||
import { Layout } from "~/components/Layout";
|
||||
import { LoadingPage } from "~/components/loading";
|
||||
|
|
@ -62,7 +59,7 @@ const Annunci = ({ options }: AnnunciPageProps) => {
|
|||
<meta content={t.heads.annunci_description} name="description" />
|
||||
</Head>
|
||||
|
||||
<main className="relative mx-auto w-full max-w-7xl space-y-5 bg-background2 px-2 py-5 md:px-8">
|
||||
<main className="relative mx-auto w-full max-w-9xl space-y-5 bg-background2 px-2 py-5 md:px-8">
|
||||
<div className="inline-block rounded-md bg-accent px-3 py-1 text-primary text-sm outline outline-neutral-500">
|
||||
{t.annunci.titolo}
|
||||
</div>
|
||||
|
|
@ -125,9 +122,9 @@ const Ricerca = () => {
|
|||
}, [page]);
|
||||
|
||||
return (
|
||||
<div className="mx-auto w-full max-w-7xl space-y-5 xl:w-[100rem]">
|
||||
<div className="mx-auto w-full space-y-5">
|
||||
<RicercaHeader />
|
||||
<div className="flex w-full gap-2">
|
||||
<div className="relative flex w-full gap-4">
|
||||
<RicercaSideFilters />
|
||||
<div className="flex-1">{map ? <MapSection /> : <AnnunciList />}</div>
|
||||
</div>
|
||||
|
|
@ -135,7 +132,7 @@ const Ricerca = () => {
|
|||
);
|
||||
};
|
||||
|
||||
const RicercaSideFilters = () => {
|
||||
const Filters = () => {
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
tipo,
|
||||
|
|
@ -157,9 +154,8 @@ const RicercaSideFilters = () => {
|
|||
() => consegnaOptions.map((m) => t.preferenze.mesi[m]!).filter(Boolean),
|
||||
[consegnaOptions, t.preferenze.mesi],
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="hidden h-fit w-46 flex-col gap-3 rounded-md bg-white p-2 outline-neutral-300 xl:flex">
|
||||
<>
|
||||
<SelectFilter
|
||||
defaultValue={""}
|
||||
handleReset={async () => {
|
||||
|
|
@ -229,35 +225,23 @@ const RicercaSideFilters = () => {
|
|||
>
|
||||
<FilterX className="size-5" /> {t.annunci.filtri_reset}
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const RicercaSideFilters = () => {
|
||||
return (
|
||||
<div className="hidden h-fit w-46 max-w-46 shrink-0 grow-0 flex-col gap-3 overflow-clip rounded-md bg-white p-2 outline-neutral-300 2xl:flex">
|
||||
<Filters />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const DrowdownFilters = () => {
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
tipo,
|
||||
setTipo,
|
||||
comune,
|
||||
setComune,
|
||||
consegna,
|
||||
setConsegna,
|
||||
sort,
|
||||
setSort,
|
||||
comuniOptions,
|
||||
tipologieOptions,
|
||||
consegnaOptions,
|
||||
ResetParams,
|
||||
nFiltri,
|
||||
} = useRicerca();
|
||||
const { nFiltri } = useRicerca();
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const mappedConsegnaOptions = useMemo(
|
||||
// biome-ignore lint/style/noNonNullAssertion: <known lenght>
|
||||
() => consegnaOptions.map((m) => t.preferenze.mesi[m]!).filter(Boolean),
|
||||
[consegnaOptions, t.preferenze.mesi],
|
||||
);
|
||||
|
||||
// Close dropdown when page resizes
|
||||
const handleResize = useCallback(() => {
|
||||
setOpen(false);
|
||||
|
|
@ -271,7 +255,7 @@ const DrowdownFilters = () => {
|
|||
}, [handleResize]);
|
||||
|
||||
return (
|
||||
<div className="flex w-full sm:w-auto xl:hidden">
|
||||
<div className="flex w-full sm:w-auto 2xl:hidden">
|
||||
<DropdownMenu onOpenChange={setOpen} open={open}>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
|
|
@ -290,75 +274,7 @@ const DrowdownFilters = () => {
|
|||
align="start"
|
||||
className="flex w-60 max-w-3xl flex-col gap-2 p-4"
|
||||
>
|
||||
<SelectFilter
|
||||
defaultValue={""}
|
||||
handleReset={async () => {
|
||||
await setTipo("");
|
||||
}}
|
||||
label={t.annunci.fs_tipologia.titolo}
|
||||
onValueChange={async (value: string) => {
|
||||
await setTipo(value);
|
||||
}}
|
||||
options={tipologieOptions}
|
||||
placeholder={t.seleziona_placeholder}
|
||||
value={tipo}
|
||||
/>
|
||||
<SelectFilter
|
||||
defaultValue={""}
|
||||
handleReset={async () => {
|
||||
await setComune(null);
|
||||
}}
|
||||
label={t.annunci.comune}
|
||||
onValueChange={async (value: string) => {
|
||||
await setComune(value);
|
||||
}}
|
||||
options={comuniOptions}
|
||||
placeholder={t.seleziona_placeholder}
|
||||
value={comune}
|
||||
/>
|
||||
<SelectFilter
|
||||
defaultValue={""}
|
||||
handleReset={async () => {
|
||||
await setConsegna(null);
|
||||
}}
|
||||
label={t.annunci.consegna}
|
||||
onValueChange={async (value: string) => {
|
||||
if (value === "") {
|
||||
await setConsegna(null);
|
||||
return;
|
||||
}
|
||||
if (t.preferenze.mesi.includes(value)) {
|
||||
await setConsegna(t.preferenze.mesi.indexOf(value));
|
||||
return;
|
||||
}
|
||||
console.warn("Value not found in preferenze.mesi");
|
||||
await setConsegna(null);
|
||||
}}
|
||||
options={mappedConsegnaOptions}
|
||||
placeholder={t.seleziona_placeholder}
|
||||
value={consegna ? t.preferenze.mesi[consegna] || "" : ""}
|
||||
/>
|
||||
<SelectFilter
|
||||
defaultValue={sort}
|
||||
handleReset={async () => {
|
||||
await setSort("Recenti");
|
||||
}}
|
||||
label={t.ordina_per}
|
||||
onValueChange={async (value: SortTypes) => {
|
||||
await setSort(value);
|
||||
}}
|
||||
options={["Recenti", "Prezzo", "Consegna", "Mq"]}
|
||||
placeholder={t.seleziona_placeholder}
|
||||
value={sort}
|
||||
/>
|
||||
<Button
|
||||
className="flex flex-row gap-2"
|
||||
disabled={nFiltri === 0}
|
||||
onClick={ResetParams}
|
||||
variant="destructive"
|
||||
>
|
||||
<FilterX className="size-5" /> {t.annunci.filtri_reset}
|
||||
</Button>
|
||||
<Filters />
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
|
|
@ -369,7 +285,7 @@ const RicercaHeader = () => {
|
|||
const { map, setMap } = useRicerca();
|
||||
|
||||
return (
|
||||
<div className="mx-auto w-full max-w-7xl space-y-5">
|
||||
<div className="mx-auto w-full max-w-9xl space-y-5">
|
||||
<div className="flex w-full flex-col-reverse gap-4 sm:flex-row sm:gap-2">
|
||||
<div className="flex w-full gap-2 sm:w-auto">
|
||||
<DrowdownFilters />
|
||||
|
|
@ -417,26 +333,33 @@ const AnnunciList = () => {
|
|||
sort,
|
||||
map,
|
||||
page,
|
||||
setPage,
|
||||
isLoading: ricercaLoading,
|
||||
annunciNumber,
|
||||
} = useRicerca();
|
||||
|
||||
const { data, status, isPlaceholderData } =
|
||||
api.annunci.getWithCursor.useQuery(
|
||||
{
|
||||
comune: comune || undefined,
|
||||
consegna: consegna || undefined,
|
||||
page,
|
||||
pageSize: 6,
|
||||
sort: sort || undefined,
|
||||
tipologia: tipo || undefined,
|
||||
},
|
||||
{
|
||||
enabled: !map,
|
||||
placeholderData: keepPreviousData,
|
||||
staleTime: 5000,
|
||||
},
|
||||
);
|
||||
const {
|
||||
data,
|
||||
status,
|
||||
//isPlaceholderData
|
||||
} = api.annunci.getWithCursor.useQuery(
|
||||
{
|
||||
comune: comune || undefined,
|
||||
consegna: consegna || undefined,
|
||||
page,
|
||||
pageSize: annunciNumber,
|
||||
sort: sort || undefined,
|
||||
tipologia: tipo || undefined,
|
||||
},
|
||||
{
|
||||
enabled: !map,
|
||||
placeholderData: keepPreviousData,
|
||||
staleTime: 5000,
|
||||
},
|
||||
);
|
||||
|
||||
/*
|
||||
DISABILITATO FUNZIONALITA PAGING E PAGE SIZE
|
||||
|
||||
const utils = api.useUtils();
|
||||
useEffect(() => {
|
||||
const prefetchData = async () => {
|
||||
|
|
@ -445,7 +368,7 @@ const AnnunciList = () => {
|
|||
comune: comune || undefined,
|
||||
consegna: consegna || undefined,
|
||||
page: page + 1,
|
||||
pageSize: 6,
|
||||
pageSize: annunciNumber,
|
||||
sort: sort || undefined,
|
||||
tipologia: tipo || undefined,
|
||||
});
|
||||
|
|
@ -454,7 +377,7 @@ const AnnunciList = () => {
|
|||
prefetchData().catch((err) => {
|
||||
console.error("Error prefetching next page:", err);
|
||||
});
|
||||
}, [data, isPlaceholderData, page]);
|
||||
}, [data, isPlaceholderData, page, annunciNumber]);
|
||||
|
||||
useEffect(() => {
|
||||
// Reset to page 0 if current page has no data or less than page size
|
||||
|
|
@ -463,16 +386,29 @@ const AnnunciList = () => {
|
|||
if (data.annunci.length === 0 && page !== 0) {
|
||||
await setPage(0);
|
||||
}
|
||||
if (data.annunci.length < 6 || !data.hasMore) {
|
||||
await setPage(0);
|
||||
}
|
||||
}
|
||||
};
|
||||
checkPage().catch((err) => {
|
||||
console.error("Error checking data for page reset:", err);
|
||||
});
|
||||
}, [data, tipo, comune, consegna, sort, setPage]);
|
||||
}, [data, tipo, comune, consegna, sort, setPage, annunciNumber]);
|
||||
|
||||
const [debouncedAnnunciNumber, setDebouncedAnnunciNumber] =
|
||||
useState(annunciNumber);
|
||||
|
||||
useDebounce(
|
||||
async () => {
|
||||
console.log("Setting annunciNumber to", debouncedAnnunciNumber);
|
||||
console.log("Current annunciNumber is", annunciNumber);
|
||||
if (debouncedAnnunciNumber !== annunciNumber) {
|
||||
await setAnnunciNumber(debouncedAnnunciNumber);
|
||||
await setPage(0);
|
||||
}
|
||||
},
|
||||
500,
|
||||
[debouncedAnnunciNumber],
|
||||
);
|
||||
*/
|
||||
if (ricercaLoading) return <LoadingPage />;
|
||||
if (status === "error") return <Status500 />;
|
||||
|
||||
|
|
@ -481,14 +417,34 @@ const AnnunciList = () => {
|
|||
{status === "pending" ? (
|
||||
<LoadingPage />
|
||||
) : (
|
||||
<div className="relative z-0 mx-auto grid max-w-7xl grid-flow-row grid-cols-1 gap-4 sm:grid-cols-2 sm:gap-6 lg:grid-cols-3">
|
||||
{data.annunci.map((annuncio) => (
|
||||
<CardAnnuncio key={annuncio.codice} {...annuncio} />
|
||||
<div className="relative z-0 mx-auto grid max-w-8xl grid-flow-row grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 2xl:w-7xl 2xl:grid-cols-4">
|
||||
{data.annunci.map((annuncio, idx) => (
|
||||
<LazyCardAnnuncio
|
||||
key={annuncio.codice}
|
||||
{...annuncio}
|
||||
eager={idx <= 9}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex items-center justify-center gap-2">
|
||||
{/* <div className="relative flex items-center justify-center gap-2">
|
||||
<div className="absolute left-0 flex items-center gap-2">
|
||||
<span className="text-muted-foreground text-sm">
|
||||
annunci per pagina:
|
||||
</span>
|
||||
<NumberInput
|
||||
allowNegative={false}
|
||||
className="w-16 bg-white"
|
||||
min={0}
|
||||
onValueChange={(val) => {
|
||||
if (val !== undefined) {
|
||||
setDebouncedAnnunciNumber(val);
|
||||
}
|
||||
}}
|
||||
value={debouncedAnnunciNumber}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex w-24 items-center justify-end gap-2">
|
||||
{page >= 2 && (
|
||||
<Button
|
||||
|
|
@ -515,11 +471,9 @@ const AnnunciList = () => {
|
|||
<ChevronLeft className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="mx-4 w-12 rounded-md bg-white py-2 text-center font-medium text-lg">
|
||||
{page + 1}
|
||||
</div>
|
||||
|
||||
<div className="flex w-24 items-center justify-start gap-2">
|
||||
<Button
|
||||
aria-label="Next page"
|
||||
|
|
@ -535,7 +489,7 @@ const AnnunciList = () => {
|
|||
<ChevronRight className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -571,7 +525,11 @@ export const SelectFilter = <T extends string>({
|
|||
{label}
|
||||
</Label>
|
||||
{value !== defaultValue && (
|
||||
<button onClick={handleReset} type="button">
|
||||
<button
|
||||
className="cursor-pointer"
|
||||
onClick={handleReset}
|
||||
type="button"
|
||||
>
|
||||
<RotateCcwIcon className="size-4" />
|
||||
</button>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ const OnboardUser: NextPageWithLayout<OnboardUserProps> = ({
|
|||
return <Status500 />;
|
||||
}
|
||||
return (
|
||||
<div className="mx-auto max-w-7xl grow space-y-4">
|
||||
<div className="mx-auto max-w-8xl grow space-y-4">
|
||||
<div className="flex justify-between">
|
||||
<h3 className="font-bold text-2xl text-primary">
|
||||
Onboarding Utente (Versione Admin)
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ const ServizioUser: NextPageWithLayout<ServizioUserProps> = ({
|
|||
const [open, setOpen] = useState(false);
|
||||
const [editData, setEditData] = useState<Servizio | undefined>(undefined);
|
||||
return (
|
||||
<div className="mx-auto max-w-7xl grow space-y-4">
|
||||
<div className="mx-auto max-w-8xl grow space-y-4">
|
||||
<div className="flex justify-between">
|
||||
<h3 className="font-bold text-2xl">Servizi Utente</h3>
|
||||
<NewServizioModal
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ const Comunicazioni: NextPageWithLayout = () => {
|
|||
<meta content={t.heads.area_riservata_description} name="description" />
|
||||
</Head>
|
||||
|
||||
<div className="mx-auto max-w-7xl grow p-4">
|
||||
<div className="mx-auto max-w-8xl grow p-4">
|
||||
<div className="p-1">
|
||||
<h1 className="font-bold text-2xl text-primary">Comunicazioni</h1>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ const ChiSiamo: NextPage = () => {
|
|||
<title>{t.heads.chi_siamo_titolo}</title>
|
||||
<meta content={t.heads.main_description} name="description" />
|
||||
</Head>
|
||||
<main className="mx-auto w-full max-w-7xl space-y-5 px-2 py-5 md:px-8">
|
||||
<main className="mx-auto w-full max-w-8xl space-y-5 px-2 py-5 md:px-8">
|
||||
<div className="inline-block rounded-md bg-accent px-3 py-1 text-primary text-sm outline outline-neutral-500">
|
||||
{t.chi_siamo.title}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ const Contatto: NextPage = () => {
|
|||
<title>{t.heads.contatti_titolo}</title>
|
||||
<meta content={t.heads.main_description} name="description" />
|
||||
</Head>
|
||||
<main className="mx-auto w-full max-w-7xl px-2 py-5 md:px-8">
|
||||
<main className="mx-auto w-full max-w-8xl px-2 py-5 md:px-8">
|
||||
<div className="inline-block rounded-md bg-accent px-3 py-1 text-primary text-sm outline outline-neutral-500">
|
||||
{t.contatti}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ const Guida: NextPage = () => {
|
|||
<title>{t.heads.guida_titolo}</title>
|
||||
<meta content={t.heads.main_description} name="description" />
|
||||
</Head>
|
||||
<main className="mx-auto w-full max-w-7xl px-2 py-5 md:px-8">
|
||||
<main className="mx-auto w-full max-w-8xl px-2 py-5 md:px-8">
|
||||
<div className="inline-block rounded-md bg-accent px-3 py-1 text-primary text-sm outline outline-neutral-500">
|
||||
{t.guida}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ const Home: NextPage = () => {
|
|||
<meta content="Infoalloggi.it" property="og:site_name" />
|
||||
</Head>
|
||||
<div className="mx-5 mt-0 mb-12 sm:mt-[2rem]">
|
||||
<main className="mx-auto mb-4 max-w-7xl space-y-5 lg:mb-20">
|
||||
<main className="mx-auto mb-4 max-w-8xl space-y-5 lg:mb-20">
|
||||
<div className="flex flex-col items-center justify-center lg:flex-row lg:justify-around">
|
||||
<div className="-mt-2 xs:mt-5 flex h-[19rem] max-w-full items-center justify-center min-[22rem]:h-[23rem] min-[25rem]:h-[26rem]">
|
||||
<div className="flex scale-50 items-center justify-center drop-shadow-xl sm:scale-100 md:max-h-96 min-[20rem]:scale-[0.6] min-[22rem]:scale-[0.7] min-[25rem]:scale-[0.8]">
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ const Prezzi: NextPage = () => {
|
|||
<title>{t.heads.prezzi_titolo}</title>
|
||||
<meta content={t.heads.prezzi_description} name="description" />
|
||||
</Head>
|
||||
<section className="mx-auto max-w-7xl px-2 py-5 md:px-8">
|
||||
<section className="mx-auto max-w-8xl px-2 py-5 md:px-8">
|
||||
<div className="inline-block rounded-md bg-accent px-3 py-1 text-primary text-sm outline outline-neutral-500">
|
||||
{t.prezzi_titolo}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ const Proprietari: NextPage = () => {
|
|||
<title>{t.proprietari.head}</title>
|
||||
<meta content={t.proprietari.description} name="description" />
|
||||
</Head>
|
||||
<main className="mx-auto w-full max-w-7xl space-y-5 px-2 py-5 md:px-8">
|
||||
<main className="mx-auto w-full max-w-8xl space-y-5 px-2 py-5 md:px-8">
|
||||
<div className="inline-block rounded-md bg-accent px-3 py-1 text-primary text-sm outline outline-neutral-500">
|
||||
{t.proprietari.titolo}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -46,6 +46,10 @@ type RicercaContextType = {
|
|||
value: number | ((old: number | null) => number | null) | null,
|
||||
) => Promise<URLSearchParams>;
|
||||
ResetParams: () => Promise<void>;
|
||||
annunciNumber: number;
|
||||
setAnnunciNumber: (
|
||||
value: number | ((old: number) => number | null) | null,
|
||||
) => Promise<URLSearchParams>;
|
||||
nFiltri: number;
|
||||
isLoading: boolean;
|
||||
};
|
||||
|
|
@ -104,6 +108,10 @@ export const RicercaProvider: FC<{
|
|||
"p",
|
||||
parseAsInteger.withDefault(0).withOptions({ clearOnDefault: true }),
|
||||
);
|
||||
const [annunciNumber, setAnnunciNumber] = useQueryState(
|
||||
"n",
|
||||
parseAsInteger.withDefault(1000).withOptions({ startTransition }),
|
||||
);
|
||||
|
||||
const tipologieOptions = useMemo(() => {
|
||||
const set = new Set<string>();
|
||||
|
|
@ -153,7 +161,7 @@ export const RicercaProvider: FC<{
|
|||
await setComune("");
|
||||
await setConsegna(null);
|
||||
await setSort("Recenti");
|
||||
await setPage(0);
|
||||
//await setPage(0);
|
||||
};
|
||||
|
||||
const nFiltri =
|
||||
|
|
@ -187,6 +195,9 @@ export const RicercaProvider: FC<{
|
|||
sortOptions: sortOptions,
|
||||
tipo,
|
||||
tipologieOptions,
|
||||
|
||||
annunciNumber,
|
||||
setAnnunciNumber,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
|
|
|||
|
|
@ -366,6 +366,7 @@ export const getCursor_AnnunciHandler = async ({
|
|||
.limit(pageSize + 1)
|
||||
.offset(page * pageSize)
|
||||
.execute();
|
||||
|
||||
const hasMore = annunci.length > pageSize;
|
||||
if (annunci.length > pageSize) {
|
||||
annunci.pop(); // Remove the last item if it exceeds the page size
|
||||
|
|
|
|||
|
|
@ -36,7 +36,9 @@
|
|||
--breakpoint-3xl: 120rem;
|
||||
--breakpoint-4xl: 160rem;
|
||||
--breakpoint-5xl: 192rem;
|
||||
|
||||
--container-8xl: 88rem;
|
||||
--container-9xl: 96rem;
|
||||
--container-10xl: 104rem;
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-lg: var(--radius);
|
||||
|
|
@ -160,7 +162,7 @@
|
|||
:root {
|
||||
--radius: 0.625rem;
|
||||
--background: oklch(1 0 0);
|
||||
--background2: oklch(95.041% 0.02791 62.217);
|
||||
--background2: oklch(80.395% 0.06402 83.429);
|
||||
--foreground: oklch(0.145 0 0);
|
||||
--card: oklch(1 0 0);
|
||||
--card-foreground: oklch(0.145 0 0);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue