refactor: enhance styling and layout of AnnuncioCard and AnnuncioDettaglio components
This commit is contained in:
parent
831ae0edef
commit
496a947f97
6 changed files with 116 additions and 139 deletions
|
|
@ -1,9 +1,6 @@
|
|||
import { ExternalLink } from "lucide-react";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { AnnuncioActions } from "~/components/servizio/annuncio_actions";
|
||||
import { Interactions } from "~/components/servizio/interactions";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card";
|
||||
import { handleConsegna } from "~/lib/annuncio_details";
|
||||
import { getStorageUrl } from "~/lib/storage_utils";
|
||||
|
|
@ -45,35 +42,40 @@ export const BasicAnnuncioCard = ({
|
|||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Card className={cn("w-full border-white py-5", className)}>
|
||||
<CardHeader className="flex flex-row flex-wrap items-center justify-between space-y-0 pb-0">
|
||||
<CardTitle className="text-2xl">Codice: {data.codice}</CardTitle>
|
||||
<Card className={cn("w-full border-white py-3", className)}>
|
||||
<CardHeader className="flex flex-row flex-wrap items-center justify-between space-y-0 px-3 pb-0">
|
||||
<CardTitle className="text-2xl">Annuncio {data.codice}</CardTitle>
|
||||
{actions}
|
||||
</CardHeader>
|
||||
<CardContent className="px-4">
|
||||
<div className="flex w-full flex-col gap-4 md:flex-row md:gap-10">
|
||||
<Image
|
||||
alt={data.codice}
|
||||
className="h-auto max-h-72 w-full rounded-md bg-[#e6e9ec] object-contain sm:max-w-xs"
|
||||
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 className="flex w-full flex-col gap-5">
|
||||
{interactions}
|
||||
<CardContent className="px-3">
|
||||
<div className="flex w-full flex-col gap-4 md:gap-10">
|
||||
<div className="grid grid-cols-[6rem_auto] gap-2 gap-x-4 md:grid-cols-[12rem_auto] md:gap-x-10">
|
||||
<div className="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="flex flex-wrap items-center gap-3">
|
||||
<div className="flex w-full max-w-xl flex-wrap gap-5 md:col-span-1">
|
||||
<span className="text-wrap">{data.titolo_it}</span>
|
||||
</div>
|
||||
|
||||
<div className="col-span-2 flex w-full max-w-xl flex-wrap items-center justify-between gap-3 md:col-span-1">
|
||||
<TipoBadge tipo={data.tipo} />
|
||||
<span>
|
||||
{handleConsegna({
|
||||
|
|
@ -84,25 +86,15 @@ export const BasicAnnuncioCard = ({
|
|||
subito: t.card.consegna_subito,
|
||||
})}
|
||||
</span>
|
||||
<span>{formatCurrency(data.prezzo / 1e2)}</span>
|
||||
<span className="font-semibold">
|
||||
{formatCurrency(data.prezzo / 1e2)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex w-full flex-wrap items-center gap-5">
|
||||
<span className="text-wrap">{data.titolo_it || data.codice}</span>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<AnnuncioDettaglio data={data} />
|
||||
{data.stato !== "Sospeso" && data.web && (
|
||||
<Link
|
||||
aria-label="Pagina Annuncio"
|
||||
href={`/annuncio/${data.codice}`}
|
||||
>
|
||||
<Button variant="outline">
|
||||
<ExternalLink className="size-6" />
|
||||
</Button>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
<div className="col-span-2 w-full max-w-xl md:col-span-1">
|
||||
<AnnuncioDettaglio data={data} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex w-full flex-col gap-5">{interactions}</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { ExternalLink, UnfoldVertical } from "lucide-react";
|
||||
import { Expand, ExternalLink } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { replaceWithBr } from "~/lib/newlineToBr";
|
||||
import { cn, formatCurrency } from "~/lib/utils";
|
||||
|
|
@ -6,16 +6,17 @@ import { useTranslation } from "~/providers/I18nProvider";
|
|||
import type { Annunci } from "~/schemas/public/Annunci";
|
||||
import type { AnnuncioRicerca } from "~/server/controllers/annunci.controller";
|
||||
import { CarouselAnnuncio } from "../annuncio_card";
|
||||
import {
|
||||
Credenza,
|
||||
CredenzaBody,
|
||||
CredenzaContent,
|
||||
CredenzaDescription,
|
||||
CredenzaHeader,
|
||||
CredenzaTitle,
|
||||
CredenzaTrigger,
|
||||
} from "../custom_ui/credenza";
|
||||
import { Badge } from "../ui/badge";
|
||||
import { Button } from "../ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "../ui/dialog";
|
||||
|
||||
export const TipoBadge = ({ tipo }: { tipo: Annunci["tipo"] }) => {
|
||||
return (
|
||||
|
|
@ -37,70 +38,78 @@ export const AnnuncioDettaglio = ({ data }: { data: AnnuncioRicerca }) => {
|
|||
const { locale, t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button aria-label="Dettagli Annuncio" variant="outline">
|
||||
<UnfoldVertical className="size-6" /> Dettagli annuncio
|
||||
<Credenza>
|
||||
<CredenzaTrigger asChild>
|
||||
<Button
|
||||
aria-label="Dettagli Annuncio"
|
||||
className="w-full"
|
||||
size="sm"
|
||||
variant="outline"
|
||||
>
|
||||
<Expand /> Dettaglio
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-h-[70vh] max-w-xl overflow-y-auto sm:max-w-6xl">
|
||||
<DialogHeader className="flex-row items-center gap-4">
|
||||
<DialogTitle className="text-xl">Annuncio {data.codice}</DialogTitle>
|
||||
</CredenzaTrigger>
|
||||
<CredenzaContent className="max-w-xl sm:max-w-6xl md:max-h-[90vh] md:overflow-y-auto">
|
||||
<CredenzaHeader className="flex-row items-center justify-between gap-4 md:justify-start">
|
||||
<CredenzaTitle className="text-xl">
|
||||
Annuncio {data.codice}
|
||||
</CredenzaTitle>
|
||||
<Link href={`/annuncio/${data.codice}`} target="_blank">
|
||||
<Button size="sm" variant="info">
|
||||
<span>Vai alla pagina completa</span>{" "}
|
||||
<ExternalLink className="size-4" />
|
||||
<span>Pagina completa</span> <ExternalLink />
|
||||
</Button>
|
||||
</Link>
|
||||
<DialogDescription className="sr-only">
|
||||
Annuncio {data.codice}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="flex flex-col gap-2 px-2">
|
||||
<div className="w-full contain-inline-size">
|
||||
<CarouselAnnuncio
|
||||
immagini={data.images}
|
||||
updated_at={data.media_updated_at}
|
||||
videos={data.videos}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="flex items-center gap-4">
|
||||
<TipoBadge tipo={data.tipo} />
|
||||
{data.stato === "Trattativa" && (
|
||||
<Badge className="bg-violet-500 font-semibold text-md">
|
||||
Annuncio in Trattativa
|
||||
</Badge>
|
||||
)}
|
||||
<CredenzaDescription className="sr-only">
|
||||
Dettaglio
|
||||
</CredenzaDescription>
|
||||
</CredenzaHeader>
|
||||
<CredenzaBody className="h-full overflow-auto pb-5">
|
||||
<div className="flex flex-col gap-2 px-2">
|
||||
<div className="w-full contain-inline-size">
|
||||
<CarouselAnnuncio
|
||||
immagini={data.images}
|
||||
updated_at={data.media_updated_at}
|
||||
videos={data.videos}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-1 space-y-2">
|
||||
<div className="flex flex-row justify-around">
|
||||
<div className="text-center">
|
||||
<dt className="sr-only">{t.card.codice}</dt>
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center gap-4">
|
||||
<TipoBadge tipo={data.tipo} />
|
||||
{data.stato === "Trattativa" && (
|
||||
<Badge className="bg-violet-500 font-semibold text-md">
|
||||
Annuncio in Trattativa
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<dd className="font-semibold text-lg">Cod: {data.codice}</dd>
|
||||
<div className="space-y-2">
|
||||
<div className="flex flex-row justify-around">
|
||||
<div className="text-center">
|
||||
<dt className="sr-only">{t.card.codice}</dt>
|
||||
|
||||
<dd className="font-semibold text-lg">
|
||||
Cod: {data.codice}
|
||||
</dd>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<dt className="sr-only">{t.card.prezzo}</dt>
|
||||
|
||||
<dd className="font-semibold text-lg">
|
||||
{formatCurrency(data.prezzo / 1e2)}
|
||||
</dd>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<dt className="sr-only">{t.card.prezzo}</dt>
|
||||
|
||||
<dd className="font-semibold text-lg">
|
||||
{formatCurrency(data.prezzo / 1e2)}
|
||||
<div className="">
|
||||
<dt className="sr-only">{t.card.titolo}</dt>
|
||||
|
||||
<dd className="font-semibold text-base md:text-lg">
|
||||
{locale === "it" ? data.titolo_it : data.titolo_en}
|
||||
</dd>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-3">
|
||||
<dt className="sr-only">{t.card.titolo}</dt>
|
||||
|
||||
<dd className="font-semibold text-base md:text-lg">
|
||||
{locale === "it" ? data.titolo_it : data.titolo_en}
|
||||
</dd>
|
||||
</div>
|
||||
|
||||
<div className="mb-3">
|
||||
<dd
|
||||
<div
|
||||
className="text-base"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: replaceWithBr(
|
||||
|
|
@ -111,8 +120,8 @@ export const AnnuncioDettaglio = ({ data }: { data: AnnuncioRicerca }) => {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</CredenzaBody>
|
||||
</CredenzaContent>
|
||||
</Credenza>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ export const Interactions = () => {
|
|||
const { data } = useServizioAnnuncio();
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-3">
|
||||
<div className="flex w-full flex-col gap-3">
|
||||
<ContattiProprietarioModal />
|
||||
|
||||
<SezioneConferma />
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ const ServizioCard = ({
|
|||
return (
|
||||
<Card
|
||||
className={cn(
|
||||
"gap-2 rounded-none rounded-b-md border-primary border-t-0",
|
||||
"gap-2 rounded-none rounded-b-md border-primary border-t-0 pb-0",
|
||||
cardClassName,
|
||||
)}
|
||||
>
|
||||
|
|
@ -218,32 +218,6 @@ export const ServizioContent = () => {
|
|||
<ServizioCard
|
||||
content={
|
||||
<>
|
||||
{/* <div className="flex w-full flex-col gap-8 sm:flex-row sm:items-start">
|
||||
<div className="flex flex-2 flex-col gap-2 sm:max-w-1/2">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<UserCircle className="size-6 text-primary" />
|
||||
<span className="font-medium">Contatti sbloccati</span>
|
||||
</div>
|
||||
<span className="text-sm">
|
||||
{openContattiAnnunci.length} / 10
|
||||
</span>
|
||||
</div>
|
||||
<Progress
|
||||
className="h-2"
|
||||
value={openContattiAnnunci.length * 10}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col flex-wrap gap-2 sm:flex-row sm:items-center">
|
||||
<div className="flex items-center gap-2">
|
||||
<CalendarClock className="size-6 text-primary" />
|
||||
<span className="font-medium">Durata servizio:</span>
|
||||
</div>
|
||||
<span>
|
||||
{`${new Date(servizio.decorrenza).toLocaleDateString("it-IT")} - ${new Date(add(servizio.decorrenza, { days: 60 })).toLocaleDateString("it-IT")}`}
|
||||
</span>
|
||||
</div>
|
||||
</div> */}
|
||||
{annuncioConfermato.length > 0 && (
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex items-center gap-2">
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ export const ContattiProprietarioModal = () => {
|
|||
{isUnlocked ? (
|
||||
<Button
|
||||
aria-label="Vedi contatti proprietario"
|
||||
className="w-fit"
|
||||
className="w-full md:w-fit"
|
||||
variant="success"
|
||||
>
|
||||
<CircleUser className="size-7" />
|
||||
|
|
@ -58,7 +58,7 @@ export const ContattiProprietarioModal = () => {
|
|||
) : (
|
||||
<Button
|
||||
aria-label="Contatta proprietario"
|
||||
className="w-fit"
|
||||
className="w-full md:w-fit"
|
||||
variant="warning"
|
||||
>
|
||||
<CircleUser className="size-7" />
|
||||
|
|
|
|||
|
|
@ -765,7 +765,9 @@ export const PasswordSVG = (props: SVGProps<SVGSVGElement>) => (
|
|||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
/*
|
||||
from: https://www.svgrepo.com/svg/477007/alarm-clock
|
||||
*/
|
||||
export const AlarmClockSVG = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
className="icon"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue