feat: implement AnnuncioDisplay component and integrate it into ServizioContent for better display of selected announcements
This commit is contained in:
parent
6c4c57fd69
commit
76bcf640ca
4 changed files with 106 additions and 187 deletions
|
|
@ -35,6 +35,70 @@ export const AnnuncioCard = ({
|
|||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const AnnuncioDisplay = ({
|
||||
data,
|
||||
confirming,
|
||||
}: {
|
||||
data: AnnuncioRicerca;
|
||||
confirming?: boolean;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<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",
|
||||
)}
|
||||
>
|
||||
<div className="row-span-1 md:row-span-3">
|
||||
<Image
|
||||
alt={data.codice}
|
||||
className="size-24 rounded-md bg-[#e6e9ec] object-cover md:size-48"
|
||||
height={1080}
|
||||
priority
|
||||
src={
|
||||
(data?.images[0] &&
|
||||
getStorageUrl({
|
||||
storageId: data.images[0].img,
|
||||
params: {
|
||||
cacheKey: data.media_updated_at?.toISOString(),
|
||||
media: "image",
|
||||
},
|
||||
})) ||
|
||||
"/fallback-image.png"
|
||||
}
|
||||
width={1920}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="col-span-1 flex w-full max-w-xl flex-wrap gap-5 md:col-span-1 md:mt-4 md:pr-8">
|
||||
<span className="text-wrap">{data.titolo_it}</span>
|
||||
</div>
|
||||
|
||||
<div className="col-span-2 flex w-full max-w-xl items-center justify-between gap-2 md:col-span-1 md:pr-8">
|
||||
<TipoBadge mini tipo={data.tipo} />
|
||||
<span className="max-w-auto truncate">
|
||||
{handleConsegna({
|
||||
aggiornamento: t.card.in_aggiornamento,
|
||||
consegna: data.consegna,
|
||||
consegna_da: t.card.consegna_da,
|
||||
mesi: t.parametri.mesi,
|
||||
subito: t.card.consegna_subito,
|
||||
})}
|
||||
</span>
|
||||
<span className="font-semibold">
|
||||
{formatCurrency(data.prezzo / 1e2)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="col-span-2 w-full max-w-xl md:col-span-1 md:pr-8">
|
||||
<AnnuncioDettaglio data={data} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const BasicAnnuncioCard = ({
|
||||
actions,
|
||||
interactions,
|
||||
|
|
@ -48,8 +112,6 @@ export const BasicAnnuncioCard = ({
|
|||
data: AnnuncioRicerca;
|
||||
confirming?: boolean;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
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">
|
||||
|
|
@ -64,56 +126,7 @@ export const BasicAnnuncioCard = ({
|
|||
)}
|
||||
id="container"
|
||||
>
|
||||
<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-6 xl:gap-x-8 dark:md:border-primary dark:md:bg-card",
|
||||
confirming && "xl:w-1/2",
|
||||
)}
|
||||
>
|
||||
<div className="row-span-1 md:row-span-3">
|
||||
<Image
|
||||
alt={data.codice}
|
||||
className="size-24 rounded-md bg-[#e6e9ec] object-cover md:size-48"
|
||||
height={1080}
|
||||
priority
|
||||
src={
|
||||
(data?.images[0] &&
|
||||
getStorageUrl({
|
||||
storageId: data.images[0].img,
|
||||
params: {
|
||||
cacheKey: data.media_updated_at?.toISOString(),
|
||||
media: "image",
|
||||
},
|
||||
})) ||
|
||||
"/fallback-image.png"
|
||||
}
|
||||
width={1920}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="col-span-1 flex w-full max-w-xl flex-wrap gap-5 md:col-span-1 md:mt-4 md:pr-8">
|
||||
<span className="text-wrap">{data.titolo_it}</span>
|
||||
</div>
|
||||
|
||||
<div className="col-span-2 flex w-full max-w-xl items-center justify-between gap-2 md:col-span-1 md:pr-8">
|
||||
<TipoBadge mini tipo={data.tipo} />
|
||||
<span className="max-w-auto truncate">
|
||||
{handleConsegna({
|
||||
aggiornamento: t.card.in_aggiornamento,
|
||||
consegna: data.consegna,
|
||||
consegna_da: t.card.consegna_da,
|
||||
mesi: t.parametri.mesi,
|
||||
subito: t.card.consegna_subito,
|
||||
})}
|
||||
</span>
|
||||
<span className="font-semibold">
|
||||
{formatCurrency(data.prezzo / 1e2)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="col-span-2 w-full max-w-xl md:col-span-1 md:pr-8">
|
||||
<AnnuncioDettaglio data={data} />
|
||||
</div>
|
||||
</div>
|
||||
<AnnuncioDisplay confirming={confirming} data={data} />
|
||||
<div
|
||||
className={cn(
|
||||
"flex w-full flex-col gap-4",
|
||||
|
|
@ -127,19 +140,3 @@ export const BasicAnnuncioCard = ({
|
|||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export const AnnuncioCardSkeleton = () => {
|
||||
return (
|
||||
<Card className="hidden w-full gap-2 rounded-md border-border py-3 opacity-30 lg:flex">
|
||||
<CardHeader className="flex flex-row flex-wrap items-center justify-between space-y-0 px-3 pb-2">
|
||||
<CardTitle className="h-8 w-64 rounded-md bg-muted" />
|
||||
</CardHeader>
|
||||
<CardContent className="h-max px-3">
|
||||
<div className="flex w-full flex-col gap-4">
|
||||
<div className="h-[194px] w-full rounded-md bg-muted" />
|
||||
<div className="h-8 w-48 rounded-md bg-muted" />
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { useEffect } from "react";
|
|||
import toast from "react-hot-toast";
|
||||
import {
|
||||
AnnuncioCard,
|
||||
AnnuncioCardSkeleton,
|
||||
AnnuncioDisplay,
|
||||
} from "~/components/servizio/annuncio_card";
|
||||
import { SaldoButton } from "~/components/servizio/interactions";
|
||||
import { ServizioActions } from "~/components/servizio/servizio_actions";
|
||||
|
|
@ -26,7 +26,6 @@ import {
|
|||
import { api } from "~/utils/api";
|
||||
import { AlarmClockSVG } from "../svgs";
|
||||
import { AnnunciCompatibili } from "./compatibili_dialog";
|
||||
import { AnnunciSelezionatiDialog } from "./servizio_annunci_accordions";
|
||||
|
||||
const ServizioCard = ({
|
||||
cardClassName,
|
||||
|
|
@ -163,7 +162,34 @@ export const ServizioContent = () => {
|
|||
)}
|
||||
</div>
|
||||
|
||||
{isAdmin && <AnnunciSelezionatiDialog annunci={servizio.annunci} />}
|
||||
{servizio.annunci.length > 0 && (
|
||||
<div className="w-full space-y-2">
|
||||
<p>
|
||||
Sono già stati selezionati {servizio.annunci.length} annunci
|
||||
che potrebbero interessarti.
|
||||
</p>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
{servizio.annunci.map((data) => (
|
||||
<div className="" key={data.id}>
|
||||
<AnnuncioDisplay
|
||||
data={{
|
||||
...data,
|
||||
modificato_il: data.modificato_il
|
||||
? new Date(data.modificato_il)
|
||||
: null,
|
||||
media_updated_at: data.media_updated_at
|
||||
? new Date(data.media_updated_at)
|
||||
: null,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
{servizio.annunci.length % 2 === 1 && (
|
||||
<div className="size-full rounded-md border border-[var(--pattern-fg)] bg-[repeating-linear-gradient(45deg,_var(--pattern-fg)_0,_var(--pattern-fg)_1px,_transparent_0,_transparent_50%)] bg-[size:10px_10px] bg-fixed opacity-10 [--pattern-fg:#696969] dark:[--pattern-fg:#e1e1e1]" />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
contentClassName={cn(!isAdmin && "gap-0")}
|
||||
|
|
@ -297,7 +323,9 @@ export const ServizioContent = () => {
|
|||
</ServizioAnnuncioProvider>
|
||||
);
|
||||
})}
|
||||
{servizio.annunci.length % 2 === 1 && <AnnuncioCardSkeleton />}
|
||||
{servizio.annunci.length % 2 === 1 && (
|
||||
<div className="size-full rounded-md border border-[var(--pattern-fg)] bg-[repeating-linear-gradient(45deg,_var(--pattern-fg)_0,_var(--pattern-fg)_1px,_transparent_0,_transparent_50%)] bg-[size:10px_10px] bg-fixed opacity-10 [--pattern-fg:#696969] dark:[--pattern-fg:#e1e1e1]" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-center">
|
||||
|
|
|
|||
|
|
@ -1,11 +1,6 @@
|
|||
import { ExternalLink, Trash2 } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import type { ReactNode } from "react";
|
||||
import { Trash2 } from "lucide-react";
|
||||
import toast from "react-hot-toast";
|
||||
import {
|
||||
AnnuncioCard,
|
||||
BasicAnnuncioCard,
|
||||
} from "~/components/servizio/annuncio_card";
|
||||
import { BasicAnnuncioCard } from "~/components/servizio/annuncio_card";
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
|
|
@ -13,105 +8,8 @@ import {
|
|||
AccordionTrigger,
|
||||
} from "~/components/ui/accordion";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import {
|
||||
ServizioAnnuncioProvider,
|
||||
useServizio,
|
||||
} from "~/providers/ServizioProvider";
|
||||
import type { UsersId } from "~/schemas/public/Users";
|
||||
import type { ServizioData } from "~/server/controllers/servizio.controller";
|
||||
import { api } from "~/utils/api";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "../ui/dialog";
|
||||
|
||||
const DialogServizio = ({
|
||||
trigger,
|
||||
title,
|
||||
children,
|
||||
}: {
|
||||
trigger: ReactNode;
|
||||
title: string;
|
||||
children: ReactNode;
|
||||
}) => {
|
||||
return (
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>{trigger}</DialogTrigger>
|
||||
<DialogContent className="max-w-xl p-2 sm:max-w-5xl sm:p-6 md:max-w-7xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{title}</DialogTitle>
|
||||
<DialogDescription className="sr-only">
|
||||
Servizio Dialog
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
{children}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export const AnnunciSelezionatiDialog = ({
|
||||
annunci,
|
||||
}: {
|
||||
annunci: ServizioData["annunci"];
|
||||
}) => {
|
||||
const { servizioId, userId } = useServizio();
|
||||
return (
|
||||
<DialogServizio
|
||||
title="Annunci selezionati"
|
||||
trigger={
|
||||
<div className="relative flex w-full sm:w-fit">
|
||||
<Button
|
||||
className="w-full text-lg sm:w-fit"
|
||||
size="xl"
|
||||
variant="orange"
|
||||
>
|
||||
Annunci selezionati
|
||||
</Button>
|
||||
|
||||
<span className="-translate-y-1/2 absolute top-0 right-0 flex min-w-6 origin-center translate-x-1/2 items-center justify-center rounded-full bg-destructive px-1 text-white">
|
||||
{annunci.length || 0}
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div className="flex max-h-[80vh] flex-col gap-2 overflow-y-auto">
|
||||
{annunci.length > 0 ? (
|
||||
annunci.map((data) => {
|
||||
return (
|
||||
<ServizioAnnuncioProvider
|
||||
data={data}
|
||||
key={data.id}
|
||||
servizioId={servizioId}
|
||||
userId={userId}
|
||||
>
|
||||
<AnnuncioCard className="border-2 border-sky-500" />
|
||||
</ServizioAnnuncioProvider>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<div className="flex items-center justify-center gap-1 rounded-md bg-white p-4 sm:flex">
|
||||
<span>
|
||||
Nessun annuncio selezionato, fai una ricerca nella pagina{" "}
|
||||
<Link
|
||||
aria-label="Annunci Compatibili"
|
||||
className="inline-flex items-center gap-1 text-blue-500 underline"
|
||||
href="/annunci"
|
||||
>
|
||||
Annunci
|
||||
<ExternalLink className="size-4" />
|
||||
</Link>
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</DialogServizio>
|
||||
);
|
||||
};
|
||||
|
||||
export const AnnunciRichiesti = ({ userId }: { userId: UsersId }) => {
|
||||
const { data, isLoading } = api.intrests.getUserInterestsAnnunci.useQuery({
|
||||
|
|
|
|||
|
|
@ -14,17 +14,13 @@
|
|||
|
||||
@custom-variant search-cancel (&::-webkit-search-cancel-button);
|
||||
|
||||
@utility stripes-* {
|
||||
background-image: linear-gradient(45deg,
|
||||
--value([color]) 12.5%,
|
||||
transparent 12.5%,
|
||||
transparent 50%,
|
||||
--value([color]) 50%,
|
||||
--value([color]) 62.5%,
|
||||
transparent 62.5%,
|
||||
transparent 100%);
|
||||
background-size: 10.66px 10.66px;
|
||||
}
|
||||
/*
|
||||
STRIPED BACKGROUND EXAMPLE:
|
||||
<div className="border border-[var(--pattern-fg)]
|
||||
bg-[repeating-linear-gradient(45deg,_var(--pattern-fg)_0,_var(--pattern-fg)_1px,_transparent_0,_transparent_50%)]
|
||||
bg-[size:10px_10px] bg-fixed
|
||||
[--pattern-fg:#696969] dark:[--pattern-fg:#e1e1e1]" />
|
||||
*/
|
||||
|
||||
@theme inline {
|
||||
--font-sans: var(--font-inter);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue