Refactor and enhance UI components across the application
- Renamed `AnnunciInConferma` to `AnnunciInConfermaDialog` and `AnnunciSelezionati` to `AnnunciSelezionatiDialog` for clarity. - Simplified button notifications for announcements by always displaying the count. - Introduced `AnnunciInConfermaAccordion` and `AnnunciSelezionatiAccordion` components to manage accordion behavior for announcements. - Updated button styles to remove unnecessary flex properties for better alignment. - Improved form validation logic in `FormNewServizioAcquisto` for better clarity and performance. - Enhanced the `UploadModal` to accept props directly, simplifying the component structure. - Added a new `CardAnnuncio` component for displaying announcements with improved layout and functionality. - Updated global styles to include a new background color variable. - Refactored API routes and controllers for better clarity and maintainability. - Cleaned up various components by removing redundant class names and improving accessibility.
This commit is contained in:
parent
97503b34e5
commit
6ad74c9002
43 changed files with 829 additions and 416 deletions
|
|
@ -109,7 +109,6 @@
|
||||||
"noDangerouslySetInnerHtml": "off"
|
"noDangerouslySetInnerHtml": "off"
|
||||||
},
|
},
|
||||||
"style": {
|
"style": {
|
||||||
"noNestedTernary": "info",
|
|
||||||
"noUselessElse": "on",
|
"noUselessElse": "on",
|
||||||
"noYodaExpression": "on",
|
"noYodaExpression": "on",
|
||||||
"useThrowNewError": "on",
|
"useThrowNewError": "on",
|
||||||
|
|
|
||||||
|
|
@ -199,11 +199,7 @@ const UserViewHeader = () => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Link href={`https://wa.me/${data.telefono}`} target="_blank">
|
<Link href={`https://wa.me/${data.telefono}`} target="_blank">
|
||||||
<Button
|
<Button size="sm" variant="success">
|
||||||
className="flex items-center gap-2"
|
|
||||||
size="sm"
|
|
||||||
variant="success"
|
|
||||||
>
|
|
||||||
<WhatsAppIcon2 className="size-4 fill-white" />
|
<WhatsAppIcon2 className="size-4 fill-white" />
|
||||||
WhatsApp
|
WhatsApp
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -212,7 +208,7 @@ const UserViewHeader = () => {
|
||||||
<div className="flex flex-row flex-wrap gap-2">
|
<div className="flex flex-row flex-wrap gap-2">
|
||||||
<Link href={`/area-riservata/admin/user-view/edit-user/${data.id}`}>
|
<Link href={`/area-riservata/admin/user-view/edit-user/${data.id}`}>
|
||||||
<Button
|
<Button
|
||||||
className="flex items-center gap-2 border"
|
className="border"
|
||||||
size="sm"
|
size="sm"
|
||||||
variant={pathname.includes("edit-user") ? "secondary" : "outline"}
|
variant={pathname.includes("edit-user") ? "secondary" : "outline"}
|
||||||
>
|
>
|
||||||
|
|
@ -221,7 +217,7 @@ const UserViewHeader = () => {
|
||||||
</Link>
|
</Link>
|
||||||
<Link href={`/area-riservata/admin/user-view/servizio/${data.id}`}>
|
<Link href={`/area-riservata/admin/user-view/servizio/${data.id}`}>
|
||||||
<Button
|
<Button
|
||||||
className="flex items-center gap-2 border"
|
className="border"
|
||||||
size="sm"
|
size="sm"
|
||||||
variant={pathname.includes("servizio") ? "secondary" : "outline"}
|
variant={pathname.includes("servizio") ? "secondary" : "outline"}
|
||||||
>
|
>
|
||||||
|
|
@ -231,7 +227,7 @@ const UserViewHeader = () => {
|
||||||
|
|
||||||
<Link href={`/area-riservata/admin/user-view/ricerca/${data.id}`}>
|
<Link href={`/area-riservata/admin/user-view/ricerca/${data.id}`}>
|
||||||
<Button
|
<Button
|
||||||
className="flex items-center gap-2 border"
|
className="border"
|
||||||
size="sm"
|
size="sm"
|
||||||
variant={pathname.includes("ricerca") ? "secondary" : "outline"}
|
variant={pathname.includes("ricerca") ? "secondary" : "outline"}
|
||||||
>
|
>
|
||||||
|
|
@ -240,7 +236,7 @@ const UserViewHeader = () => {
|
||||||
</Link>
|
</Link>
|
||||||
<Link href={`/area-riservata/admin/user-view/comunicazioni/${data.id}`}>
|
<Link href={`/area-riservata/admin/user-view/comunicazioni/${data.id}`}>
|
||||||
<Button
|
<Button
|
||||||
className="flex items-center gap-2 border"
|
className="border"
|
||||||
size="sm"
|
size="sm"
|
||||||
variant={
|
variant={
|
||||||
pathname.includes("comunicazioni") ? "secondary" : "outline"
|
pathname.includes("comunicazioni") ? "secondary" : "outline"
|
||||||
|
|
@ -252,7 +248,7 @@ const UserViewHeader = () => {
|
||||||
|
|
||||||
<Link href={`/area-riservata/admin/user-view/ordini/${data.id}`}>
|
<Link href={`/area-riservata/admin/user-view/ordini/${data.id}`}>
|
||||||
<Button
|
<Button
|
||||||
className="flex items-center gap-2 border"
|
className="border"
|
||||||
size="sm"
|
size="sm"
|
||||||
variant={pathname.includes("ordini") ? "secondary" : "outline"}
|
variant={pathname.includes("ordini") ? "secondary" : "outline"}
|
||||||
>
|
>
|
||||||
|
|
@ -261,7 +257,7 @@ const UserViewHeader = () => {
|
||||||
</Link>
|
</Link>
|
||||||
<Link href={`/area-riservata/admin/user-view/allegati/${data.id}`}>
|
<Link href={`/area-riservata/admin/user-view/allegati/${data.id}`}>
|
||||||
<Button
|
<Button
|
||||||
className="flex items-center gap-2 border"
|
className="border"
|
||||||
size="sm"
|
size="sm"
|
||||||
variant={pathname.includes("allegati") ? "secondary" : "outline"}
|
variant={pathname.includes("allegati") ? "secondary" : "outline"}
|
||||||
>
|
>
|
||||||
|
|
@ -281,7 +277,7 @@ const UserViewHeader = () => {
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
className="flex items-center gap-2 border"
|
className="border"
|
||||||
size="sm"
|
size="sm"
|
||||||
variant={!data.chatid ? "ghost" : "outline"}
|
variant={!data.chatid ? "ghost" : "outline"}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,7 @@ const PricePreparation = ({
|
||||||
href={`/servizio/condizioni/${prezziario.testo_condizioni}`}
|
href={`/servizio/condizioni/${prezziario.testo_condizioni}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<Button className="flex w-full items-center gap-2 text-sm">
|
<Button className="w-full text-sm">
|
||||||
<span>{t.acquisto.leggi_condizioni}</span>
|
<span>{t.acquisto.leggi_condizioni}</span>
|
||||||
<ExternalLink />
|
<ExternalLink />
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -154,7 +154,7 @@ const PricePreparation = ({
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
className="flex w-full items-center gap-2 text-lg"
|
className="w-full text-lg"
|
||||||
disabled={isLoading || !prezziario}
|
disabled={isLoading || !prezziario}
|
||||||
onClick={onProcedi}
|
onClick={onProcedi}
|
||||||
size="xl"
|
size="xl"
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { CardAnnuncio } from "~/components/annuncio_card";
|
import { CardAnnuncio } from "~/components/annuncio_card2";
|
||||||
import { getTitoloTranslation } from "~/lib/annuncio_details";
|
import { getTitoloTranslation } from "~/lib/annuncio_details";
|
||||||
import { useTranslation } from "~/providers/I18nProvider";
|
import { useTranslation } from "~/providers/I18nProvider";
|
||||||
import type { AnnuncioRicerca } from "~/server/controllers/annunci.controller";
|
import type { AnnuncioRicerca } from "~/server/controllers/annunci.controller";
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ export const CTA_TipologiaModal = () => {
|
||||||
open={open}
|
open={open}
|
||||||
>
|
>
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Button className="flex items-center gap-2" variant="info">
|
<Button variant="info">
|
||||||
<CircleHelp />{" "}
|
<CircleHelp />{" "}
|
||||||
<span className="hidden sm:block">
|
<span className="hidden sm:block">
|
||||||
{t.tipologia_tutorial.btn_title}
|
{t.tipologia_tutorial.btn_title}
|
||||||
|
|
@ -78,7 +78,7 @@ export const CTA_TipologiaModal = () => {
|
||||||
<p>{t.tipologia_tutorial.transitorio_desc}</p>
|
<p>{t.tipologia_tutorial.transitorio_desc}</p>
|
||||||
<Button
|
<Button
|
||||||
aria-label={t.tipologia_tutorial.transitorio_cta}
|
aria-label={t.tipologia_tutorial.transitorio_cta}
|
||||||
className="flex w-full items-center gap-2 bg-transitorio"
|
className="w-full bg-transitorio"
|
||||||
onClick={async () => await update("Transitorio")}
|
onClick={async () => await update("Transitorio")}
|
||||||
>
|
>
|
||||||
{t.tipologia_tutorial.transitorio_cta}
|
{t.tipologia_tutorial.transitorio_cta}
|
||||||
|
|
@ -93,7 +93,7 @@ export const CTA_TipologiaModal = () => {
|
||||||
<p>{t.tipologia_tutorial.stabile_desc}</p>
|
<p>{t.tipologia_tutorial.stabile_desc}</p>
|
||||||
<Button
|
<Button
|
||||||
aria-label={t.tipologia_tutorial.stabile_cta}
|
aria-label={t.tipologia_tutorial.stabile_cta}
|
||||||
className="flex w-full items-center gap-2 bg-stabile"
|
className="w-full bg-stabile"
|
||||||
onClick={async () => await update("Stabile")}
|
onClick={async () => await update("Stabile")}
|
||||||
>
|
>
|
||||||
{t.tipologia_tutorial.stabile_cta}
|
{t.tipologia_tutorial.stabile_cta}
|
||||||
|
|
@ -104,7 +104,7 @@ export const CTA_TipologiaModal = () => {
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
aria-label={t.tipologia_tutorial.alone}
|
aria-label={t.tipologia_tutorial.alone}
|
||||||
className="flex w-full items-center gap-2"
|
className="w-full"
|
||||||
onClick={async () => await update(null)}
|
onClick={async () => await update(null)}
|
||||||
variant="outline"
|
variant="outline"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ const ServizioInteraction = ({
|
||||||
aria-label="Vai alla tua area riservata"
|
aria-label="Vai alla tua area riservata"
|
||||||
href={`/area-riservata/dashboard`}
|
href={`/area-riservata/dashboard`}
|
||||||
>
|
>
|
||||||
<Button className="flex w-full items-center gap-2" variant="success">
|
<Button className="w-full" variant="success">
|
||||||
Vai alla tua area riservata <ArrowRight />
|
Vai alla tua area riservata <ArrowRight />
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
@ -128,7 +128,7 @@ const InteressatoButton = ({ annuncioId }: { annuncioId: AnnunciId }) => {
|
||||||
|
|
||||||
if (isLoading || hasInterest === undefined) {
|
if (isLoading || hasInterest === undefined) {
|
||||||
return (
|
return (
|
||||||
<Button className="flex w-full items-center gap-2" disabled>
|
<Button className="w-full" disabled>
|
||||||
<BadgePlus className="size-6" />
|
<BadgePlus className="size-6" />
|
||||||
Caricamento...
|
Caricamento...
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -146,7 +146,7 @@ const InteressatoButton = ({ annuncioId }: { annuncioId: AnnunciId }) => {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
aria-label="Sono interessato"
|
aria-label="Sono interessato"
|
||||||
className="flex w-full items-center gap-2"
|
className="w-full"
|
||||||
//size="xl"
|
//size="xl"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
add({
|
add({
|
||||||
|
|
@ -188,7 +188,7 @@ export const InteressatoButtonBatchV = ({
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
aria-label="Sono interessato"
|
aria-label="Sono interessato"
|
||||||
className="flex w-full items-center gap-2"
|
className="w-full"
|
||||||
//size="xl"
|
//size="xl"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
add({
|
add({
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,7 @@ export const ContattoAnnuncio = () => {
|
||||||
return (
|
return (
|
||||||
<Credenza>
|
<Credenza>
|
||||||
<CredenzaTrigger asChild>
|
<CredenzaTrigger asChild>
|
||||||
<Button
|
<Button className="w-full" variant="destructive">
|
||||||
className="flex w-full items-center gap-2"
|
|
||||||
variant="destructive"
|
|
||||||
>
|
|
||||||
<MessageCircleQuestion className="size-6" /> Contattaci
|
<MessageCircleQuestion className="size-6" /> Contattaci
|
||||||
</Button>
|
</Button>
|
||||||
</CredenzaTrigger>
|
</CredenzaTrigger>
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ export const CardAnnuncio = ({
|
||||||
<Carousel opts={{ loop: true }}>
|
<Carousel opts={{ loop: true }}>
|
||||||
<CarouselContent>
|
<CarouselContent>
|
||||||
{images?.map((img, idx) => (
|
{images?.map((img, idx) => (
|
||||||
<CarouselItem className="" key={`${img.img}key`}>
|
<CarouselItem key={`${img.img}key`}>
|
||||||
<ImageFlbk
|
<ImageFlbk
|
||||||
alt={t.card.alt_immagine}
|
alt={t.card.alt_immagine}
|
||||||
blurDataURL={`/storage-api/get/${img.thumb}?image=true`}
|
blurDataURL={`/storage-api/get/${img.thumb}?image=true`}
|
||||||
|
|
|
||||||
404
apps/infoalloggi/src/components/annuncio_card2.tsx
Normal file
404
apps/infoalloggi/src/components/annuncio_card2.tsx
Normal file
|
|
@ -0,0 +1,404 @@
|
||||||
|
import { BedDouble, CalendarClock, Maximize2, Ruler } from "lucide-react";
|
||||||
|
import Image from "next/image";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { ImageFlbk } from "~/components/ImageWithFallback";
|
||||||
|
import {
|
||||||
|
Carousel,
|
||||||
|
CarouselContent,
|
||||||
|
CarouselItem,
|
||||||
|
CarouselNext,
|
||||||
|
CarouselPrevious,
|
||||||
|
} from "~/components/ui/carousel";
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
} from "~/components/ui/dialog";
|
||||||
|
import { camereTesti, handleConsegna } from "~/lib/annuncio_details";
|
||||||
|
import { cn, formatCurrency } from "~/lib/utils";
|
||||||
|
import { useTranslation } from "~/providers/I18nProvider";
|
||||||
|
|
||||||
|
import { VideoPlayer } from "./videoPlayer";
|
||||||
|
|
||||||
|
type CardAnnuncioProps = {
|
||||||
|
id: number;
|
||||||
|
codice: string;
|
||||||
|
prezzo: number;
|
||||||
|
titolo: string | null;
|
||||||
|
mq: string | null;
|
||||||
|
comune: string | null;
|
||||||
|
provincia: string | null;
|
||||||
|
consegna: number | null;
|
||||||
|
camere: number | null;
|
||||||
|
//immagini: string[] | undefined;
|
||||||
|
tipo: string | null;
|
||||||
|
stato: string | null;
|
||||||
|
className?: string;
|
||||||
|
videos?: string[] | undefined;
|
||||||
|
updated_at: Date | null;
|
||||||
|
images: { img: string; thumb: string }[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CardAnnuncio = ({
|
||||||
|
id,
|
||||||
|
codice,
|
||||||
|
prezzo,
|
||||||
|
titolo,
|
||||||
|
mq,
|
||||||
|
comune,
|
||||||
|
provincia,
|
||||||
|
consegna,
|
||||||
|
camere,
|
||||||
|
//immagini,
|
||||||
|
tipo,
|
||||||
|
stato,
|
||||||
|
className,
|
||||||
|
videos,
|
||||||
|
updated_at,
|
||||||
|
images,
|
||||||
|
}: CardAnnuncioProps) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"h-[464px] rounded-md bg-white shadow-neutral-100 shadow-sm hover:shadow-md hover:outline-neutral-600",
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
id={`card-annuncio-${id}`}
|
||||||
|
>
|
||||||
|
<Link
|
||||||
|
className="block p-2"
|
||||||
|
//target="_blank"
|
||||||
|
href={`/annuncio/${codice}`} //duration-700 ease-in-out animate-in fade-in
|
||||||
|
>
|
||||||
|
<div className="group relative overflow-clip text-clip rounded-md">
|
||||||
|
<div className="absolute top-2 left-2 z-20 rounded-md bg-white px-2 py-1 font-semibold text-neutral-800 text-sm shadow-md shadow-neutral-300 backdrop-blur-sm">
|
||||||
|
Cod: {codice}
|
||||||
|
</div>
|
||||||
|
{stato === "Trattativa" && (
|
||||||
|
<div>
|
||||||
|
<div className="absolute z-20 h-56 w-full">
|
||||||
|
<div className="absolute bottom-0 w-full touch-none select-none rounded-b-md bg-violet-500 text-center text-lg text-white">
|
||||||
|
Annuncio in Trattativa
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Carousel opts={{ loop: true }}>
|
||||||
|
<CarouselContent>
|
||||||
|
{images?.map((img, idx) => (
|
||||||
|
<CarouselItem key={`${img.img}key`}>
|
||||||
|
<ImageFlbk
|
||||||
|
alt={t.card.alt_immagine}
|
||||||
|
blurDataURL={`/storage-api/get/${img.thumb}?image=true`}
|
||||||
|
className={"h-64 w-full object-cover"}
|
||||||
|
height={1080}
|
||||||
|
priority={idx === 0}
|
||||||
|
src={`/storage-api/get/${img.img}?image=true`}
|
||||||
|
width={1920}
|
||||||
|
/>
|
||||||
|
</CarouselItem>
|
||||||
|
))}
|
||||||
|
{videos?.map((video) => {
|
||||||
|
if (!video) return null;
|
||||||
|
if (video.includes("youtu")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<CarouselItem
|
||||||
|
className={cn("group relative")}
|
||||||
|
key={`videoplayer-${video}`}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<VideoPlayer
|
||||||
|
cacheKey={updated_at?.toString() || new Date().toString()}
|
||||||
|
className="h-56"
|
||||||
|
coverImage={
|
||||||
|
images?.[0]
|
||||||
|
? `/storage-api/get/${images[0].img}?image=true`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
key={`videoplayer-${video}`}
|
||||||
|
videoSrc={video}
|
||||||
|
/>
|
||||||
|
</CarouselItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</CarouselContent>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className="block opacity-0 transition-all duration-200 group-hover:opacity-60 disabled:group-hover:opacity-0"
|
||||||
|
onClick={(e) => e.preventDefault()}
|
||||||
|
onKeyDown={(e) => e.stopPropagation()}
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
|
>
|
||||||
|
<CarouselPrevious
|
||||||
|
className="left-2 cursor-pointer"
|
||||||
|
disabled={!images || images.length === 1}
|
||||||
|
/>
|
||||||
|
<CarouselNext
|
||||||
|
className="right-2 cursor-pointer"
|
||||||
|
disabled={!images || images.length === 1}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Carousel>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"mt-2 flex w-full items-center justify-center rounded-md",
|
||||||
|
tipo === "Transitorio" && "bg-transitorio",
|
||||||
|
tipo === "Stabile" && "bg-stabile",
|
||||||
|
tipo === "Cessione" && "bg-blue-400",
|
||||||
|
tipo === "Vendita" && "bg-green-400",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className="font-semibold text-white">{tipo}</div>
|
||||||
|
</div>
|
||||||
|
<div className="mt-2 space-y-2">
|
||||||
|
<div className="flex flex-row justify-around">
|
||||||
|
<div className="text-center">
|
||||||
|
<span className="sr-only">{t.card.codice}</span>
|
||||||
|
|
||||||
|
<span className="font-semibold text-red-600 text-xl">
|
||||||
|
Cod: {codice}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="text-center">
|
||||||
|
<span className="sr-only">{t.card.prezzo}</span>
|
||||||
|
|
||||||
|
<span className="font-semibold text-xl">
|
||||||
|
{formatCurrency(prezzo / 1e2)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mb-3 text-center text-muted-foreground">
|
||||||
|
<span className="sr-only">{t.card.titolo}</span>
|
||||||
|
|
||||||
|
<span className="line-clamp-2 min-h-[3.5rem] font-medium text-base md:text-lg">
|
||||||
|
{titolo}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="text-center text-muted-foreground">
|
||||||
|
<span className="sr-only">{t.card.indirizzo}</span>
|
||||||
|
|
||||||
|
<span className="font-medium text-sm">
|
||||||
|
{comune && provincia && `${comune} (${provincia})`}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-4 flex items-center justify-around gap-2 text-muted-foreground text-xs">
|
||||||
|
<div className="flex w-full items-center justify-center gap-1 rounded-md bg-neutral-100 py-3">
|
||||||
|
<Ruler className="size-4 text-indigo-700" />
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p className="font-medium">
|
||||||
|
{mq ? Number.parseFloat(mq) : 0}{" "}
|
||||||
|
<span>
|
||||||
|
m<sup>2</sup>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex w-full items-center justify-center gap-1 rounded-md bg-neutral-100 py-3">
|
||||||
|
<BedDouble className="size-4 text-indigo-700" />
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p className="font-medium">
|
||||||
|
{camereTesti({ camere: camere, testi: t.card })}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex w-full items-center justify-center gap-1 rounded-md bg-neutral-100 py-3">
|
||||||
|
<CalendarClock className="size-4 text-indigo-700" />
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p className="truncate font-medium">
|
||||||
|
{handleConsegna({
|
||||||
|
aggiornamento: t.card.in_aggiornamento,
|
||||||
|
consegna: consegna,
|
||||||
|
consegna_da: t.card.consegna_da,
|
||||||
|
mesi: t.preferenze.mesi,
|
||||||
|
subito: t.card.consegna_subito,
|
||||||
|
})}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CarouselAnnuncio = ({
|
||||||
|
single,
|
||||||
|
immagini,
|
||||||
|
videos,
|
||||||
|
updated_at,
|
||||||
|
}: {
|
||||||
|
single?: boolean;
|
||||||
|
immagini: string[] | null;
|
||||||
|
videos: string[] | null;
|
||||||
|
updated_at: Date | null;
|
||||||
|
}) => {
|
||||||
|
const [openModal, setOpenModal] = useState(false);
|
||||||
|
const [idxModal, setIdxModal] = useState(0);
|
||||||
|
function handleOpenModal(position: number) {
|
||||||
|
setIdxModal(position);
|
||||||
|
setOpenModal(true);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="mx-auto my-4 w-full text-clip rounded-md">
|
||||||
|
<div className="relative">
|
||||||
|
<Carousel opts={{ align: "start", loop: true }}>
|
||||||
|
<CarouselContent>
|
||||||
|
{immagini?.map((img, idx) => (
|
||||||
|
<CarouselItem
|
||||||
|
className={cn(
|
||||||
|
"group relative flex items-center justify-center",
|
||||||
|
immagini && immagini.length === 1
|
||||||
|
? ""
|
||||||
|
: !single && "md:basis-1/2 lg:basis-1/3",
|
||||||
|
)}
|
||||||
|
key={`${img}-cF`}
|
||||||
|
>
|
||||||
|
<ImageFlbk
|
||||||
|
alt={img}
|
||||||
|
className={cn(
|
||||||
|
"aspect-square max-h-92 w-full rounded-md object-cover sm:max-h-80",
|
||||||
|
immagini.length === 1 && "object-contain",
|
||||||
|
)}
|
||||||
|
height={400}
|
||||||
|
onClick={() => handleOpenModal(idx)}
|
||||||
|
priority={idx === 0}
|
||||||
|
src={`/storage-api/get/${img}?image=true&${updated_at?.toString() || new Date().toString()}`}
|
||||||
|
width={800}
|
||||||
|
/>
|
||||||
|
<Maximize2
|
||||||
|
className="absolute right-2 bottom-2 size-7 origin-bottom-right cursor-pointer rounded-md bg-white/70 stroke-2 p-1 transition-all duration-300 ease-in-out hover:scale-150 group-hover:opacity-100 sm:opacity-0"
|
||||||
|
onClick={() => handleOpenModal(idx)}
|
||||||
|
/>
|
||||||
|
</CarouselItem>
|
||||||
|
))}
|
||||||
|
{videos?.map((video, idx) => {
|
||||||
|
if (!video) return null;
|
||||||
|
if (video.includes("youtu")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<CarouselItem
|
||||||
|
className={cn(
|
||||||
|
"group relative",
|
||||||
|
immagini && immagini.length === 1
|
||||||
|
? ""
|
||||||
|
: !single && "md:basis-1/2 lg:basis-1/3",
|
||||||
|
)}
|
||||||
|
key={`videoplayer-${video}`}
|
||||||
|
>
|
||||||
|
<VideoPlayer
|
||||||
|
cacheKey={updated_at?.toString() || new Date().toString()}
|
||||||
|
className="h-72"
|
||||||
|
coverImage={
|
||||||
|
immagini?.[0]
|
||||||
|
? `/storage-api/get/${immagini[0]}?image=true`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
key={`videoplayer-${idx}-${openModal}`}
|
||||||
|
videoSrc={video}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Maximize2
|
||||||
|
className="absolute right-2 bottom-2 size-7 origin-bottom-right cursor-pointer rounded-md bg-white/70 stroke-2 p-1 transition-all duration-300 ease-in-out hover:scale-150 group-hover:opacity-100 sm:opacity-0"
|
||||||
|
onClick={() =>
|
||||||
|
handleOpenModal(immagini?.length || 0 + idx)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</CarouselItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</CarouselContent>
|
||||||
|
|
||||||
|
<CarouselPrevious
|
||||||
|
className="left-2 cursor-pointer opacity-60 disabled:opacity-0"
|
||||||
|
disabled={!immagini || immagini.length === 1}
|
||||||
|
type="button"
|
||||||
|
/>
|
||||||
|
<CarouselNext
|
||||||
|
className="right-2 cursor-pointer opacity-60 disabled:opacity-0"
|
||||||
|
disabled={!immagini || immagini.length === 1}
|
||||||
|
type="button"
|
||||||
|
/>
|
||||||
|
</Carousel>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Dialog onOpenChange={setOpenModal} open={openModal}>
|
||||||
|
<DialogContent className="flex h-full w-full max-w-full items-center justify-center border-transparent border-none bg-white p-0 md:max-w-[80vw] md:p-6 [&_#dialog-close>svg]:size-8">
|
||||||
|
<DialogHeader className="absolute top-0 right-0 left-0 z-10">
|
||||||
|
<DialogTitle className="sr-only">Image Dialog</DialogTitle>
|
||||||
|
<DialogDescription className="sr-only">Immagine</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
<Carousel opts={{ loop: true, startIndex: idxModal }}>
|
||||||
|
<CarouselContent>
|
||||||
|
{immagini?.map((img, idx) => (
|
||||||
|
<CarouselItem key={`${img}-cD`}>
|
||||||
|
<Image
|
||||||
|
alt={`carousel-img-${idx}`}
|
||||||
|
className="mx-auto h-[90vh] w-full rounded-md object-contain sm:w-[80vw]"
|
||||||
|
height={1080}
|
||||||
|
src={`/storage-api/get/${img}?image=true&${updated_at?.toString() || new Date().toString()}`}
|
||||||
|
width={1920}
|
||||||
|
/>
|
||||||
|
</CarouselItem>
|
||||||
|
))}
|
||||||
|
{videos?.map((video) => {
|
||||||
|
if (!video) return null;
|
||||||
|
if (video.includes("youtu")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<CarouselItem
|
||||||
|
className="relative flex items-center justify-center"
|
||||||
|
key={`carousel-videoplayer-${video}`}
|
||||||
|
>
|
||||||
|
<VideoPlayer
|
||||||
|
cacheKey={updated_at?.toString() || new Date().toString()}
|
||||||
|
className="absolute mx-auto h-[90vh] w-full max-w-fit rounded-md object-contain"
|
||||||
|
coverImage={
|
||||||
|
immagini?.[0]
|
||||||
|
? `/storage-api/get/${immagini[0]}?image=true`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
videoSrc={video}
|
||||||
|
/>
|
||||||
|
</CarouselItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</CarouselContent>
|
||||||
|
|
||||||
|
<CarouselPrevious
|
||||||
|
className="left-2 cursor-pointer opacity-60 disabled:opacity-0"
|
||||||
|
disabled={!immagini || immagini.length === 1}
|
||||||
|
type="button"
|
||||||
|
/>
|
||||||
|
<CarouselNext
|
||||||
|
className="right-2 cursor-pointer opacity-60 disabled:opacity-0"
|
||||||
|
disabled={!immagini || immagini.length === 1}
|
||||||
|
type="button"
|
||||||
|
/>
|
||||||
|
</Carousel>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -30,7 +30,7 @@ export const AdminDashboard = () => {
|
||||||
<div className="text-red-500">Errore caricamento statistiche</div>
|
<div className="text-red-500">Errore caricamento statistiche</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="grid grid-cols-1 gap-4 px-2 pt-4 sm:grid-cols-2 sm:px-4">
|
<div className="grid grid-cols-1 gap-4 px-2 pt-4 sm:grid-cols-2 sm:px-4">
|
||||||
<Card className="">
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>Utenti</CardTitle>
|
<CardTitle>Utenti</CardTitle>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ export const OrdiniModal = ({
|
||||||
href={`/area-riservata/payment-recap/${data.ordine_id}`}
|
href={`/area-riservata/payment-recap/${data.ordine_id}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<Button className="flex items-center gap-2" variant="outline">
|
<Button variant="outline">
|
||||||
Ricevuta di cortesia <ReceiptText />
|
Ricevuta di cortesia <ReceiptText />
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ export const ChatAttachments = ({
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
className="flex h-8 items-center gap-2 truncate p-0 text-base has-[>svg]:px-0"
|
className="h-8 truncate p-0 text-base has-[>svg]:px-0"
|
||||||
variant="link"
|
variant="link"
|
||||||
>
|
>
|
||||||
<ExtIcon mimeType={file.mimeType} />
|
<ExtIcon mimeType={file.mimeType} />
|
||||||
|
|
|
||||||
|
|
@ -157,7 +157,7 @@ const FormMessage = React.forwardRef<
|
||||||
return (
|
return (
|
||||||
<p
|
<p
|
||||||
className={cn(
|
className={cn(
|
||||||
"font-medium text-red-500 text-sm dark:text-red-600",
|
"font-medium text-red-500 text-sm leading-none dark:text-red-600",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
id={formMessageId}
|
id={formMessageId}
|
||||||
|
|
|
||||||
|
|
@ -107,12 +107,7 @@ export const OnboardTutorial = () => {
|
||||||
</div>
|
</div>
|
||||||
</AlertDialogHeader>
|
</AlertDialogHeader>
|
||||||
<AlertDialogFooter>
|
<AlertDialogFooter>
|
||||||
<Button
|
<Button onClick={handleClose} size="lg" variant="success">
|
||||||
className="flex items-center gap-2"
|
|
||||||
onClick={handleClose}
|
|
||||||
size="lg"
|
|
||||||
variant="success"
|
|
||||||
>
|
|
||||||
<span>{t.onboarding_tutorial.button_text}</span>
|
<span>{t.onboarding_tutorial.button_text}</span>
|
||||||
<ArrowRight className="size-5" />
|
<ArrowRight className="size-5" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -200,7 +200,7 @@ export const PricingComponent = ({
|
||||||
href={"/prezzi#contratti"}
|
href={"/prezzi#contratti"}
|
||||||
id="contratto-link"
|
id="contratto-link"
|
||||||
>
|
>
|
||||||
<Button className="flex items-center gap-2">
|
<Button>
|
||||||
Più info <ExternalLink className="size-4" />
|
Più info <ExternalLink className="size-4" />
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
||||||
|
|
@ -216,7 +216,7 @@ function SchedaAnnuncio({ data }: { data: Annunci }) {
|
||||||
className="flex items-center justify-start gap-2"
|
className="flex items-center justify-start gap-2"
|
||||||
key={item.text}
|
key={item.text}
|
||||||
>
|
>
|
||||||
<span className="">
|
<span>
|
||||||
<IconMatrix type={item.icon} />
|
<IconMatrix type={item.icon} />
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import {
|
||||||
FolderKanban,
|
FolderKanban,
|
||||||
Pen,
|
Pen,
|
||||||
Plus,
|
Plus,
|
||||||
|
ShieldUser,
|
||||||
Trash2,
|
Trash2,
|
||||||
Wrench,
|
Wrench,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
|
|
@ -99,7 +100,7 @@ export const AnnuncioActions = () => {
|
||||||
href={`https://win-jk822fggr6b:480/id/${data.gestionale_id}`}
|
href={`https://win-jk822fggr6b:480/id/${data.gestionale_id}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<Button className="flex items-center gap-2">
|
<Button>
|
||||||
<FolderKanban className="size-5" /> Gestionale
|
<FolderKanban className="size-5" /> Gestionale
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
@ -107,18 +108,29 @@ export const AnnuncioActions = () => {
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{isAdmin && (
|
{isAdmin && (
|
||||||
<>
|
<Popover>
|
||||||
|
<PopoverTrigger asChild>
|
||||||
|
<Button>
|
||||||
|
<ShieldUser />
|
||||||
|
<span>Admin</span>
|
||||||
|
</Button>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent
|
||||||
|
align="end"
|
||||||
|
className="flex w-fit flex-col items-center gap-2"
|
||||||
|
>
|
||||||
<Link
|
<Link
|
||||||
href={`/area-riservata/admin/edit-annuncio/${annuncioId}`}
|
href={`/area-riservata/admin/edit-annuncio/${annuncioId}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
aria-label="Edit Annuncio"
|
aria-label="Edit Annuncio"
|
||||||
className="flex w-full items-center gap-2"
|
className="w-full"
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
>
|
>
|
||||||
<Wrench className="size-6" />
|
<Wrench />
|
||||||
|
<span>Modifica Annuncio</span>
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
|
|
@ -134,14 +146,16 @@ export const AnnuncioActions = () => {
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
aria-label="Delete Annuncio"
|
aria-label="Delete Annuncio"
|
||||||
className="flex items-center gap-2"
|
className="w-full"
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="destructive"
|
variant="destructive"
|
||||||
>
|
>
|
||||||
<Trash2 className="size-6" />
|
<Trash2 />
|
||||||
|
<span>Elimina Annuncio</span>
|
||||||
</Button>
|
</Button>
|
||||||
</Confirm>
|
</Confirm>
|
||||||
</>
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
@ -232,7 +246,6 @@ const ContrattoImport = ({
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<Button
|
<Button
|
||||||
aria-label="Import Contratto"
|
aria-label="Import Contratto"
|
||||||
className="flex items-center gap-2"
|
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const clipboardText = await navigator.clipboard.readText();
|
const clipboardText = await navigator.clipboard.readText();
|
||||||
|
|
||||||
|
|
@ -245,7 +258,6 @@ const ContrattoImport = ({
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
aria-label="Reset Contratto"
|
aria-label="Reset Contratto"
|
||||||
className="flex items-center gap-2"
|
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
setContratto({
|
setContratto({
|
||||||
contratto_decorrenza: null,
|
contratto_decorrenza: null,
|
||||||
|
|
@ -445,7 +457,7 @@ const AdminContratto = () => {
|
||||||
<CredenzaTrigger asChild>
|
<CredenzaTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
aria-label="Open Contratto Section"
|
aria-label="Open Contratto Section"
|
||||||
className="flex w-fit items-center gap-2"
|
className="w-fit"
|
||||||
variant={data.doc_contratto_added ? "success" : "secondary"}
|
variant={data.doc_contratto_added ? "success" : "secondary"}
|
||||||
>
|
>
|
||||||
{data.doc_contratto_added ? (
|
{data.doc_contratto_added ? (
|
||||||
|
|
@ -709,7 +721,7 @@ const AdminLavoraConferma = () => {
|
||||||
<CredenzaTrigger asChild>
|
<CredenzaTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
aria-label="Open Lavora Conferma Section"
|
aria-label="Open Lavora Conferma Section"
|
||||||
className="flex w-fit items-center gap-2"
|
className="w-fit"
|
||||||
variant={data.hasConfermaAdmin ? "success" : "secondary"}
|
variant={data.hasConfermaAdmin ? "success" : "secondary"}
|
||||||
>
|
>
|
||||||
{data.hasConfermaAdmin ? (
|
{data.hasConfermaAdmin ? (
|
||||||
|
|
@ -983,7 +995,6 @@ const Caparra = ({
|
||||||
<div className="flex flex-wrap items-center gap-3">
|
<div className="flex flex-wrap items-center gap-3">
|
||||||
<Button
|
<Button
|
||||||
aria-label="Import Caparra"
|
aria-label="Import Caparra"
|
||||||
className="flex items-center gap-2"
|
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const clipboardText = await navigator.clipboard.readText();
|
const clipboardText = await navigator.clipboard.readText();
|
||||||
|
|
||||||
|
|
@ -996,7 +1007,6 @@ const Caparra = ({
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
aria-label="Reset Caparra"
|
aria-label="Reset Caparra"
|
||||||
className="flex items-center gap-2"
|
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
setCaparra({
|
setCaparra({
|
||||||
caparra_causale: null,
|
caparra_causale: null,
|
||||||
|
|
|
||||||
|
|
@ -120,10 +120,7 @@ export const BasicAnnuncioCard = ({
|
||||||
aria-label="Pagina Annuncio"
|
aria-label="Pagina Annuncio"
|
||||||
href={`/annuncio/${data.codice}`}
|
href={`/annuncio/${data.codice}`}
|
||||||
>
|
>
|
||||||
<Button
|
<Button variant="outline">
|
||||||
className="flex items-center gap-2"
|
|
||||||
variant="outline"
|
|
||||||
>
|
|
||||||
<ExternalLink className="size-6" />
|
<ExternalLink className="size-6" />
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
@ -159,11 +156,7 @@ const AnnuncioDettaglio = ({ data }: { data: AnnuncioData }) => {
|
||||||
return (
|
return (
|
||||||
<Credenza>
|
<Credenza>
|
||||||
<CredenzaTrigger asChild>
|
<CredenzaTrigger asChild>
|
||||||
<Button
|
<Button aria-label="Dettagli Annuncio" variant="outline">
|
||||||
aria-label="Dettagli Annuncio"
|
|
||||||
className="flex items-center gap-2"
|
|
||||||
variant="outline"
|
|
||||||
>
|
|
||||||
<UnfoldVertical className="size-6" /> Dettagli annuncio
|
<UnfoldVertical className="size-6" /> Dettagli annuncio
|
||||||
</Button>
|
</Button>
|
||||||
</CredenzaTrigger>
|
</CredenzaTrigger>
|
||||||
|
|
|
||||||
|
|
@ -58,10 +58,7 @@ export const Interactions = () => {
|
||||||
aria-label="Conferma immobile"
|
aria-label="Conferma immobile"
|
||||||
href={`/servizio/conferma-immobile/${servizioId}/${annuncioId}`}
|
href={`/servizio/conferma-immobile/${servizioId}/${annuncioId}`}
|
||||||
>
|
>
|
||||||
<Button
|
<Button className="w-fit" variant="success">
|
||||||
className="flex w-fit items-center gap-2"
|
|
||||||
variant="success"
|
|
||||||
>
|
|
||||||
<Pointer className="size-6" />
|
<Pointer className="size-6" />
|
||||||
Confermato - Procedi ora
|
Confermato - Procedi ora
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -71,7 +68,7 @@ export const Interactions = () => {
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
className="flex w-fit cursor-not-allowed items-center gap-2 opacity-50"
|
className="w-fit cursor-not-allowed opacity-50"
|
||||||
variant="success"
|
variant="success"
|
||||||
>
|
>
|
||||||
<Pointer className="size-6" />
|
<Pointer className="size-6" />
|
||||||
|
|
@ -92,7 +89,7 @@ export const Interactions = () => {
|
||||||
aria-label="Conferma immobile"
|
aria-label="Conferma immobile"
|
||||||
href={`/servizio/riapri-conferma/${servizioId}/${annuncioId}`}
|
href={`/servizio/riapri-conferma/${servizioId}/${annuncioId}`}
|
||||||
>
|
>
|
||||||
<Button className="flex w-fit items-center gap-2" variant="success">
|
<Button className="w-fit" variant="success">
|
||||||
<Pointer className="size-6" />
|
<Pointer className="size-6" />
|
||||||
Rivedi la conferma
|
Rivedi la conferma
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -136,7 +133,7 @@ export const Interactions = () => {
|
||||||
href={`/servizio/contratto/${servizioId}/${annuncioId}`}
|
href={`/servizio/contratto/${servizioId}/${annuncioId}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<Button className="flex w-fit items-center gap-2">
|
<Button className="w-fit">
|
||||||
<FileText className="size-6" />
|
<FileText className="size-6" />
|
||||||
Visualizza il contratto
|
Visualizza il contratto
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -145,7 +142,7 @@ export const Interactions = () => {
|
||||||
<TooltipProvider delayDuration={0}>
|
<TooltipProvider delayDuration={0}>
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<Button className="flex w-fit cursor-not-allowed items-center gap-2 opacity-50">
|
<Button className="w-fit cursor-not-allowed opacity-50">
|
||||||
<FileText className="size-6" />
|
<FileText className="size-6" />
|
||||||
Visualizza il contratto
|
Visualizza il contratto
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -172,7 +169,7 @@ export const Interactions = () => {
|
||||||
href={`/servizio/contratto-registrazione/${servizioId}/${annuncioId}`}
|
href={`/servizio/contratto-registrazione/${servizioId}/${annuncioId}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<Button className="flex w-fit items-center gap-2">
|
<Button className="w-fit">
|
||||||
<FileBadge className="size-6" />
|
<FileBadge className="size-6" />
|
||||||
Visualizza la registrazione
|
Visualizza la registrazione
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -181,7 +178,7 @@ export const Interactions = () => {
|
||||||
<TooltipProvider delayDuration={0}>
|
<TooltipProvider delayDuration={0}>
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<Button className="flex w-fit cursor-not-allowed items-center gap-2 opacity-50">
|
<Button className="w-fit cursor-not-allowed opacity-50">
|
||||||
<FileBadge className="size-6" />
|
<FileBadge className="size-6" />
|
||||||
Visualizza la registrazione
|
Visualizza la registrazione
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -230,7 +227,7 @@ export const SaldoButton = ({
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
aria-label="Procedi al saldo"
|
aria-label="Procedi al saldo"
|
||||||
className={cn("flex w-fit items-center gap-2", className)}
|
className={cn("w-fit", className)}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
mutate({
|
mutate({
|
||||||
annuncioId,
|
annuncioId,
|
||||||
|
|
@ -271,7 +268,7 @@ const SaldoConsulenzaButton = ({
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
aria-label="Procedi al saldo consulenza"
|
aria-label="Procedi al saldo consulenza"
|
||||||
className={cn("flex w-fit items-center gap-2", className)}
|
className={cn("w-fit", className)}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
mutate({
|
mutate({
|
||||||
annuncioId,
|
annuncioId,
|
||||||
|
|
@ -311,10 +308,7 @@ const AnnuncioConfirm = () => {
|
||||||
return (
|
return (
|
||||||
<Credenza onOpenChange={setOpen} open={open}>
|
<Credenza onOpenChange={setOpen} open={open}>
|
||||||
<CredenzaTrigger asChild>
|
<CredenzaTrigger asChild>
|
||||||
<Button
|
<Button aria-label="Conferma immobile" className="w-fit">
|
||||||
aria-label="Conferma immobile"
|
|
||||||
className="flex w-fit items-center gap-2"
|
|
||||||
>
|
|
||||||
<Handshake className="size-6" /> Conferma immobile
|
<Handshake className="size-6" /> Conferma immobile
|
||||||
</Button>
|
</Button>
|
||||||
</CredenzaTrigger>
|
</CredenzaTrigger>
|
||||||
|
|
@ -356,10 +350,7 @@ const ConfermaLavorazioneModal = () => {
|
||||||
return (
|
return (
|
||||||
<Credenza>
|
<Credenza>
|
||||||
<CredenzaTrigger asChild>
|
<CredenzaTrigger asChild>
|
||||||
<Button
|
<Button aria-label="Conferma in lavorazione" className="w-fit">
|
||||||
aria-label="Conferma in lavorazione"
|
|
||||||
className="flex w-fit items-center gap-2"
|
|
||||||
>
|
|
||||||
<CircleCheck className="size-7" />
|
<CircleCheck className="size-7" />
|
||||||
Conferma in lavorazione
|
Conferma in lavorazione
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { add } from "date-fns";
|
||||||
import { Package, PackageCheck, UserCircle } from "lucide-react";
|
import { Package, PackageCheck, UserCircle } from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
|
@ -5,8 +6,7 @@ import { useEffect } from "react";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
import { AnnuncioCard } from "~/components/servizio/annuncio_card";
|
import { AnnuncioCard } from "~/components/servizio/annuncio_card";
|
||||||
import { SaldoButton } from "~/components/servizio/interactions";
|
import { SaldoButton } from "~/components/servizio/interactions";
|
||||||
import { ServizioDuration } from "~/components/servizio/service-duration-display";
|
import { ServizioActions } from "~/components/servizio/servizio_actions";
|
||||||
import { ServizioActions2 } from "~/components/servizio/servizio_actions";
|
|
||||||
import { Button } from "~/components/ui/button";
|
import { Button } from "~/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
|
|
@ -24,7 +24,8 @@ import {
|
||||||
import { api } from "~/utils/api";
|
import { api } from "~/utils/api";
|
||||||
import {
|
import {
|
||||||
AnnunciCompatibili,
|
AnnunciCompatibili,
|
||||||
AnnunciSelezionati,
|
AnnunciSelezionatiAccordion,
|
||||||
|
AnnunciSelezionatiDialog,
|
||||||
} from "./servizio_annunci_accordions";
|
} from "./servizio_annunci_accordions";
|
||||||
|
|
||||||
const ServizioCard = ({
|
const ServizioCard = ({
|
||||||
|
|
@ -42,7 +43,10 @@ const ServizioCard = ({
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
className={cn("gap-2 border-neutral-200 bg-neutral-200", cardClassName)}
|
className={cn(
|
||||||
|
"gap-2 rounded-md border-neutral-200 bg-neutral-200",
|
||||||
|
cardClassName,
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<CardHeader
|
<CardHeader
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|
@ -149,7 +153,7 @@ export const ServizioContent = () => {
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{isAdmin && <AnnunciSelezionati annunci={servizio.annunci} />}
|
{isAdmin && <AnnunciSelezionatiDialog annunci={servizio.annunci} />}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
header={
|
header={
|
||||||
|
|
@ -157,7 +161,7 @@ export const ServizioContent = () => {
|
||||||
<span className="text-foreground/70 text-lg">
|
<span className="text-foreground/70 text-lg">
|
||||||
Servizio non attivo
|
Servizio non attivo
|
||||||
</span>
|
</span>
|
||||||
<ServizioActions2 />
|
<ServizioActions />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
@ -183,7 +187,7 @@ export const ServizioContent = () => {
|
||||||
}
|
}
|
||||||
header={
|
header={
|
||||||
<>
|
<>
|
||||||
<ServizioActions2 />
|
<ServizioActions />
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
@ -192,7 +196,6 @@ export const ServizioContent = () => {
|
||||||
|
|
||||||
const openContattiAnnunci = servizio.annunci.filter(
|
const openContattiAnnunci = servizio.annunci.filter(
|
||||||
(a) => a.open_contatti_at !== null && a.user_confirmed_at === null,
|
(a) => a.open_contatti_at !== null && a.user_confirmed_at === null,
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const annunciInConferma = servizio.annunci.filter(
|
const annunciInConferma = servizio.annunci.filter(
|
||||||
|
|
@ -206,19 +209,27 @@ export const ServizioContent = () => {
|
||||||
<ServizioCard
|
<ServizioCard
|
||||||
content={
|
content={
|
||||||
<>
|
<>
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex w-full flex-col gap-4 sm:flex-row sm:gap-8">
|
||||||
|
<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 justify-between">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<UserCircle className="size-6 text-primary" />
|
<UserCircle className="size-6 text-primary" />
|
||||||
<span className="font-medium">Contatti sbloccati</span>
|
<span className="font-medium">Contatti sbloccati</span>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-sm">{openContattiAnnunci.length} / 10</span>
|
<span className="text-sm">
|
||||||
|
{openContattiAnnunci.length} / 10
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<Progress className="h-2" value={openContattiAnnunci.length * 10} />
|
<Progress
|
||||||
|
className="h-2"
|
||||||
|
value={openContattiAnnunci.length * 10}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span>
|
||||||
|
{`Durata servizio: ${new Date(servizio.decorrenza).toLocaleDateString("it-IT")} - ${new Date(add(servizio.decorrenza, { days: 60 })).toLocaleDateString("it-IT")}`}
|
||||||
|
</span>
|
||||||
|
{/* <ServizioDuration decorrenza={servizio.decorrenza} /> */}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ServizioDuration decorrenza={servizio.decorrenza} />
|
|
||||||
|
|
||||||
{annuncioConfermato.length > 0 && (
|
{annuncioConfermato.length > 0 && (
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
|
|
@ -256,15 +267,6 @@ export const ServizioContent = () => {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<div className="flex flex-col gap-2 overflow-y-auto">
|
|
||||||
{openContattiAnnunci.map((data) => {
|
|
||||||
return (
|
|
||||||
<ServizioAnnuncioProvider data={data} key={data.id}>
|
|
||||||
<AnnuncioCard className="border-2 border-green-500" />
|
|
||||||
</ServizioAnnuncioProvider>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-col gap-2 overflow-y-auto">
|
<div className="flex flex-col gap-2 overflow-y-auto">
|
||||||
{annunciInConferma.map((data) => {
|
{annunciInConferma.map((data) => {
|
||||||
return (
|
return (
|
||||||
|
|
@ -275,8 +277,8 @@ export const ServizioContent = () => {
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col items-center gap-4 sm:flex-row">
|
<AnnunciSelezionatiAccordion annunci={annunciNotInConferma} />
|
||||||
<AnnunciSelezionati annunci={annunciNotInConferma} />
|
<div className="flex items-center justify-center">
|
||||||
<AnnunciCompatibili />
|
<AnnunciCompatibili />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -284,7 +286,7 @@ export const ServizioContent = () => {
|
||||||
}
|
}
|
||||||
header={
|
header={
|
||||||
<>
|
<>
|
||||||
<ServizioActions2 />
|
<ServizioActions />
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -32,13 +32,19 @@ export const ContattiProprietarioModal = () => {
|
||||||
const { servizio } = useServizio();
|
const { servizio } = useServizio();
|
||||||
const { data } = useServizioAnnuncio();
|
const { data } = useServizioAnnuncio();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const isUnlocked = data.open_contatti_at != null;
|
||||||
|
const needsDocuments =
|
||||||
|
!servizio.skipControlloDoc &&
|
||||||
|
(!servizio.doc_personale_fronte || !servizio.doc_personale_retro);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Credenza>
|
<Credenza>
|
||||||
<CredenzaTrigger asChild>
|
<CredenzaTrigger asChild>
|
||||||
{data.open_contatti_at != null ? (
|
{data.open_contatti_at != null ? (
|
||||||
<Button
|
<Button
|
||||||
aria-label="Vedi contatti proprietario"
|
aria-label="Vedi contatti proprietario"
|
||||||
className="flex w-fit items-center gap-2"
|
className="w-fit"
|
||||||
variant="success"
|
variant="success"
|
||||||
>
|
>
|
||||||
<CircleUser className="size-7" />
|
<CircleUser className="size-7" />
|
||||||
|
|
@ -47,7 +53,7 @@ export const ContattiProprietarioModal = () => {
|
||||||
) : (
|
) : (
|
||||||
<Button
|
<Button
|
||||||
aria-label="Contatta proprietario"
|
aria-label="Contatta proprietario"
|
||||||
className="flex w-fit items-center gap-2"
|
className="w-fit"
|
||||||
variant="warning"
|
variant="warning"
|
||||||
>
|
>
|
||||||
<CircleUser className="size-7" />
|
<CircleUser className="size-7" />
|
||||||
|
|
@ -55,21 +61,19 @@ export const ContattiProprietarioModal = () => {
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</CredenzaTrigger>
|
</CredenzaTrigger>
|
||||||
<CredenzaContent className="max-h-[90vh]">
|
<CredenzaContent className="max-h-[90vh] sm:max-w-2xl">
|
||||||
<CredenzaHeader>
|
<CredenzaHeader>
|
||||||
<CredenzaTitle>{t.contatto.title}</CredenzaTitle>
|
<CredenzaTitle className="text-xl">{t.contatto.title}</CredenzaTitle>
|
||||||
<CredenzaDescription className="sr-only">
|
<CredenzaDescription className="sr-only">
|
||||||
{t.contatto.descrizione}
|
{t.contatto.descrizione}
|
||||||
</CredenzaDescription>
|
</CredenzaDescription>
|
||||||
</CredenzaHeader>
|
</CredenzaHeader>
|
||||||
{servizio.doc_personale_fronte == null ||
|
{needsDocuments ? (
|
||||||
servizio.doc_personale_retro == null ? (
|
|
||||||
<DocCheckpoint />
|
<DocCheckpoint />
|
||||||
// biome-ignore lint/style/noNestedTernary: <this is fine>
|
) : isUnlocked ? (
|
||||||
) : data.open_contatti_at == null ? (
|
|
||||||
<PreUnlock />
|
|
||||||
) : (
|
|
||||||
<PostUnlock />
|
<PostUnlock />
|
||||||
|
) : (
|
||||||
|
<PreUnlock />
|
||||||
)}
|
)}
|
||||||
</CredenzaContent>
|
</CredenzaContent>
|
||||||
</Credenza>
|
</Credenza>
|
||||||
|
|
@ -88,22 +92,30 @@ const DocComponent = ({
|
||||||
}) => {
|
}) => {
|
||||||
const { isAdmin, userId } = useServizio();
|
const { isAdmin, userId } = useServizio();
|
||||||
|
|
||||||
if (!docInfo?.storageId) {
|
if (docInfo?.storageId) {
|
||||||
return <UploadModal cb_onUpload={cb} isAdmin={isAdmin} userId={userId} />;
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-2 text-green-500">
|
<div className="flex items-center gap-2 text-green-500">
|
||||||
<CircleCheck className="size-5" />
|
<CircleCheck className="size-5" />
|
||||||
<span>Documento caricato</span>
|
<span>Documento caricato</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<UploadModal
|
||||||
|
cb_onUpload={cb}
|
||||||
|
isAdmin={isAdmin}
|
||||||
|
maxFiles={1}
|
||||||
|
userId={userId}
|
||||||
|
/>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const DocCheckpoint = () => {
|
const DocCheckpoint = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { userId, servizio } = useServizio();
|
const { userId, servizio } = useServizio();
|
||||||
const utils = api.useUtils();
|
const utils = api.useUtils();
|
||||||
const { mutate } = api.servizio.updateServizio.useMutation({
|
const { mutate, isPending } = api.servizio.updateServizio.useMutation({
|
||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
await utils.servizio.getAllServizioAnnunci.invalidate({
|
await utils.servizio.getAllServizioAnnunci.invalidate({
|
||||||
userId,
|
userId,
|
||||||
|
|
@ -117,37 +129,38 @@ const DocCheckpoint = () => {
|
||||||
toast.error(`Errore aggiornamento servizio: ${err.message}`);
|
toast.error(`Errore aggiornamento servizio: ${err.message}`);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
const handleUpload = (
|
||||||
|
field: "doc_personale_fronte_ref" | "doc_personale_retro_ref",
|
||||||
|
id: string,
|
||||||
|
) => {
|
||||||
|
mutate({
|
||||||
|
servizioId: servizio.servizio_id,
|
||||||
|
data: { [field]: id },
|
||||||
|
});
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CredenzaBody className="max-h-[80vh] overflow-auto pb-5">
|
<CredenzaBody className="max-h-[80vh] overflow-auto pb-5">
|
||||||
<div className="space-y-5">
|
<div className="space-y-5">
|
||||||
<p>Devi ancora caricare un tuo documento</p>
|
<p>Devi ancora caricare un tuo documento</p>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
Fronte documento:{" "}
|
<span>Fronte documento:</span>
|
||||||
<DocComponent
|
<DocComponent
|
||||||
cb={({ userStorageIds }) =>
|
cb={({ userStorageIds }) =>
|
||||||
userStorageIds.length > 0 &&
|
userStorageIds.length > 0 &&
|
||||||
mutate({
|
userStorageIds[0] &&
|
||||||
servizioId: servizio.servizio_id,
|
handleUpload("doc_personale_fronte_ref", userStorageIds[0])
|
||||||
data: {
|
|
||||||
doc_personale_fronte_ref: userStorageIds[0],
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
docInfo={servizio.doc_personale_fronte}
|
docInfo={servizio.doc_personale_fronte}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
Retro documento:{" "}
|
<span>Retro documento:</span>
|
||||||
<DocComponent
|
<DocComponent
|
||||||
cb={({ userStorageIds }) =>
|
cb={({ userStorageIds }) =>
|
||||||
userStorageIds.length > 0 &&
|
userStorageIds.length > 0 &&
|
||||||
mutate({
|
userStorageIds[0] &&
|
||||||
servizioId: servizio.servizio_id,
|
handleUpload("doc_personale_retro_ref", userStorageIds[0])
|
||||||
data: {
|
|
||||||
doc_personale_retro_ref: userStorageIds[0],
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
docInfo={servizio.doc_personale_retro}
|
docInfo={servizio.doc_personale_retro}
|
||||||
/>
|
/>
|
||||||
|
|
@ -166,7 +179,7 @@ const DocCheckpoint = () => {
|
||||||
</CredenzaBody>
|
</CredenzaBody>
|
||||||
<CredenzaFooter>
|
<CredenzaFooter>
|
||||||
<CredenzaClose asChild>
|
<CredenzaClose asChild>
|
||||||
<Button aria-label="Chiudi modal credenza" variant="outline">
|
<Button aria-label="Chiudi" disabled={isPending} variant="outline">
|
||||||
{t.chiudi}
|
{t.chiudi}
|
||||||
</Button>
|
</Button>
|
||||||
</CredenzaClose>
|
</CredenzaClose>
|
||||||
|
|
@ -182,7 +195,8 @@ const PreUnlock = () => {
|
||||||
|
|
||||||
const utils = api.useUtils();
|
const utils = api.useUtils();
|
||||||
|
|
||||||
const { mutate } = api.servizio.unlockServizioContatti.useMutation({
|
const { mutate, isPending } = api.servizio.unlockServizioContatti.useMutation(
|
||||||
|
{
|
||||||
onError: (err) => {
|
onError: (err) => {
|
||||||
toast.error(err.message, {
|
toast.error(err.message, {
|
||||||
id: "unlock-contacts",
|
id: "unlock-contacts",
|
||||||
|
|
@ -207,11 +221,11 @@ const PreUnlock = () => {
|
||||||
userId,
|
userId,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const d = new Date();
|
const currentHour = new Date().getHours();
|
||||||
const tooEarly = d.getHours() < 9;
|
const isOutsideBusinessHours = currentHour < 9 || currentHour >= 20;
|
||||||
const tooLate = d.getHours() >= 20;
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CredenzaBody className="max-h-[80vh] overflow-auto pb-5">
|
<CredenzaBody className="max-h-[80vh] overflow-auto pb-5">
|
||||||
|
|
@ -221,13 +235,12 @@ const PreUnlock = () => {
|
||||||
<p className="text-muted-foreground text-xs">
|
<p className="text-muted-foreground text-xs">
|
||||||
{t.contatto.disclaimer3}
|
{t.contatto.disclaimer3}
|
||||||
</p>
|
</p>
|
||||||
{(tooEarly || tooLate) && (
|
{isOutsideBusinessHours && (
|
||||||
<div className="flex items-center gap-2 rounded-md bg-yellow-200 p-2">
|
<div className="flex items-center gap-2 rounded-md bg-yellow-200 p-2">
|
||||||
<TriangleAlert className="size-8" />
|
<TriangleAlert className="size-8" />
|
||||||
{/*TODO testare */}
|
|
||||||
<p>
|
<p>
|
||||||
Il proprietario riceverà la notifica alle ore 9.00{" "}
|
Il proprietario riceverà la notifica alle ore 9.00{" "}
|
||||||
{tooLate && "di domani"}
|
{currentHour >= 20 && "di domani"}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
@ -236,6 +249,7 @@ const PreUnlock = () => {
|
||||||
<CredenzaFooter>
|
<CredenzaFooter>
|
||||||
<Button
|
<Button
|
||||||
aria-label="Contatta proprietario"
|
aria-label="Contatta proprietario"
|
||||||
|
disabled={isPending}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
mutate({
|
mutate({
|
||||||
annuncioId,
|
annuncioId,
|
||||||
|
|
@ -248,7 +262,11 @@ const PreUnlock = () => {
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<CredenzaClose asChild>
|
<CredenzaClose asChild>
|
||||||
<Button aria-label="Chiudi modal credenza" variant="outline">
|
<Button
|
||||||
|
aria-label="Chiudi modal credenza"
|
||||||
|
disabled={isPending}
|
||||||
|
variant="outline"
|
||||||
|
>
|
||||||
{t.chiudi}
|
{t.chiudi}
|
||||||
</Button>
|
</Button>
|
||||||
</CredenzaClose>
|
</CredenzaClose>
|
||||||
|
|
@ -258,18 +276,14 @@ const PreUnlock = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
function getNavigationUrl(lat: string, lon: string): string {
|
function getNavigationUrl(lat: string, lon: string): string {
|
||||||
if (typeof window !== "undefined") {
|
if (typeof window === "undefined") {
|
||||||
const isIOS =
|
|
||||||
navigator.userAgent.toUpperCase().includes("MAC") ||
|
|
||||||
navigator.userAgent.toUpperCase().includes("IPAD") ||
|
|
||||||
navigator.userAgent.toUpperCase().includes("IPHONE") ||
|
|
||||||
navigator.userAgent.toUpperCase().includes("IOS") ||
|
|
||||||
navigator.userAgent.toUpperCase().includes("IPOD");
|
|
||||||
|
|
||||||
return `${isIOS ? "maps" : "https"}://www.google.com/maps/dir/?api=1&travelmode=driving&layer=traffic&destination=${lat},${lon}`;
|
|
||||||
}
|
|
||||||
return `https://www.google.com/maps/dir/?api=1&travelmode=driving&layer=traffic&destination=${lat},${lon}`;
|
return `https://www.google.com/maps/dir/?api=1&travelmode=driving&layer=traffic&destination=${lat},${lon}`;
|
||||||
}
|
}
|
||||||
|
const isIOS = /iPad|iPhone|iPod|Mac/.test(navigator.userAgent);
|
||||||
|
const protocol = isIOS ? "maps" : "https";
|
||||||
|
|
||||||
|
return `${protocol}://www.google.com/maps/dir/?api=1&travelmode=driving&layer=traffic&destination=${lat},${lon}`;
|
||||||
|
}
|
||||||
|
|
||||||
const PostUnlock = () => {
|
const PostUnlock = () => {
|
||||||
const { servizioId } = useServizio();
|
const { servizioId } = useServizio();
|
||||||
|
|
@ -290,80 +304,86 @@ const PostUnlock = () => {
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
<div className="flex justify-center">
|
<CredenzaBody className="flex justify-center p-8">
|
||||||
<LoadingPage />
|
<LoadingPage />
|
||||||
</div>
|
</CredenzaBody>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (!data || !data.propData) {
|
if (!data || !data.propData) {
|
||||||
return <p>{t.contatto.error}</p>;
|
return (
|
||||||
|
<CredenzaBody>
|
||||||
|
<p className="text-destructive">{t.contatto.error}</p>
|
||||||
|
</CredenzaBody>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
const { opened_at, propData } = data;
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CredenzaBody className="max-h-[80vh] overflow-auto pb-5">
|
<CredenzaBody className="max-h-[80vh] overflow-auto pb-5 sm:max-w-xl">
|
||||||
<div className="flex flex-col gap-2">
|
<div className="space-y-10">
|
||||||
<h3 className="font-semibold">{t.contatto.propietario}:</h3>
|
{/* Proprietario Section */}
|
||||||
<p>
|
<section>
|
||||||
{t.contatto.nome}: {data.propData.locatore}
|
<h3 className="mb-2 font-semibold">{t.contatto.propietario}:</h3>
|
||||||
|
<p className="mb-2">
|
||||||
|
{t.contatto.nome}: {propData.locatore}
|
||||||
</p>
|
</p>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex flex-wrap items-center gap-5">
|
||||||
<a
|
<a
|
||||||
className="flex items-center gap-2"
|
className="flex items-center gap-2 text-blue-600 hover:underline"
|
||||||
href={`tel:${data.propData.numero}`}
|
href={`tel:${propData.numero}`}
|
||||||
>
|
>
|
||||||
<Phone />:
|
<Phone className="size-4" />
|
||||||
<span className="text-blue-600 underline">
|
<span>{propData.numero}</span>
|
||||||
{data.propData.numero}
|
|
||||||
</span>
|
|
||||||
</a>
|
</a>
|
||||||
<Link
|
<Link href={`https://wa.me/${propData.numero}`} target="_blank">
|
||||||
href={`https://wa.me/${data.propData.numero}`}
|
<Button size="sm" variant="success">
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
className="flex items-center gap-2"
|
|
||||||
size="sm"
|
|
||||||
variant="success"
|
|
||||||
>
|
|
||||||
<WhatsAppIcon2 className="size-4 fill-white" />
|
<WhatsAppIcon2 className="size-4 fill-white" />
|
||||||
WhatsApp
|
WhatsApp
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<br />
|
{/* Immobile Section */}
|
||||||
<h3 className="font-semibold">{t.contatto.immobile}:</h3>
|
<section>
|
||||||
<p>
|
<h3 className="mb-2 font-semibold">{t.contatto.immobile}:</h3>
|
||||||
{t.contatto.indirizzo}: {data.propData.indirizzo},{" "}
|
<p className="mb-2">
|
||||||
{data.propData.civico} {data.propData.comune} (
|
{t.contatto.indirizzo}: {propData.indirizzo}, {propData.civico}{" "}
|
||||||
{data.propData.provincia})
|
{propData.comune} ({propData.provincia})
|
||||||
</p>
|
</p>
|
||||||
|
{navigationUrl && (
|
||||||
<a
|
<a
|
||||||
className="flex w-fit items-center gap-2 rounded-md border border-border px-3 py-2"
|
className="inline-flex items-center gap-2 rounded-md border border-border px-3 py-2 hover:bg-accent"
|
||||||
href={navigationUrl}
|
href={navigationUrl}
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<Navigation /> <span>{t.contatto.apri_nav}</span>
|
<Navigation className="size-4" />
|
||||||
|
<span>{t.contatto.apri_nav}</span>
|
||||||
</a>
|
</a>
|
||||||
<br />
|
)}
|
||||||
<p>
|
</section>
|
||||||
|
|
||||||
|
{/* Warning */}
|
||||||
|
<div className="flex w-fit items-start gap-3 rounded-md bg-red-500 p-2 text-white">
|
||||||
|
<TriangleAlert className="size-6 shrink-0" />
|
||||||
|
<div className="space-y-1">
|
||||||
|
<p className="font-medium">{t.contatto.contatta}</p>
|
||||||
|
<p className="text-sm">{t.contatto.orari}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Metadata */}
|
||||||
|
<p className="text-muted-foreground text-sm">
|
||||||
{t.contatto.sbloccato_il}:{" "}
|
{t.contatto.sbloccato_il}:{" "}
|
||||||
{data.opened_at.toLocaleString("it", {
|
{opened_at.toLocaleString("it", {
|
||||||
day: "2-digit",
|
day: "2-digit",
|
||||||
hour: "2-digit",
|
|
||||||
minute: "2-digit",
|
|
||||||
month: "2-digit",
|
month: "2-digit",
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
})}
|
})}
|
||||||
</p>
|
</p>
|
||||||
<div className="flex items-center gap-2 rounded-md bg-red-500 p-2 text-white">
|
|
||||||
<TriangleAlert className="size-8" />
|
|
||||||
<div>
|
|
||||||
<p>{t.contatto.contatta}</p>
|
|
||||||
<p className="font-semibold">{t.contatto.orari}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</CredenzaBody>
|
</CredenzaBody>
|
||||||
<CredenzaFooter>
|
<CredenzaFooter>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { add } from "date-fns";
|
import { add } from "date-fns";
|
||||||
import { Bug, Calculator, ClockAlert, Plus, Wrench } from "lucide-react";
|
import { Bug, Calculator, ClockAlert, Plus, ShieldUser } from "lucide-react";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
import {
|
import {
|
||||||
|
|
@ -50,7 +50,7 @@ import type { ServizioServizioId } from "~/schemas/public/Servizio";
|
||||||
import type { UsersId } from "~/schemas/public/Users";
|
import type { UsersId } from "~/schemas/public/Users";
|
||||||
import { api } from "~/utils/api";
|
import { api } from "~/utils/api";
|
||||||
|
|
||||||
export const ServizioActions2 = () => {
|
export const ServizioActions = () => {
|
||||||
const { servizio, isAdmin, userId } = useServizio();
|
const { servizio, isAdmin, userId } = useServizio();
|
||||||
|
|
||||||
const canUserEdit =
|
const canUserEdit =
|
||||||
|
|
@ -65,7 +65,7 @@ export const ServizioActions2 = () => {
|
||||||
<div className="flex w-full flex-col flex-wrap justify-between gap-3 sm:flex-row">
|
<div className="flex w-full flex-col flex-wrap justify-between gap-3 sm:flex-row">
|
||||||
{(isAdmin || canUserEdit) && (
|
{(isAdmin || canUserEdit) && (
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<span className="hidden sm:block">Azioni: </span>
|
{/* <span className="hidden sm:block">Azioni: </span> */}
|
||||||
<EditPreferenze />
|
<EditPreferenze />
|
||||||
<InterruzioneServizio />
|
<InterruzioneServizio />
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -123,7 +123,7 @@ export const AddAnnuncio = ({
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
aria-label="Add Annuncio"
|
aria-label="Add Annuncio"
|
||||||
className="items-center gap-2"
|
className=""
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setSelectedAnnunci([]);
|
setSelectedAnnunci([]);
|
||||||
}}
|
}}
|
||||||
|
|
@ -222,11 +222,10 @@ const InterruzioneServizio = () => {
|
||||||
<AlertDialogTrigger asChild>
|
<AlertDialogTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
aria-label="Request Interruzione"
|
aria-label="Request Interruzione"
|
||||||
className="items-center gap-2"
|
className=""
|
||||||
disabled={!beforeInterruzioneLimit}
|
disabled={!beforeInterruzioneLimit}
|
||||||
variant="outline"
|
|
||||||
>
|
>
|
||||||
<ClockAlert /> <span>Interruzione</span>
|
<ClockAlert /> <span> Richiedi Interruzione Servizio</span>
|
||||||
</Button>
|
</Button>
|
||||||
</AlertDialogTrigger>
|
</AlertDialogTrigger>
|
||||||
<AlertDialogContent>
|
<AlertDialogContent>
|
||||||
|
|
@ -288,12 +287,9 @@ const EditPreferenze = () => {
|
||||||
return (
|
return (
|
||||||
<Credenza onOpenChange={setOpenEditPreferenze} open={openEditPreferenze}>
|
<Credenza onOpenChange={setOpenEditPreferenze} open={openEditPreferenze}>
|
||||||
<CredenzaTrigger asChild>
|
<CredenzaTrigger asChild>
|
||||||
<Button
|
<Button aria-label="Preferenze di ricerca" className="">
|
||||||
aria-label="Preferenze di ricerca"
|
|
||||||
className="items-center gap-2"
|
|
||||||
>
|
|
||||||
<Calculator />
|
<Calculator />
|
||||||
Preferenze
|
Modifica Preferenze
|
||||||
</Button>
|
</Button>
|
||||||
</CredenzaTrigger>
|
</CredenzaTrigger>
|
||||||
<CredenzaContent className="max-h-[90vh] w-full sm:max-w-5xl">
|
<CredenzaContent className="max-h-[90vh] w-full sm:max-w-5xl">
|
||||||
|
|
@ -352,11 +348,8 @@ const EditServizioAdmin = () => {
|
||||||
return (
|
return (
|
||||||
<Credenza onOpenChange={setOpen} open={open}>
|
<Credenza onOpenChange={setOpen} open={open}>
|
||||||
<CredenzaTrigger asChild>
|
<CredenzaTrigger asChild>
|
||||||
<Button
|
<Button aria-label="Modifica Servizio Admin">
|
||||||
aria-label="Modifica Servizio Admin"
|
<ShieldUser />
|
||||||
className="items-center gap-2"
|
|
||||||
>
|
|
||||||
<Wrench />
|
|
||||||
Admin
|
Admin
|
||||||
</Button>
|
</Button>
|
||||||
</CredenzaTrigger>
|
</CredenzaTrigger>
|
||||||
|
|
@ -375,7 +368,7 @@ const EditServizioAdmin = () => {
|
||||||
)}
|
)}
|
||||||
<Collapsible>
|
<Collapsible>
|
||||||
<CollapsibleTrigger asChild>
|
<CollapsibleTrigger asChild>
|
||||||
<Button className="items-center gap-2" variant="warning">
|
<Button variant="warning">
|
||||||
<Bug /> Debug Info Servizio
|
<Bug /> Debug Info Servizio
|
||||||
</Button>
|
</Button>
|
||||||
</CollapsibleTrigger>
|
</CollapsibleTrigger>
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ const DialogServizio = ({
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
export const AnnunciInConferma = ({
|
export const AnnunciInConfermaDialog = ({
|
||||||
annunci,
|
annunci,
|
||||||
}: {
|
}: {
|
||||||
annunci: ServizioData["annunci"];
|
annunci: ServizioData["annunci"];
|
||||||
|
|
@ -74,11 +74,10 @@ export const AnnunciInConferma = ({
|
||||||
>
|
>
|
||||||
Annunci in conferma
|
Annunci in conferma
|
||||||
</Button>
|
</Button>
|
||||||
{annunci.length > 0 && (
|
|
||||||
<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">
|
<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}
|
{annunci.length || 0}
|
||||||
</span>
|
</span>
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
@ -95,7 +94,7 @@ export const AnnunciInConferma = ({
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AnnunciSelezionati = ({
|
export const AnnunciSelezionatiDialog = ({
|
||||||
annunci,
|
annunci,
|
||||||
}: {
|
}: {
|
||||||
annunci: ServizioData["annunci"];
|
annunci: ServizioData["annunci"];
|
||||||
|
|
@ -112,11 +111,10 @@ export const AnnunciSelezionati = ({
|
||||||
>
|
>
|
||||||
Annunci selezionati
|
Annunci selezionati
|
||||||
</Button>
|
</Button>
|
||||||
{annunci.length > 0 && (
|
|
||||||
<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">
|
<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}
|
{annunci.length || 0}
|
||||||
</span>
|
</span>
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
@ -149,6 +147,79 @@ export const AnnunciSelezionati = ({
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const AnnunciInConfermaAccordion = ({
|
||||||
|
annunci,
|
||||||
|
}: {
|
||||||
|
annunci: ServizioData["annunci"];
|
||||||
|
}) => {
|
||||||
|
if (annunci.length === 0) {
|
||||||
|
return null; // If there are no announcements in confirmation, do not render this section
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Accordion collapsible defaultValue="in-conferma" type="single">
|
||||||
|
<AccordionItem className="space-y-4" value="in-conferma">
|
||||||
|
<AccordionTrigger className="rounded-md border-2 border-green-500 bg-white p-2">
|
||||||
|
Annunci in conferma:
|
||||||
|
</AccordionTrigger>
|
||||||
|
<AccordionContent>
|
||||||
|
<div className="flex flex-col flex-wrap gap-5">
|
||||||
|
{annunci.map((data) => {
|
||||||
|
return (
|
||||||
|
<ServizioAnnuncioProvider data={data} key={data.id}>
|
||||||
|
<AnnuncioCard className="border-2 border-green-500" />
|
||||||
|
</ServizioAnnuncioProvider>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
</Accordion>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const AnnunciSelezionatiAccordion = ({
|
||||||
|
annunci,
|
||||||
|
}: {
|
||||||
|
annunci: ServizioData["annunci"];
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<Accordion collapsible defaultValue="open" type="single">
|
||||||
|
<AccordionItem className="space-y-4" value="open">
|
||||||
|
<AccordionTrigger className="cursor-pointer rounded-md border-2 border-sky-500 bg-white p-2">
|
||||||
|
Annunci Selezionati:
|
||||||
|
</AccordionTrigger>
|
||||||
|
<AccordionContent>
|
||||||
|
<div className="flex flex-col flex-wrap gap-5">
|
||||||
|
{annunci.length > 0 ? (
|
||||||
|
annunci.map((data) => {
|
||||||
|
return (
|
||||||
|
<ServizioAnnuncioProvider data={data} key={data.id}>
|
||||||
|
<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>
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
</Accordion>
|
||||||
|
);
|
||||||
|
};
|
||||||
export const AnnunciCompatibili = () => {
|
export const AnnunciCompatibili = () => {
|
||||||
const { servizioId, userId, isAdmin } = useServizio();
|
const { servizioId, userId, isAdmin } = useServizio();
|
||||||
const { data, isLoading } = api.servizio.getCompatibileAnnunci.useQuery({
|
const { data, isLoading } = api.servizio.getCompatibileAnnunci.useQuery({
|
||||||
|
|
@ -163,16 +234,9 @@ export const AnnunciCompatibili = () => {
|
||||||
<DialogServizio
|
<DialogServizio
|
||||||
title="Annunci compatibili"
|
title="Annunci compatibili"
|
||||||
trigger={
|
trigger={
|
||||||
<div className="relative flex w-full sm:w-fit">
|
<Button className="w-full bg-purple-500 sm:w-fit">
|
||||||
<Button className="w-full bg-purple-500 text-lg sm:w-fit" size="xl">
|
Esplora Annunci Compatibili
|
||||||
Annunci compatibili
|
|
||||||
</Button>
|
</Button>
|
||||||
{data && data.length > 0 && (
|
|
||||||
<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">
|
|
||||||
{data?.length}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className="flex max-h-[80vh] flex-col gap-2 overflow-y-auto">
|
<div className="flex max-h-[80vh] flex-col gap-2 overflow-y-auto">
|
||||||
|
|
@ -254,7 +318,6 @@ export const AnnunciRichiesti = ({ userId }: { userId: UsersId }) => {
|
||||||
data={a}
|
data={a}
|
||||||
interactions={
|
interactions={
|
||||||
<Button
|
<Button
|
||||||
className="flex items-center gap-2"
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
deleteAnnuncio({ annuncioId: a.id, userId });
|
deleteAnnuncio({ annuncioId: a.id, userId });
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -51,11 +51,7 @@ export const AnnunciTable = ({
|
||||||
href={`/area-riservata/admin/edit-annuncio/${row.original.id}`}
|
href={`/area-riservata/admin/edit-annuncio/${row.original.id}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<Button
|
<Button className="px-2" size="sm" variant="default">
|
||||||
className="flex items-center gap-2 px-2"
|
|
||||||
size="sm"
|
|
||||||
variant="default"
|
|
||||||
>
|
|
||||||
<Wrench />
|
<Wrench />
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
||||||
|
|
@ -166,7 +166,6 @@ export const OrdiniTable = ({ data, isAdmin, userId }: PaymentsTableProps) => {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
aria-label="Apri Dettagli Ordine"
|
aria-label="Apri Dettagli Ordine"
|
||||||
className="flex items-center gap-2"
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setSelectedOrdine(row.original.id);
|
setSelectedOrdine(row.original.id);
|
||||||
setModalOpen(true);
|
setModalOpen(true);
|
||||||
|
|
|
||||||
|
|
@ -33,17 +33,7 @@ export type UploadCallback = (args: {
|
||||||
userStorageIds: UsersStorageUserStorageId[];
|
userStorageIds: UsersStorageUserStorageId[];
|
||||||
}) => void;
|
}) => void;
|
||||||
|
|
||||||
type UploadModalProps = {
|
export const UploadModal = (props: UploadComponentProps) => {
|
||||||
cb_onUpload?: UploadCallback;
|
|
||||||
isAdmin?: boolean;
|
|
||||||
userId?: UsersId;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const UploadModal = ({
|
|
||||||
cb_onUpload,
|
|
||||||
isAdmin,
|
|
||||||
userId,
|
|
||||||
}: UploadModalProps) => {
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -63,11 +53,7 @@ export const UploadModal = ({
|
||||||
</CredenzaDescription>
|
</CredenzaDescription>
|
||||||
</CredenzaHeader>
|
</CredenzaHeader>
|
||||||
<CredenzaBody className="max-h-[80vh] overflow-auto pb-5">
|
<CredenzaBody className="max-h-[80vh] overflow-auto pb-5">
|
||||||
<UploadComponent
|
<UploadComponent {...props} />
|
||||||
cb_onUpload={cb_onUpload}
|
|
||||||
isAdmin={isAdmin}
|
|
||||||
userId={userId}
|
|
||||||
/>
|
|
||||||
</CredenzaBody>
|
</CredenzaBody>
|
||||||
</CredenzaContent>
|
</CredenzaContent>
|
||||||
</Credenza>
|
</Credenza>
|
||||||
|
|
|
||||||
|
|
@ -246,12 +246,7 @@ export const AnnuncioEditForm = ({ data }: { data: AnnunciWithImages }) => {
|
||||||
|
|
||||||
<div className="flex flex-wrap items-center gap-2">
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
<Link href={`/annuncio/${data.codice}`} target="_blank">
|
<Link href={`/annuncio/${data.codice}`} target="_blank">
|
||||||
<Button
|
<Button size="sm" type="button" variant="outline">
|
||||||
className="flex items-center gap-2"
|
|
||||||
size="sm"
|
|
||||||
type="button"
|
|
||||||
variant="outline"
|
|
||||||
>
|
|
||||||
<Eye /> pubblica
|
<Eye /> pubblica
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
@ -259,28 +254,19 @@ export const AnnuncioEditForm = ({ data }: { data: AnnunciWithImages }) => {
|
||||||
href={`/area-riservata/admin/scheda-annuncio-stampa/${data.id}`}
|
href={`/area-riservata/admin/scheda-annuncio-stampa/${data.id}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<Button
|
<Button size="sm" type="button" variant="outline">
|
||||||
className="flex items-center gap-2"
|
|
||||||
size="sm"
|
|
||||||
type="button"
|
|
||||||
variant="outline"
|
|
||||||
>
|
|
||||||
<Printer /> Scheda
|
<Printer /> Scheda
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
<Popover>
|
<Popover>
|
||||||
<PopoverTrigger asChild>
|
<PopoverTrigger asChild>
|
||||||
<Button
|
<Button size="sm" type="button">
|
||||||
className="flex items-center gap-2"
|
|
||||||
size="sm"
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<CodeSquare /> Strumenti
|
<CodeSquare /> Strumenti
|
||||||
</Button>
|
</Button>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent className="flex w-fit items-center gap-2">
|
<PopoverContent className="flex w-fit items-center gap-2">
|
||||||
<Button
|
<Button
|
||||||
className="flex items-center gap-2 bg-purple-500"
|
className="bg-purple-500"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
await revalidate({
|
await revalidate({
|
||||||
cod: data.codice,
|
cod: data.codice,
|
||||||
|
|
@ -298,12 +284,7 @@ export const AnnuncioEditForm = ({ data }: { data: AnnunciWithImages }) => {
|
||||||
}}
|
}}
|
||||||
title="Aggiornamento Annuncio"
|
title="Aggiornamento Annuncio"
|
||||||
>
|
>
|
||||||
<Button
|
<Button size="sm" type="button" variant="warning">
|
||||||
className="flex items-center gap-2"
|
|
||||||
size="sm"
|
|
||||||
type="button"
|
|
||||||
variant="warning"
|
|
||||||
>
|
|
||||||
<TriangleAlert /> Aggiorna
|
<TriangleAlert /> Aggiorna
|
||||||
</Button>
|
</Button>
|
||||||
</Confirm>
|
</Confirm>
|
||||||
|
|
|
||||||
|
|
@ -182,7 +182,6 @@ export const FormEditServizio = ({
|
||||||
<div className="flex flex-col items-start gap-2">
|
<div className="flex flex-col items-start gap-2">
|
||||||
<Label htmlFor="reset_decorrenza">Reset Decorrenza</Label>
|
<Label htmlFor="reset_decorrenza">Reset Decorrenza</Label>
|
||||||
<Button
|
<Button
|
||||||
className="flex items-center gap-2"
|
|
||||||
id="reset_decorrenza"
|
id="reset_decorrenza"
|
||||||
onClick={() => form.setValue("decorrenza", null)}
|
onClick={() => form.setValue("decorrenza", null)}
|
||||||
type="button"
|
type="button"
|
||||||
|
|
|
||||||
|
|
@ -233,10 +233,7 @@ export const FormNewServizioAcquisto = ({
|
||||||
path: ["n_adulti"],
|
path: ["n_adulti"],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (
|
if (!permanenza && tipologia === TipologiaPosizioneEnum.Transitorio) {
|
||||||
permanenza === null &&
|
|
||||||
tipologia === TipologiaPosizioneEnum.Transitorio
|
|
||||||
) {
|
|
||||||
refinementContext.issues.push({
|
refinementContext.issues.push({
|
||||||
code: "custom",
|
code: "custom",
|
||||||
input: "",
|
input: "",
|
||||||
|
|
@ -264,6 +261,14 @@ export const FormNewServizioAcquisto = ({
|
||||||
path: ["scadenza_motivazione_transitoria"],
|
path: ["scadenza_motivazione_transitoria"],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (!permanenza) {
|
||||||
|
refinementContext.issues.push({
|
||||||
|
code: "custom",
|
||||||
|
input: "",
|
||||||
|
message: "Inserisci permanenza",
|
||||||
|
path: ["permanenza"],
|
||||||
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (reddito === "" || reddito === null) {
|
if (reddito === "" || reddito === null) {
|
||||||
refinementContext.issues.push({
|
refinementContext.issues.push({
|
||||||
|
|
@ -315,7 +320,7 @@ export const FormNewServizioAcquisto = ({
|
||||||
defaultValues: defaultValues,
|
defaultValues: defaultValues,
|
||||||
});
|
});
|
||||||
const DatePickerLocale = locale === "it" ? it : enUS;
|
const DatePickerLocale = locale === "it" ? it : enUS;
|
||||||
const { mutate } = api.servizio.postAcquistoData.useMutation({
|
const { mutate } = api.servizio.submitOnboardForPurchase.useMutation({
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
toast.error(`Errore invio dati: ${error.message}`, {
|
toast.error(`Errore invio dati: ${error.message}`, {
|
||||||
id: "salvataggio",
|
id: "salvataggio",
|
||||||
|
|
@ -424,7 +429,7 @@ export const FormNewServizioAcquisto = ({
|
||||||
fattura: "Vuoi che la fatturazione sia intestata alla tua azienda?",
|
fattura: "Vuoi che la fatturazione sia intestata alla tua azienda?",
|
||||||
personali: "Dati personali",
|
personali: "Dati personali",
|
||||||
personali_desc: "Inserisci i tuoi dati personali",
|
personali_desc: "Inserisci i tuoi dati personali",
|
||||||
salva: "Salva e procedi al pagamento",
|
salva: "Salva e procedi",
|
||||||
sdi: "Codice destinatario SDI",
|
sdi: "Codice destinatario SDI",
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
|
|
@ -433,7 +438,7 @@ export const FormNewServizioAcquisto = ({
|
||||||
fattura: "Do you want the invoice to be issued to your company?",
|
fattura: "Do you want the invoice to be issued to your company?",
|
||||||
personali: "Personal Data",
|
personali: "Personal Data",
|
||||||
personali_desc: "Enter your personal data",
|
personali_desc: "Enter your personal data",
|
||||||
salva: "Save and proceed to payment",
|
salva: "Save and proceed",
|
||||||
sdi: "SDI Recipient Code",
|
sdi: "SDI Recipient Code",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -694,7 +699,7 @@ export const FormNewServizioAcquisto = ({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{tipologia === TipologiaPosizioneEnum.Transitorio ? (
|
{tipologia === TipologiaPosizioneEnum.Transitorio ? (
|
||||||
<>
|
<div className="items-top flex w-full flex-col justify-between gap-4 sm:flex-row">
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
key={tipologia}
|
key={tipologia}
|
||||||
|
|
@ -704,10 +709,9 @@ export const FormNewServizioAcquisto = ({
|
||||||
t.preferenze.motivazioni_mappings.find(
|
t.preferenze.motivazioni_mappings.find(
|
||||||
(m) => m.id === field.value,
|
(m) => m.id === field.value,
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormItem>
|
<FormItem className="w-full">
|
||||||
<div className="flex flex-wrap items-center gap-x-2">
|
<div className="flex w-full flex-wrap items-center gap-x-2">
|
||||||
<FormLabel htmlFor="motivazione_transitorio">
|
<FormLabel htmlFor="motivazione_transitorio">
|
||||||
{t.preferenze.motivazione_label}
|
{t.preferenze.motivazione_label}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
|
|
@ -736,7 +740,6 @@ export const FormNewServizioAcquisto = ({
|
||||||
)}
|
)}
|
||||||
placeholder={t.seleziona_placeholder}
|
placeholder={t.seleziona_placeholder}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FormDescription>
|
<FormDescription>
|
||||||
{t.preferenze.motivazione_desc}
|
{t.preferenze.motivazione_desc}
|
||||||
</FormDescription>
|
</FormDescription>
|
||||||
|
|
@ -794,7 +797,7 @@ export const FormNewServizioAcquisto = ({
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ const Annunci = ({ options }: AnnunciPageProps) => {
|
||||||
<meta content={t.heads.annunci_description} name="description" />
|
<meta content={t.heads.annunci_description} name="description" />
|
||||||
</Head>
|
</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-7xl space-y-5 bg-background2 px-2 py-5 md:px-8">
|
||||||
<div className="inline-block rounded-md bg-primary/10 px-3 py-1 text-primary text-sm">
|
<div className="inline-block rounded-md bg-primary/10 px-3 py-1 text-primary text-sm">
|
||||||
{t.annunci.titolo}
|
{t.annunci.titolo}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,7 @@ const AnnuncioView = ({ cod, flag }: Omit<AnnuncioProps, "meta">) => {
|
||||||
href={`/area-riservata/admin/edit-annuncio/${data.id}`}
|
href={`/area-riservata/admin/edit-annuncio/${data.id}`}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
className="flex w-full items-center gap-2"
|
className="w-full"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<Edit /> Modifica annuncio
|
<Edit /> Modifica annuncio
|
||||||
|
|
@ -162,7 +162,7 @@ const AnnuncioView = ({ cod, flag }: Omit<AnnuncioProps, "meta">) => {
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
className="flex w-full items-center gap-2"
|
className="w-full"
|
||||||
type="button"
|
type="button"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
>
|
>
|
||||||
|
|
@ -669,7 +669,7 @@ const AnnuncioFooter = ({
|
||||||
}}
|
}}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<Button className="my-10 flex w-full items-center gap-2 bg-neutral-500 text-xl">
|
<Button className="my-10 w-full bg-neutral-500 text-xl">
|
||||||
Cerca annunci simili <ExternalLink className="size-6" />
|
Cerca annunci simili <ExternalLink className="size-6" />
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
||||||
|
|
@ -53,17 +53,13 @@ const Admin_Annunci: NextPageWithLayout = () => {
|
||||||
</button>
|
</button>
|
||||||
<Popover>
|
<Popover>
|
||||||
<PopoverTrigger asChild>
|
<PopoverTrigger asChild>
|
||||||
<Button
|
<Button size="sm" type="button">
|
||||||
className="flex items-center gap-2"
|
|
||||||
size="sm"
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<CodeSquare /> Strumenti avanzati
|
<CodeSquare /> Strumenti avanzati
|
||||||
</Button>
|
</Button>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent className="flex flex-col items-center gap-2">
|
<PopoverContent className="flex flex-col items-center gap-2">
|
||||||
<Button
|
<Button
|
||||||
className="flex items-center gap-2 bg-purple-500"
|
className="bg-purple-500"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
await revalidate();
|
await revalidate();
|
||||||
}}
|
}}
|
||||||
|
|
@ -79,12 +75,7 @@ const Admin_Annunci: NextPageWithLayout = () => {
|
||||||
}}
|
}}
|
||||||
title="Aggiornamento Annunci"
|
title="Aggiornamento Annunci"
|
||||||
>
|
>
|
||||||
<Button
|
<Button size="sm" type="button" variant="warning">
|
||||||
className="flex items-center gap-2"
|
|
||||||
size="sm"
|
|
||||||
type="button"
|
|
||||||
variant="warning"
|
|
||||||
>
|
|
||||||
<TriangleAlert /> Aggiorna tutti gli annunci
|
<TriangleAlert /> Aggiorna tutti gli annunci
|
||||||
</Button>
|
</Button>
|
||||||
</Confirm>
|
</Confirm>
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ const AdminBanners: NextPageWithLayout = () => {
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-3 md:mt-0">
|
<div className="mt-3 md:mt-0">
|
||||||
<Button
|
<Button
|
||||||
className="flex items-center gap-2 font-semibold"
|
className="font-semibold"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleEdit(null);
|
handleEdit(null);
|
||||||
handleOpen(true);
|
handleOpen(true);
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ const AdminBlacklist: NextPageWithLayout = () => {
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-3 md:mt-0">
|
<div className="mt-3 md:mt-0">
|
||||||
<Button
|
<Button
|
||||||
className="flex items-center gap-2 font-semibold"
|
className="font-semibold"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleEdit(null);
|
handleEdit(null);
|
||||||
handleOpen(true);
|
handleOpen(true);
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ const AdminEtichette: NextPageWithLayout = () => {
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-3 md:mt-0">
|
<div className="mt-3 md:mt-0">
|
||||||
<Button
|
<Button
|
||||||
className="flex items-center gap-2 font-semibold"
|
className="font-semibold"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleEdit(null);
|
handleEdit(null);
|
||||||
handleOpen(true);
|
handleOpen(true);
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ const AdminFlags: NextPageWithLayout = () => {
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-3 md:mt-0">
|
<div className="mt-3 md:mt-0">
|
||||||
<Button
|
<Button
|
||||||
className="flex items-center gap-2 font-semibold"
|
className="font-semibold"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleEdit(null);
|
handleEdit(null);
|
||||||
handleOpen(true);
|
handleOpen(true);
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ const AdminTestiStringhe: NextPageWithLayout = () => {
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-3 md:mt-0">
|
<div className="mt-3 md:mt-0">
|
||||||
<Button
|
<Button
|
||||||
className="flex items-center gap-2 font-semibold"
|
className="font-semibold"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleEdit(null);
|
handleEdit(null);
|
||||||
handleOpen(true);
|
handleOpen(true);
|
||||||
|
|
|
||||||
|
|
@ -125,10 +125,7 @@ const EditUser: NextPageWithLayout<EditUserProps> = ({
|
||||||
<div className="flex flex-wrap items-end gap-2">
|
<div className="flex flex-wrap items-end gap-2">
|
||||||
<AlertDialog>
|
<AlertDialog>
|
||||||
<AlertDialogTrigger asChild>
|
<AlertDialogTrigger asChild>
|
||||||
<Button
|
<Button variant={userData.isBlocked ? "success" : "orange"}>
|
||||||
className="flex items-center gap-2"
|
|
||||||
variant={userData.isBlocked ? "success" : "orange"}
|
|
||||||
>
|
|
||||||
{userData.isBlocked ? (
|
{userData.isBlocked ? (
|
||||||
<>
|
<>
|
||||||
<Unlock className="size-4" />
|
<Unlock className="size-4" />
|
||||||
|
|
@ -161,10 +158,7 @@ const EditUser: NextPageWithLayout<EditUserProps> = ({
|
||||||
</AlertDialog>
|
</AlertDialog>
|
||||||
<AlertDialog>
|
<AlertDialog>
|
||||||
<AlertDialogTrigger asChild>
|
<AlertDialogTrigger asChild>
|
||||||
<Button
|
<Button variant="destructive">
|
||||||
className="flex items-center gap-2"
|
|
||||||
variant="destructive"
|
|
||||||
>
|
|
||||||
<Trash2 className="size-4" /> Elimina utente permanentemente
|
<Trash2 className="size-4" /> Elimina utente permanentemente
|
||||||
</Button>
|
</Button>
|
||||||
</AlertDialogTrigger>
|
</AlertDialogTrigger>
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ const PreOnboardServizio: NextPageWithLayout<PreOnboardServizioProps> = ({
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<Button
|
<Button
|
||||||
className="flex items-center gap-2 text-xl"
|
className="text-xl"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
if (data.hasPrevious) {
|
if (data.hasPrevious) {
|
||||||
await router.push({
|
await router.push({
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ const RiapriConferma: NextPageWithLayout<RiapriConfermaProps> = ({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
className="mx-auto mb-4 flex items-center gap-2"
|
className="mx-auto mb-4"
|
||||||
onClick={() => router.back()}
|
onClick={() => router.back()}
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -250,7 +250,7 @@ export const servizioRouter = createTRPCRouter({
|
||||||
return await isOrdineAwaitingPayment(input.ordineId);
|
return await isOrdineAwaitingPayment(input.ordineId);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
postAcquistoData: protectedProcedure
|
submitOnboardForPurchase: protectedProcedure
|
||||||
.input(
|
.input(
|
||||||
z.object({
|
z.object({
|
||||||
anagrafica: z.custom<UsersAnagraficaUpdate>(),
|
anagrafica: z.custom<UsersAnagraficaUpdate>(),
|
||||||
|
|
|
||||||
|
|
@ -247,6 +247,7 @@ export const postAcquistoDataHandler = async ({
|
||||||
}) => {
|
}) => {
|
||||||
try {
|
try {
|
||||||
const servizioData = await db.transaction().execute(async (tx) => {
|
const servizioData = await db.transaction().execute(async (tx) => {
|
||||||
|
// Update user and anagrafica data
|
||||||
await tx
|
await tx
|
||||||
.updateTable("users")
|
.updateTable("users")
|
||||||
.set(user)
|
.set(user)
|
||||||
|
|
@ -274,13 +275,7 @@ export const postAcquistoDataHandler = async ({
|
||||||
.returningAll()
|
.returningAll()
|
||||||
.executeTakeFirstOrThrow();
|
.executeTakeFirstOrThrow();
|
||||||
}
|
}
|
||||||
|
// Update servizio data
|
||||||
await tx
|
|
||||||
.updateTable("users_anagrafica")
|
|
||||||
.set(anagrafica)
|
|
||||||
.where("userid", "=", userId)
|
|
||||||
.executeTakeFirstOrThrow();
|
|
||||||
|
|
||||||
return await tx
|
return await tx
|
||||||
.updateTable("servizio")
|
.updateTable("servizio")
|
||||||
.set(servizio)
|
.set(servizio)
|
||||||
|
|
@ -290,6 +285,7 @@ export const postAcquistoDataHandler = async ({
|
||||||
});
|
});
|
||||||
|
|
||||||
if (skipOrdine) {
|
if (skipOrdine) {
|
||||||
|
// If skipping order, set servizio as active with decorrenza today
|
||||||
await updateServizio({
|
await updateServizio({
|
||||||
data: {
|
data: {
|
||||||
decorrenza: new Date(),
|
decorrenza: new Date(),
|
||||||
|
|
@ -627,6 +623,9 @@ export const getAllServizioAnnunci = async (userId: UsersId) => {
|
||||||
"servizio.isOkAcconto",
|
"servizio.isOkAcconto",
|
||||||
"servizio.isOkSaldo",
|
"servizio.isOkSaldo",
|
||||||
"servizio.isOkConsulenza",
|
"servizio.isOkConsulenza",
|
||||||
|
"servizio.skipPayment",
|
||||||
|
"servizio.skipControlloDoc",
|
||||||
|
"servizio.skipDocMotivazione",
|
||||||
jsonObjectFrom(
|
jsonObjectFrom(
|
||||||
eb
|
eb
|
||||||
.selectFrom("users_storage")
|
.selectFrom("users_storage")
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@
|
||||||
--radius-lg: var(--radius);
|
--radius-lg: var(--radius);
|
||||||
--radius-xl: calc(var(--radius) + 4px);
|
--radius-xl: calc(var(--radius) + 4px);
|
||||||
--color-background: var(--background);
|
--color-background: var(--background);
|
||||||
|
--color-background2: var(--background2);
|
||||||
--color-foreground: var(--foreground);
|
--color-foreground: var(--foreground);
|
||||||
--color-card: var(--card);
|
--color-card: var(--card);
|
||||||
--color-card-foreground: var(--card-foreground);
|
--color-card-foreground: var(--card-foreground);
|
||||||
|
|
@ -171,6 +172,7 @@
|
||||||
:root {
|
:root {
|
||||||
--radius: 0.625rem;
|
--radius: 0.625rem;
|
||||||
--background: oklch(1 0 0);
|
--background: oklch(1 0 0);
|
||||||
|
--background2: oklch(95.041% 0.02791 62.217);
|
||||||
--foreground: oklch(0.145 0 0);
|
--foreground: oklch(0.145 0 0);
|
||||||
--card: oklch(1 0 0);
|
--card: oklch(1 0 0);
|
||||||
--card-foreground: oklch(0.145 0 0);
|
--card-foreground: oklch(0.145 0 0);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue