intestazione maker
This commit is contained in:
parent
6d38dc5d5c
commit
eaf9ecc1d3
10 changed files with 302 additions and 164 deletions
|
|
@ -1,20 +1,6 @@
|
|||
import { getCookie } from "cookies-next";
|
||||
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 type { ReactNode } from "react";
|
||||
import {
|
||||
SIDEBAR_COOKIE_NAME,
|
||||
Sidebar,
|
||||
|
|
@ -23,10 +9,7 @@ import { BannerFactory } from "~/components/banners";
|
|||
import { Footer, MiniFooter } from "~/components/footer";
|
||||
import { LoadingPage } from "~/components/loading";
|
||||
import { SiteHeader } from "~/components/navbar/site-header";
|
||||
import { WhatsAppIcon2 } from "~/components/svgs";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { Separator } from "~/components/ui/separator";
|
||||
import { UserViewContext, UserViewProvider } from "~/lib/userViewContext";
|
||||
import { UserViewProvider } from "~/lib/userViewContext";
|
||||
import { cn } from "~/lib/utils";
|
||||
import { useTranslation } from "~/providers/I18nProvider";
|
||||
import {
|
||||
|
|
@ -36,6 +19,7 @@ import {
|
|||
import type { UsersId } from "~/schemas/public/Users";
|
||||
import type { ValidSession } from "~/server/api/trpc";
|
||||
import { api } from "~/utils/api";
|
||||
import { UserViewHeader } from "./area-riservata/userViewHeader";
|
||||
|
||||
interface Props {
|
||||
bodyClassName?: string;
|
||||
|
|
@ -68,7 +52,6 @@ export const Layout = ({
|
|||
</main>
|
||||
|
||||
{!noFooter && <Footer className={footerClassName} />}
|
||||
{/* <CookieConsent /> */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -171,8 +154,6 @@ export const AreaRiservataLayout = ({
|
|||
</div>
|
||||
</main>
|
||||
{!noFooter && <MiniFooter className={footerClassName} />}
|
||||
|
||||
{/* <CookieConsent /> */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -214,132 +195,6 @@ export const AreaRiservataLayoutUserView = ({
|
|||
</main>
|
||||
|
||||
<MiniFooter />
|
||||
|
||||
{/* <CookieConsent /> */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const UserViewHeader = () => {
|
||||
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>
|
||||
|
||||
<Link href={`https://wa.me/${data.telefono}`} target="_blank">
|
||||
<Button size="sm" variant="success">
|
||||
<WhatsAppIcon2 className="size-4 fill-white" />
|
||||
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="border"
|
||||
size="sm"
|
||||
variant={pathname.includes("edit-user") ? "secondary" : "outline"}
|
||||
>
|
||||
<UserCog /> Profilo
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href={`/area-riservata/admin/user-view/servizio/${data.id}`}>
|
||||
<Button
|
||||
className="border"
|
||||
size="sm"
|
||||
variant={pathname.includes("servizio") ? "secondary" : "outline"}
|
||||
>
|
||||
<Tickets /> Servizi
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
<Link href={`/area-riservata/admin/user-view/ricerca/${data.id}`}>
|
||||
<Button
|
||||
className="border"
|
||||
size="sm"
|
||||
variant={pathname.includes("ricerca") ? "secondary" : "outline"}
|
||||
>
|
||||
<Search /> Ricerca
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href={`/area-riservata/admin/user-view/comunicazioni/${data.id}`}>
|
||||
<Button
|
||||
className="border"
|
||||
size="sm"
|
||||
variant={
|
||||
pathname.includes("comunicazioni") ? "secondary" : "outline"
|
||||
}
|
||||
>
|
||||
<Mail /> Comunicazioni
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
<Link href={`/area-riservata/admin/user-view/ordini/${data.id}`}>
|
||||
<Button
|
||||
className="border"
|
||||
size="sm"
|
||||
variant={pathname.includes("ordini") ? "secondary" : "outline"}
|
||||
>
|
||||
<ShoppingBag /> Ordini
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href={`/area-riservata/admin/user-view/allegati/${data.id}`}>
|
||||
<Button
|
||||
className="border"
|
||||
size="sm"
|
||||
variant={pathname.includes("allegati") ? "secondary" : "outline"}
|
||||
>
|
||||
<Paperclip /> Allegati
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
<Link
|
||||
href={
|
||||
data.chatid
|
||||
? {
|
||||
pathname: "/area-riservata/admin/chats",
|
||||
query: { chatid: data.chatid },
|
||||
}
|
||||
: "/area-riservata/admin/chats"
|
||||
}
|
||||
target="_blank"
|
||||
>
|
||||
<Button
|
||||
className="border"
|
||||
size="sm"
|
||||
variant={!data.chatid ? "ghost" : "outline"}
|
||||
>
|
||||
<MessagesSquare /> Chat
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
<Button
|
||||
className="flex gap-2"
|
||||
onClick={() =>
|
||||
swap({
|
||||
id: data.id,
|
||||
})
|
||||
}
|
||||
size="sm"
|
||||
>
|
||||
<ExternalLink /> Login
|
||||
</Button>
|
||||
</div>
|
||||
<Separator />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import toast from "react-hot-toast";
|
|||
import { useSession } from "~/providers/SessionProvider";
|
||||
import type { UsersId } from "~/schemas/public/Users";
|
||||
import type { UsersStorageUserStorageId } from "~/schemas/public/UsersStorage";
|
||||
import type { UserWithAnagrafica } from "~/server/services/user.service";
|
||||
import type { CompleteUserData } from "~/server/services/user.service";
|
||||
import { api } from "~/utils/api";
|
||||
import { Confirm } from "../confirm";
|
||||
import { ImageFlbk } from "../ImageWithFallback";
|
||||
|
|
@ -24,7 +24,7 @@ import { UploadModal } from "../upload_modal";
|
|||
export const DocumentiPersonali = ({
|
||||
userData,
|
||||
}: {
|
||||
userData: UserWithAnagrafica;
|
||||
userData: CompleteUserData;
|
||||
}) => {
|
||||
const utils = api.useUtils();
|
||||
const { mutate, isPending } = api.users.editUserAnagrafica.useMutation({
|
||||
|
|
|
|||
|
|
@ -0,0 +1,250 @@
|
|||
import { format } from "date-fns";
|
||||
import {
|
||||
ExternalLink,
|
||||
Mail,
|
||||
MessagesSquare,
|
||||
Paperclip,
|
||||
Search,
|
||||
ShoppingBag,
|
||||
Tickets,
|
||||
UserCog,
|
||||
UserPen,
|
||||
} from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { useRouter } from "next/router";
|
||||
import toast from "react-hot-toast";
|
||||
import { useUserViewContext } from "~/lib/userViewContext";
|
||||
import { api } from "~/utils/api";
|
||||
import { WhatsAppIcon2 } from "../svgs";
|
||||
import { Button } from "../ui/button";
|
||||
import { Separator } from "../ui/separator";
|
||||
|
||||
export const UserViewHeader = () => {
|
||||
const data = useUserViewContext();
|
||||
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>
|
||||
|
||||
<Link href={`https://wa.me/${data.telefono}`} target="_blank">
|
||||
<Button size="sm" variant="success">
|
||||
<WhatsAppIcon2 className="size-4 fill-white" />
|
||||
WhatsApp
|
||||
</Button>
|
||||
</Link>
|
||||
{data.codice_fiscale ? (
|
||||
<IntestazioneMaker />
|
||||
) : (
|
||||
<Button disabled size="sm">
|
||||
<UserPen /> Intestazione
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-row flex-wrap gap-2">
|
||||
<Link href={`/area-riservata/admin/user-view/edit-user/${data.id}`}>
|
||||
<Button
|
||||
className="border"
|
||||
size="sm"
|
||||
variant={pathname.includes("edit-user") ? "secondary" : "outline"}
|
||||
>
|
||||
<UserCog /> Profilo
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href={`/area-riservata/admin/user-view/servizio/${data.id}`}>
|
||||
<Button
|
||||
className="border"
|
||||
size="sm"
|
||||
variant={pathname.includes("servizio") ? "secondary" : "outline"}
|
||||
>
|
||||
<Tickets /> Servizi
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
<Link href={`/area-riservata/admin/user-view/ricerca/${data.id}`}>
|
||||
<Button
|
||||
className="border"
|
||||
size="sm"
|
||||
variant={pathname.includes("ricerca") ? "secondary" : "outline"}
|
||||
>
|
||||
<Search /> Ricerca
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href={`/area-riservata/admin/user-view/comunicazioni/${data.id}`}>
|
||||
<Button
|
||||
className="border"
|
||||
size="sm"
|
||||
variant={
|
||||
pathname.includes("comunicazioni") ? "secondary" : "outline"
|
||||
}
|
||||
>
|
||||
<Mail /> Comunicazioni
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
<Link href={`/area-riservata/admin/user-view/ordini/${data.id}`}>
|
||||
<Button
|
||||
className="border"
|
||||
size="sm"
|
||||
variant={pathname.includes("ordini") ? "secondary" : "outline"}
|
||||
>
|
||||
<ShoppingBag /> Ordini
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href={`/area-riservata/admin/user-view/allegati/${data.id}`}>
|
||||
<Button
|
||||
className="border"
|
||||
size="sm"
|
||||
variant={pathname.includes("allegati") ? "secondary" : "outline"}
|
||||
>
|
||||
<Paperclip /> Allegati
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
<Link
|
||||
href={
|
||||
data.chatid
|
||||
? {
|
||||
pathname: "/area-riservata/admin/chats",
|
||||
query: { chatid: data.chatid },
|
||||
}
|
||||
: "/area-riservata/admin/chats"
|
||||
}
|
||||
target="_blank"
|
||||
>
|
||||
<Button
|
||||
className="border"
|
||||
size="sm"
|
||||
variant={!data.chatid ? "ghost" : "outline"}
|
||||
>
|
||||
<MessagesSquare /> Chat
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
<Button
|
||||
className="flex gap-2"
|
||||
onClick={() =>
|
||||
swap({
|
||||
id: data.id,
|
||||
})
|
||||
}
|
||||
size="sm"
|
||||
>
|
||||
<ExternalLink /> Login
|
||||
</Button>
|
||||
</div>
|
||||
<Separator />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const VOCALI = ["A", "E", "I", "O", "U"] as const;
|
||||
|
||||
const IntestazioneMaker = () => {
|
||||
const data = useUserViewContext();
|
||||
const { data: comuni = [] } = api.catasto.searchComuniByCatasto.useQuery({
|
||||
catasto: [data?.luogo_nascita || "", data?.comune_residenza || ""].filter(
|
||||
(f) => f !== "",
|
||||
),
|
||||
});
|
||||
|
||||
const isDisabled =
|
||||
!data.sesso ||
|
||||
!data.cognome ||
|
||||
!data.nome ||
|
||||
!data.data_nascita ||
|
||||
!data.luogo_nascita ||
|
||||
!data.comune_residenza ||
|
||||
!data.via_residenza ||
|
||||
!data.civico_residenza;
|
||||
|
||||
const copyToClipboard = () => {
|
||||
if (
|
||||
!data.sesso ||
|
||||
!data.cognome ||
|
||||
!data.nome ||
|
||||
!data.data_nascita ||
|
||||
!data.luogo_nascita ||
|
||||
!data.comune_residenza ||
|
||||
!data.via_residenza ||
|
||||
!data.civico_residenza
|
||||
) {
|
||||
toast.error("Dati mancanti");
|
||||
return;
|
||||
}
|
||||
|
||||
const comune_nascita = comuni.find((c) => c.catasto === data.luogo_nascita);
|
||||
const comune_residenza = comuni.find(
|
||||
(c) => c.catasto === data.comune_residenza,
|
||||
);
|
||||
if (!comune_nascita || !comune_residenza) {
|
||||
toast.error("Errore comune non trovato");
|
||||
return;
|
||||
}
|
||||
|
||||
// Format names
|
||||
const cognome = titleCase(data.cognome);
|
||||
const nome = titleCase(data.nome);
|
||||
const viaResidenza = titleCase(data.via_residenza);
|
||||
const comuneNascita = titleCase(comune_nascita.nome);
|
||||
const comuneResidenza = titleCase(comune_residenza.nome);
|
||||
|
||||
// Determine article
|
||||
const isMale = data.sesso === "M";
|
||||
const articolo = isMale ? "Al Sig." : "Alla Sig.ra";
|
||||
const natoNata = isMale ? "nato" : "nata";
|
||||
const preposizione = VOCALI.includes(comuneNascita[0]?.toUpperCase() || "")
|
||||
? "ad"
|
||||
: "a";
|
||||
|
||||
// Build phrase
|
||||
const frase = [
|
||||
`${articolo} ${cognome} ${nome}`,
|
||||
`${natoNata} il ${format(data.data_nascita, "dd/MM/yyyy")}`,
|
||||
`${preposizione} ${comuneNascita} (${comune_nascita.sigla}),`,
|
||||
`residente in ${viaResidenza}, ${data.civico_residenza}`,
|
||||
`a ${comuneResidenza} (${data.provincia_residenza})`,
|
||||
`CAP ${data.cap_residenza},`,
|
||||
`con codice fiscale: ${data.codice_fiscale}`,
|
||||
].join(" ");
|
||||
|
||||
navigator.clipboard
|
||||
.writeText(frase)
|
||||
.then(() => {
|
||||
toast.success("Intestazione copiata negli appunti");
|
||||
})
|
||||
.catch(() => {
|
||||
toast.error("Errore nella copia");
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Button disabled={isDisabled} onClick={copyToClipboard} size="sm">
|
||||
<UserPen /> Intestazione
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
function titleCase(str: string | null | undefined): string {
|
||||
if (!str) return "";
|
||||
|
||||
return str
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.split(/\s+/) // Handle multiple spaces
|
||||
.map((word) => {
|
||||
if (word.length === 0) return word;
|
||||
return word.charAt(0).toUpperCase() + word.slice(1);
|
||||
})
|
||||
.join(" ");
|
||||
}
|
||||
|
|
@ -34,7 +34,7 @@ import { cn } from "~/lib/utils";
|
|||
import { useZodForm } from "~/lib/zodForm";
|
||||
import { useCatasto } from "~/providers/CatastoProvider";
|
||||
import { useTranslation } from "~/providers/I18nProvider";
|
||||
import type { UserWithAnagrafica } from "~/server/services/user.service";
|
||||
import type { CompleteUserData } from "~/server/services/user.service";
|
||||
import { api } from "~/utils/api";
|
||||
|
||||
const profileFormSchema = z.object({
|
||||
|
|
@ -62,7 +62,7 @@ type ProfileFormValues = z.infer<typeof profileFormSchema>;
|
|||
export const ProfileFormAnagrafica = ({
|
||||
userData,
|
||||
}: {
|
||||
userData: UserWithAnagrafica;
|
||||
userData: CompleteUserData;
|
||||
}) => {
|
||||
const { comuni, nazioni } = useCatasto();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { createContext, type FC, type ReactNode } from "react";
|
||||
import { createContext, type FC, type ReactNode, useContext } from "react";
|
||||
import type { ChatsChatid } from "~/schemas/public/Chats";
|
||||
import type { UsersId } from "~/schemas/public/Users";
|
||||
|
||||
import type { getUserReturnType } from "~/server/controllers/user.controller";
|
||||
import type { UserWAnagrafica } from "~/server/controllers/user.controller";
|
||||
import { api } from "~/utils/api";
|
||||
|
||||
type UserViewContextType = getUserReturnType & { chatid: ChatsChatid | null };
|
||||
type UserViewContextType = UserWAnagrafica & { chatid: ChatsChatid | null };
|
||||
|
||||
export const UserViewContext = createContext<UserViewContextType | null>(null);
|
||||
|
||||
|
|
@ -28,3 +28,13 @@ export const UserViewProvider: FC<{ children: ReactNode; userId: UsersId }> = ({
|
|||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export const useUserViewContext = () => {
|
||||
const context = useContext(UserViewContext);
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
"useUserViewContext must be used within a UserViewProvider",
|
||||
);
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import {
|
|||
getNazioneById,
|
||||
getNazioni,
|
||||
getProvincie,
|
||||
searchComuniByCatasto,
|
||||
} from "~/server/controllers/catasto.controller";
|
||||
|
||||
import { zComuneId, zNazioneId } from "~/server/utils/zod_types";
|
||||
|
|
@ -14,6 +15,15 @@ export const catastoRouter = createTRPCRouter({
|
|||
getComuni: publicProcedure.query(async () => {
|
||||
return await getComuni();
|
||||
}),
|
||||
searchComuniByCatasto: publicProcedure
|
||||
.input(
|
||||
z.object({
|
||||
catasto: z.string().array(),
|
||||
}),
|
||||
)
|
||||
.query(async ({ input }) => {
|
||||
return await searchComuniByCatasto(input.catasto);
|
||||
}),
|
||||
getComuneById: publicProcedure
|
||||
.input(
|
||||
z.object({
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import {
|
|||
getUsersWithChatInfoHandler,
|
||||
} from "~/server/controllers/user.controller";
|
||||
import { db } from "~/server/db";
|
||||
import { getUserWithAnagraficaHandler } from "~/server/services/user.service";
|
||||
import { getClientProfilo } from "~/server/services/user.service";
|
||||
import { zUserId } from "~/server/utils/zod_types";
|
||||
|
||||
export const usersRouter = createTRPCRouter({
|
||||
|
|
@ -71,7 +71,7 @@ export const usersRouter = createTRPCRouter({
|
|||
}),
|
||||
)
|
||||
.query(async ({ input }) => {
|
||||
return getUserWithAnagraficaHandler({
|
||||
return getClientProfilo({
|
||||
db,
|
||||
userId: input.userId,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -15,6 +15,20 @@ export const getComuni = async () => {
|
|||
}
|
||||
};
|
||||
|
||||
export const searchComuniByCatasto = async (catasto: string[]) => {
|
||||
try {
|
||||
return await db
|
||||
.selectFrom("comuni")
|
||||
.selectAll()
|
||||
.where("catasto", "in", catasto)
|
||||
.execute();
|
||||
} catch (e) {
|
||||
throw new TRPCError({
|
||||
code: "INTERNAL_SERVER_ERROR",
|
||||
message: `Error while getting Comuni: ${(e as Error).message}`,
|
||||
});
|
||||
}
|
||||
};
|
||||
export const getComuneById = async (id: ComuniId) => {
|
||||
try {
|
||||
return await db
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { TRPCError } from "@trpc/server";
|
||||
import type { Users, UsersId, UsersUpdate } from "~/schemas/public/Users";
|
||||
import type { UsersId, UsersUpdate } from "~/schemas/public/Users";
|
||||
import type { UsersAnagraficaUpdate } from "~/schemas/public/UsersAnagrafica";
|
||||
import type { Context } from "~/server/api/trpc";
|
||||
import { db, type Querier } from "~/server/db";
|
||||
|
|
@ -166,10 +166,11 @@ export const getUserHandler = async ({
|
|||
}: {
|
||||
db: Querier;
|
||||
id: UsersId;
|
||||
}): Promise<Users | null> => {
|
||||
}) => {
|
||||
try {
|
||||
const user = await db
|
||||
.selectFrom("users")
|
||||
.leftJoin("users_anagrafica", "users_anagrafica.userid", "users.id")
|
||||
.where("id", "=", id)
|
||||
.selectAll()
|
||||
.executeTakeFirst();
|
||||
|
|
@ -185,7 +186,7 @@ export const getUserHandler = async ({
|
|||
});
|
||||
}
|
||||
};
|
||||
export type getUserReturnType = Awaited<ReturnType<typeof getUserHandler>>;
|
||||
export type UserWAnagrafica = Awaited<ReturnType<typeof getUserHandler>>;
|
||||
|
||||
export type NonNullableUser = {
|
||||
id: NonNullable<UsersId>;
|
||||
|
|
|
|||
|
|
@ -98,10 +98,8 @@ export const addUser = async ({
|
|||
}
|
||||
};
|
||||
|
||||
export type UserWithAnagrafica = Awaited<
|
||||
ReturnType<typeof getUserWithAnagraficaHandler>
|
||||
>;
|
||||
export const getUserWithAnagraficaHandler = async ({
|
||||
export type CompleteUserData = Awaited<ReturnType<typeof getClientProfilo>>;
|
||||
export const getClientProfilo = async ({
|
||||
db,
|
||||
userId,
|
||||
}: {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue