2025-08-28 18:27:07 +02:00
|
|
|
import {
|
|
|
|
|
ExternalLink,
|
|
|
|
|
Mail,
|
|
|
|
|
MessagesSquare,
|
|
|
|
|
Paperclip,
|
|
|
|
|
Search,
|
|
|
|
|
ShoppingBag,
|
|
|
|
|
Tickets,
|
|
|
|
|
UserCog,
|
|
|
|
|
} from "lucide-react";
|
|
|
|
|
import Head from "next/head";
|
|
|
|
|
import Link from "next/link";
|
|
|
|
|
import { usePathname } from "next/navigation";
|
|
|
|
|
import { useRouter } from "next/router";
|
|
|
|
|
import { type ReactNode, useContext } from "react";
|
|
|
|
|
import toast from "react-hot-toast";
|
|
|
|
|
import { Sidebar } from "~/components/area-riservata/sidebar";
|
2025-08-04 17:45:44 +02:00
|
|
|
import { BannerFactory } from "~/components/banners";
|
|
|
|
|
import { Footer, MiniFooter } from "~/components/footer";
|
2025-08-28 18:27:07 +02:00
|
|
|
import { LoadingPage } from "~/components/loading";
|
2025-08-04 17:45:44 +02:00
|
|
|
import { SiteHeader } from "~/components/navbar/site-header";
|
2025-10-16 10:28:24 +02:00
|
|
|
import { WhatsAppIcon2 } from "~/components/svgs";
|
2025-08-04 17:45:44 +02:00
|
|
|
import { Button } from "~/components/ui/button";
|
|
|
|
|
import { Separator } from "~/components/ui/separator";
|
2025-08-28 18:27:07 +02:00
|
|
|
import { UserViewContext, UserViewProvider } from "~/lib/userViewContext";
|
|
|
|
|
import { useTranslation } from "~/providers/I18nProvider";
|
2025-08-20 14:04:23 +02:00
|
|
|
import {
|
2025-08-28 18:27:07 +02:00
|
|
|
EnforcedSessionContext,
|
|
|
|
|
useSession,
|
2025-08-20 14:04:23 +02:00
|
|
|
} from "~/providers/SessionProvider";
|
2025-08-28 18:27:07 +02:00
|
|
|
import type { UsersId } from "~/schemas/public/Users";
|
2025-08-20 14:04:23 +02:00
|
|
|
import type { ValidSession } from "~/server/api/trpc";
|
2025-08-28 18:27:07 +02:00
|
|
|
import { api } from "~/utils/api";
|
2025-08-04 17:45:44 +02:00
|
|
|
|
|
|
|
|
interface Props {
|
2025-08-28 18:27:07 +02:00
|
|
|
children: ReactNode;
|
|
|
|
|
noFooter?: boolean;
|
2025-08-04 17:45:44 +02:00
|
|
|
}
|
|
|
|
|
export const Layout = ({ children, noFooter }: Props) => {
|
2025-08-28 18:27:07 +02:00
|
|
|
const { data: bannerData } = api.settings.getBannerData.useQuery({
|
|
|
|
|
area_riservata: false,
|
|
|
|
|
});
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
return (
|
|
|
|
|
<div className="flex min-h-screen w-full flex-col">
|
|
|
|
|
<SiteHeader />
|
|
|
|
|
{bannerData?.map((banner) => (
|
|
|
|
|
<div key={`banner-elem-${banner.idbanner}`}>
|
|
|
|
|
{BannerFactory(banner)}
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
<main className="h-full flex-1 grow">{children}</main>
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
{!noFooter && <Footer />}
|
|
|
|
|
{/* <CookieConsent /> */}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
2025-08-04 17:45:44 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const AreaRiservataLayout = ({
|
2025-08-28 18:27:07 +02:00
|
|
|
children,
|
|
|
|
|
noSidebar,
|
|
|
|
|
noFooter,
|
|
|
|
|
ignoreSessionCheck,
|
2025-08-04 17:45:44 +02:00
|
|
|
}: {
|
2025-08-28 18:27:07 +02:00
|
|
|
children: ReactNode;
|
|
|
|
|
noSidebar?: boolean;
|
|
|
|
|
noFooter?: boolean;
|
|
|
|
|
ignoreSessionCheck?: boolean;
|
2025-08-04 17:45:44 +02:00
|
|
|
}) => {
|
2025-08-28 18:27:07 +02:00
|
|
|
const { data: bannerData } = api.settings.getBannerData.useQuery({
|
|
|
|
|
area_riservata: true,
|
|
|
|
|
});
|
|
|
|
|
const session = useSession();
|
|
|
|
|
if (!ignoreSessionCheck) {
|
|
|
|
|
if (session.status === "pending")
|
|
|
|
|
return (
|
|
|
|
|
<div className="flex h-full min-h-screen flex-col text-clip">
|
|
|
|
|
<SiteHeader />
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
<main className="flex h-full flex-1 overflow-auto">
|
|
|
|
|
<div className="flex h-auto w-full flex-col md:flex-row">
|
|
|
|
|
<LoadingPage />
|
|
|
|
|
</div>
|
|
|
|
|
</main>
|
|
|
|
|
{!noFooter && <MiniFooter />}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
if (session.status !== "success" || !session.user) {
|
|
|
|
|
window.location.reload();
|
|
|
|
|
return (
|
|
|
|
|
<div className="flex h-full min-h-screen flex-col text-clip">
|
|
|
|
|
<SiteHeader />
|
2025-08-20 14:04:23 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
<main className="flex h-full flex-1 overflow-auto">
|
|
|
|
|
<div className="flex h-auto w-full flex-col md:flex-row">
|
|
|
|
|
<LoadingPage />
|
|
|
|
|
</div>
|
|
|
|
|
</main>
|
|
|
|
|
{!noFooter && <MiniFooter />}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-08-20 14:04:23 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
return (
|
|
|
|
|
<div className="flex h-full min-h-screen flex-col text-clip">
|
|
|
|
|
<SiteHeader />
|
|
|
|
|
{bannerData?.map((banner) => (
|
|
|
|
|
<div key={`banner-elem-${banner.idbanner}`}>
|
|
|
|
|
{BannerFactory(banner)}
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
<main className="flex h-full flex-1 overflow-auto">
|
|
|
|
|
<div className="flex h-auto w-full flex-col md:flex-row">
|
|
|
|
|
{noSidebar ? null : (
|
|
|
|
|
<Sidebar isAdmin={session.user?.isAdmin || false} />
|
|
|
|
|
)}
|
|
|
|
|
<EnforcedSessionContext.Provider value={session as ValidSession}>
|
|
|
|
|
{children}
|
|
|
|
|
</EnforcedSessionContext.Provider>
|
|
|
|
|
</div>
|
|
|
|
|
</main>
|
|
|
|
|
{!noFooter && <MiniFooter />}
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
{/* <CookieConsent /> */}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
2025-08-04 17:45:44 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const AreaRiservataLayoutUserView = ({
|
2025-08-28 18:27:07 +02:00
|
|
|
children,
|
2025-08-04 17:45:44 +02:00
|
|
|
}: {
|
2025-08-28 18:27:07 +02:00
|
|
|
children: ReactNode & { props: { userId: UsersId } };
|
2025-08-04 17:45:44 +02:00
|
|
|
}) => {
|
2025-08-28 18:27:07 +02:00
|
|
|
const { t } = useTranslation();
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
const props = children.props as { userId: UsersId };
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
return (
|
|
|
|
|
<div className="flex h-full min-h-screen flex-col bg-white">
|
|
|
|
|
<SiteHeader />
|
|
|
|
|
<main className="flex h-full flex-1 overflow-auto">
|
|
|
|
|
<UserViewProvider userId={props.userId}>
|
|
|
|
|
<Head>
|
|
|
|
|
<title>{t.heads.area_riservata_titolo}</title>
|
|
|
|
|
<meta
|
|
|
|
|
content={t.heads.area_riservata_description}
|
2025-08-29 16:18:32 +02:00
|
|
|
name="description"
|
2025-08-28 18:27:07 +02:00
|
|
|
/>
|
|
|
|
|
</Head>
|
|
|
|
|
<div className="flex h-auto w-full flex-col md:flex-row">
|
|
|
|
|
<Sidebar isAdmin />
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
<div className="mx-4 my-3 flex-1 overflow-auto">
|
|
|
|
|
<UserViewHeader />
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
{children}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</UserViewProvider>
|
|
|
|
|
</main>
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
<MiniFooter />
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
{/* <CookieConsent /> */}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
2025-08-04 17:45:44 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const UserViewHeader = () => {
|
2025-08-28 18:27:07 +02:00
|
|
|
const data = useContext(UserViewContext);
|
|
|
|
|
const pathname = usePathname();
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
const { mutate: swap } = api.auth.swapUser.useMutation({
|
|
|
|
|
onSuccess: async () => {
|
|
|
|
|
toast.success("Utente cambiato con successo");
|
|
|
|
|
await router.push("/area-riservata/dashboard");
|
|
|
|
|
router.reload();
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
if (!data) return <div>Errore</div>;
|
|
|
|
|
return (
|
|
|
|
|
<div className="mb-5 flex flex-col space-y-5">
|
|
|
|
|
<div className="flex flex-row flex-wrap items-baseline gap-3">
|
|
|
|
|
<div className="text-3xl">{data.username}</div>
|
|
|
|
|
<div className="text-muted-foreground text-sm">
|
|
|
|
|
{data.email} | {data.telefono}
|
|
|
|
|
</div>
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
<Link href={`https://wa.me/${data.telefono}`} target="_blank">
|
|
|
|
|
<Button
|
|
|
|
|
className="flex items-center gap-2"
|
|
|
|
|
size="sm"
|
2025-08-29 16:18:32 +02:00
|
|
|
variant="success"
|
2025-08-28 18:27:07 +02:00
|
|
|
>
|
2025-10-16 10:28:24 +02:00
|
|
|
<WhatsAppIcon2 className="size-4 fill-white" />
|
2025-08-28 18:27:07 +02:00
|
|
|
WhatsApp
|
|
|
|
|
</Button>
|
|
|
|
|
</Link>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex flex-row flex-wrap gap-2">
|
|
|
|
|
<Link href={`/area-riservata/admin/user-view/edit-user/${data.id}`}>
|
|
|
|
|
<Button
|
|
|
|
|
className="flex items-center gap-2 border"
|
|
|
|
|
size="sm"
|
2025-08-29 16:18:32 +02:00
|
|
|
variant={pathname.includes("edit-user") ? "secondary" : "outline"}
|
2025-08-28 18:27:07 +02:00
|
|
|
>
|
|
|
|
|
<UserCog /> Profilo
|
|
|
|
|
</Button>
|
|
|
|
|
</Link>
|
|
|
|
|
<Link href={`/area-riservata/admin/user-view/servizio/${data.id}`}>
|
|
|
|
|
<Button
|
|
|
|
|
className="flex items-center gap-2 border"
|
|
|
|
|
size="sm"
|
2025-08-29 16:18:32 +02:00
|
|
|
variant={pathname.includes("servizio") ? "secondary" : "outline"}
|
2025-08-28 18:27:07 +02:00
|
|
|
>
|
|
|
|
|
<Tickets /> Servizi
|
|
|
|
|
</Button>
|
|
|
|
|
</Link>
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
<Link href={`/area-riservata/admin/user-view/ricerca/${data.id}`}>
|
|
|
|
|
<Button
|
|
|
|
|
className="flex items-center gap-2 border"
|
|
|
|
|
size="sm"
|
2025-08-29 16:18:32 +02:00
|
|
|
variant={pathname.includes("ricerca") ? "secondary" : "outline"}
|
2025-08-28 18:27:07 +02:00
|
|
|
>
|
|
|
|
|
<Search /> Ricerca
|
|
|
|
|
</Button>
|
|
|
|
|
</Link>
|
|
|
|
|
<Link href={`/area-riservata/admin/user-view/comunicazioni/${data.id}`}>
|
|
|
|
|
<Button
|
|
|
|
|
className="flex items-center gap-2 border"
|
2025-08-29 16:18:32 +02:00
|
|
|
size="sm"
|
2025-08-28 18:27:07 +02:00
|
|
|
variant={
|
|
|
|
|
pathname.includes("comunicazioni") ? "secondary" : "outline"
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
<Mail /> Comunicazioni
|
|
|
|
|
</Button>
|
|
|
|
|
</Link>
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
<Link href={`/area-riservata/admin/user-view/ordini/${data.id}`}>
|
|
|
|
|
<Button
|
|
|
|
|
className="flex items-center gap-2 border"
|
|
|
|
|
size="sm"
|
2025-08-29 16:18:32 +02:00
|
|
|
variant={pathname.includes("ordini") ? "secondary" : "outline"}
|
2025-08-28 18:27:07 +02:00
|
|
|
>
|
|
|
|
|
<ShoppingBag /> Ordini
|
|
|
|
|
</Button>
|
|
|
|
|
</Link>
|
|
|
|
|
<Link href={`/area-riservata/admin/user-view/allegati/${data.id}`}>
|
|
|
|
|
<Button
|
|
|
|
|
className="flex items-center gap-2 border"
|
|
|
|
|
size="sm"
|
2025-08-29 16:18:32 +02:00
|
|
|
variant={pathname.includes("allegati") ? "secondary" : "outline"}
|
2025-08-28 18:27:07 +02:00
|
|
|
>
|
|
|
|
|
<Paperclip /> Allegati
|
|
|
|
|
</Button>
|
|
|
|
|
</Link>
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
<Link
|
|
|
|
|
href={
|
|
|
|
|
data.chatid
|
|
|
|
|
? {
|
|
|
|
|
pathname: "/area-riservata/admin/chats",
|
|
|
|
|
query: { chatid: data.chatid },
|
|
|
|
|
}
|
|
|
|
|
: "/area-riservata/admin/chats"
|
|
|
|
|
}
|
|
|
|
|
target="_blank"
|
|
|
|
|
>
|
|
|
|
|
<Button
|
|
|
|
|
className="flex items-center gap-2 border"
|
|
|
|
|
size="sm"
|
2025-08-29 16:18:32 +02:00
|
|
|
variant={!data.chatid ? "ghost" : "outline"}
|
2025-08-28 18:27:07 +02:00
|
|
|
>
|
|
|
|
|
<MessagesSquare /> Chat
|
|
|
|
|
</Button>
|
|
|
|
|
</Link>
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
<Button
|
|
|
|
|
className="flex gap-2"
|
|
|
|
|
onClick={() =>
|
|
|
|
|
swap({
|
|
|
|
|
id: data.id,
|
|
|
|
|
})
|
|
|
|
|
}
|
2025-08-29 16:18:32 +02:00
|
|
|
size="sm"
|
2025-08-28 18:27:07 +02:00
|
|
|
>
|
|
|
|
|
<ExternalLink /> Login
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
<Separator />
|
|
|
|
|
</div>
|
|
|
|
|
);
|
2025-08-04 17:45:44 +02:00
|
|
|
};
|