2025-08-04 17:45:44 +02:00
|
|
|
import type { ColumnDef } from "@tanstack/react-table";
|
2025-08-28 18:27:07 +02:00
|
|
|
import {
|
|
|
|
|
Crown,
|
|
|
|
|
Mail,
|
|
|
|
|
MessagesSquare,
|
|
|
|
|
Paperclip,
|
2026-03-10 16:56:26 +01:00
|
|
|
Plus,
|
2025-08-28 18:27:07 +02:00
|
|
|
Search,
|
|
|
|
|
ShoppingBag,
|
2026-03-10 16:56:26 +01:00
|
|
|
Tags,
|
2025-08-28 18:27:07 +02:00
|
|
|
User,
|
|
|
|
|
UserCog,
|
2026-03-10 16:56:26 +01:00
|
|
|
X,
|
2025-08-28 18:27:07 +02:00
|
|
|
} from "lucide-react";
|
|
|
|
|
import Link from "next/link";
|
|
|
|
|
import { useRouter } from "next/router";
|
2026-03-10 16:56:26 +01:00
|
|
|
import { useState } from "react";
|
2025-08-28 18:27:07 +02:00
|
|
|
import toast from "react-hot-toast";
|
2026-03-19 10:24:32 +01:00
|
|
|
import { DataTable } from "~/components/ui/data-table";
|
|
|
|
|
import { DataTableColumnHeader } from "~/components/ui/dataTable-header";
|
2025-08-04 17:45:44 +02:00
|
|
|
import type {
|
2025-08-28 18:27:07 +02:00
|
|
|
PinnedFiltro,
|
|
|
|
|
SearchFiltro,
|
2026-03-19 10:24:32 +01:00
|
|
|
} from "~/components/ui/dataTable-toolbar";
|
2025-08-28 18:27:07 +02:00
|
|
|
import { UserAvatar } from "~/components/user_avatar";
|
2025-08-04 17:45:44 +02:00
|
|
|
import { cn } from "~/lib/utils";
|
2026-03-10 16:56:26 +01:00
|
|
|
import type { Etichette } from "~/schemas/public/Etichette";
|
|
|
|
|
import type { Users, UsersId } from "~/schemas/public/Users";
|
2025-08-04 17:45:44 +02:00
|
|
|
import { api } from "~/utils/api";
|
2026-03-10 16:56:26 +01:00
|
|
|
import { Etichetta } from "../etichette";
|
2026-03-10 15:05:36 +01:00
|
|
|
import { WhatsAppIcon2 } from "../svgs";
|
2026-03-10 16:56:26 +01:00
|
|
|
import { Button } from "../ui/button";
|
2026-03-10 13:57:29 +01:00
|
|
|
import {
|
|
|
|
|
ContextMenuContent,
|
|
|
|
|
ContextMenuItem,
|
2026-03-10 15:05:36 +01:00
|
|
|
ContextMenuLabel,
|
2026-03-10 13:57:29 +01:00
|
|
|
ContextMenuSeparator,
|
|
|
|
|
} from "../ui/context-menu";
|
2026-03-10 16:56:26 +01:00
|
|
|
import {
|
|
|
|
|
Dialog,
|
|
|
|
|
DialogContent,
|
|
|
|
|
DialogDescription,
|
|
|
|
|
DialogHeader,
|
|
|
|
|
DialogTitle,
|
|
|
|
|
} from "../ui/dialog";
|
|
|
|
|
import { Separator } from "../ui/separator";
|
2025-08-28 18:27:07 +02:00
|
|
|
|
2025-08-04 17:45:44 +02:00
|
|
|
type UserWChatInfo = Pick<
|
2025-08-28 18:27:07 +02:00
|
|
|
Users,
|
2026-03-10 13:57:29 +01:00
|
|
|
| "id"
|
|
|
|
|
| "username"
|
|
|
|
|
| "email"
|
|
|
|
|
| "telefono"
|
|
|
|
|
| "isAdmin"
|
|
|
|
|
| "isBlocked"
|
|
|
|
|
| "created_at"
|
2026-03-10 16:56:26 +01:00
|
|
|
> & { chatid: string | null; etichette: Etichette[] };
|
2025-08-04 17:45:44 +02:00
|
|
|
|
|
|
|
|
export const UsersTable = (props: { data: UserWChatInfo[] }) => {
|
2025-08-28 18:27:07 +02:00
|
|
|
const router = useRouter();
|
2025-09-09 10:21:19 +02:00
|
|
|
const { mutateAsync: swap } = api.auth.swapUser.useMutation({
|
2025-08-28 18:27:07 +02:00
|
|
|
onSuccess: async () => {
|
|
|
|
|
toast.success("Utente cambiato con successo");
|
2026-03-06 14:10:36 +01:00
|
|
|
await router.push("/area-riservata/load-page");
|
2025-08-28 18:27:07 +02:00
|
|
|
},
|
|
|
|
|
});
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2026-03-10 16:56:26 +01:00
|
|
|
const [selected, setSelected] = useState<{
|
|
|
|
|
id: UsersId;
|
|
|
|
|
etichette: Etichette[];
|
|
|
|
|
} | null>(null);
|
|
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
const { data } = props;
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
const tabledata = data.map((user) => {
|
|
|
|
|
return {
|
2025-08-29 16:18:32 +02:00
|
|
|
chatid: user.chatid,
|
|
|
|
|
created_at: user.created_at,
|
2025-08-28 18:27:07 +02:00
|
|
|
email: user.email,
|
2026-03-10 13:57:29 +01:00
|
|
|
telefono: user.telefono,
|
2025-08-29 16:18:32 +02:00
|
|
|
id: user.id,
|
2025-08-28 18:27:07 +02:00
|
|
|
isAdmin: user.isAdmin ? "Admin" : "Utente",
|
2026-03-10 16:56:26 +01:00
|
|
|
isBlocked: user.isBlocked ? "Bloccato" : "Attivo",
|
2025-08-29 16:18:32 +02:00
|
|
|
username: user.username,
|
2026-03-10 16:56:26 +01:00
|
|
|
etichette: user.etichette,
|
2025-08-28 18:27:07 +02:00
|
|
|
};
|
|
|
|
|
});
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
const admin_options = [
|
|
|
|
|
{ label: "Admin", value: "Admin" },
|
|
|
|
|
{ label: "Utente", value: "Utente" },
|
|
|
|
|
];
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
const columns_titles = {
|
2025-08-29 16:18:32 +02:00
|
|
|
created_at: "Creato il",
|
2025-08-28 18:27:07 +02:00
|
|
|
email: "Email",
|
2026-03-10 13:57:29 +01:00
|
|
|
telefono: "Telefono",
|
2025-08-28 18:27:07 +02:00
|
|
|
isAdmin: "Ruolo",
|
2026-03-10 16:56:26 +01:00
|
|
|
isBlocked: "Status",
|
2025-08-29 16:18:32 +02:00
|
|
|
username: "User",
|
2026-03-10 16:56:26 +01:00
|
|
|
etichette: "📎",
|
2025-08-28 18:27:07 +02:00
|
|
|
};
|
|
|
|
|
type Column = (typeof tabledata)[number];
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
const columns: ColumnDef<Column>[] = [
|
2026-03-10 16:56:26 +01:00
|
|
|
{
|
|
|
|
|
accessorKey: "etichette",
|
|
|
|
|
header: ({ column }) => (
|
|
|
|
|
<DataTableColumnHeader
|
|
|
|
|
column={column}
|
|
|
|
|
title={columns_titles.etichette}
|
|
|
|
|
/>
|
|
|
|
|
),
|
|
|
|
|
cell: ({ row }) => {
|
|
|
|
|
return (
|
|
|
|
|
<div className="flex max-w-32 flex-wrap items-center gap-2">
|
|
|
|
|
{row.original.etichette.map((e) => (
|
|
|
|
|
<Etichetta
|
|
|
|
|
color_hex={e.color_hex}
|
|
|
|
|
key={e.id_etichetta}
|
|
|
|
|
title={e.title}
|
|
|
|
|
/>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
enableHiding: false,
|
|
|
|
|
enableSorting: false,
|
|
|
|
|
},
|
2025-08-28 18:27:07 +02:00
|
|
|
{
|
|
|
|
|
accessorKey: "username",
|
|
|
|
|
cell: ({ row }) => {
|
|
|
|
|
const user = row.original;
|
|
|
|
|
return (
|
|
|
|
|
<Link
|
|
|
|
|
aria-label="Visualizza Utente"
|
|
|
|
|
className="flex items-center gap-2"
|
2026-03-12 17:02:35 +01:00
|
|
|
href={`/area-riservata/admin/user-view/ricerca/${user.id}`}
|
2025-08-28 18:27:07 +02:00
|
|
|
>
|
|
|
|
|
<UserAvatar
|
|
|
|
|
className="size-8"
|
|
|
|
|
userId={user.id}
|
2025-08-29 16:18:32 +02:00
|
|
|
username={user.username}
|
2025-08-28 18:27:07 +02:00
|
|
|
/>
|
2025-10-10 16:18:43 +02:00
|
|
|
<span className="font-semibold text-sm">{user.username}</span>
|
2025-08-28 18:27:07 +02:00
|
|
|
</Link>
|
|
|
|
|
);
|
|
|
|
|
},
|
2025-08-29 16:18:32 +02:00
|
|
|
enableHiding: false,
|
|
|
|
|
header: ({ column }) => (
|
|
|
|
|
<DataTableColumnHeader
|
|
|
|
|
column={column}
|
|
|
|
|
title={columns_titles.username}
|
|
|
|
|
/>
|
|
|
|
|
),
|
2025-08-28 18:27:07 +02:00
|
|
|
},
|
2026-03-10 18:05:15 +01:00
|
|
|
|
2026-03-10 13:57:29 +01:00
|
|
|
{
|
|
|
|
|
accessorKey: "telefono",
|
|
|
|
|
header: ({ column }) => (
|
|
|
|
|
<DataTableColumnHeader
|
|
|
|
|
column={column}
|
|
|
|
|
title={columns_titles.telefono}
|
|
|
|
|
/>
|
|
|
|
|
),
|
|
|
|
|
},
|
2026-03-10 18:05:15 +01:00
|
|
|
{
|
|
|
|
|
accessorKey: "email",
|
|
|
|
|
header: ({ column }) => (
|
|
|
|
|
<DataTableColumnHeader column={column} title={columns_titles.email} />
|
|
|
|
|
),
|
|
|
|
|
},
|
2026-03-10 13:57:29 +01:00
|
|
|
{
|
|
|
|
|
accessorKey: "created_at",
|
|
|
|
|
cell: ({ row }) => {
|
|
|
|
|
const date = row.getValue("created_at");
|
|
|
|
|
return new Date(date as Date).toLocaleDateString();
|
|
|
|
|
},
|
|
|
|
|
enableHiding: false,
|
|
|
|
|
header: ({ column }) => (
|
|
|
|
|
<DataTableColumnHeader
|
|
|
|
|
column={column}
|
|
|
|
|
title={columns_titles.created_at}
|
|
|
|
|
/>
|
|
|
|
|
),
|
|
|
|
|
sortingFn: "datetime",
|
|
|
|
|
},
|
2025-08-28 18:27:07 +02:00
|
|
|
{
|
2025-08-29 16:18:32 +02:00
|
|
|
accessorKey: "isAdmin",
|
2025-08-28 18:27:07 +02:00
|
|
|
cell: ({ row }) => {
|
|
|
|
|
const isadmin = admin_options.find(
|
|
|
|
|
(status) => status.value === row.getValue("isAdmin"),
|
|
|
|
|
);
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
if (!isadmin) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2025-08-04 17:45:44 +02:00
|
|
|
|
2025-08-28 18:27:07 +02:00
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
className={cn(
|
2026-01-16 10:30:27 +01:00
|
|
|
"flex w-25 items-center",
|
2025-08-28 18:27:07 +02:00
|
|
|
isadmin.value === "Admin" && "text-green-500",
|
|
|
|
|
)}
|
|
|
|
|
>
|
|
|
|
|
{isadmin.value === "Admin" && <Crown className="size-4" />}
|
|
|
|
|
<span>{isadmin.label}</span>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
filterFn: (row, id, value) => {
|
|
|
|
|
return value.includes(row.getValue(id));
|
|
|
|
|
},
|
|
|
|
|
header: ({ column }) => (
|
2025-08-29 16:18:32 +02:00
|
|
|
<DataTableColumnHeader column={column} title={columns_titles.isAdmin} />
|
2025-08-28 18:27:07 +02:00
|
|
|
),
|
2025-08-29 16:18:32 +02:00
|
|
|
},
|
2026-03-10 13:57:29 +01:00
|
|
|
|
2025-08-29 16:18:32 +02:00
|
|
|
{
|
2026-03-10 16:56:26 +01:00
|
|
|
accessorKey: "isBlocked",
|
2025-08-28 18:27:07 +02:00
|
|
|
filterFn: (row, id, value) => {
|
|
|
|
|
return value.includes(row.getValue(id));
|
|
|
|
|
},
|
|
|
|
|
header: ({ column }) => (
|
|
|
|
|
<DataTableColumnHeader
|
|
|
|
|
column={column}
|
2026-03-10 16:56:26 +01:00
|
|
|
title={columns_titles.isBlocked}
|
2025-08-28 18:27:07 +02:00
|
|
|
/>
|
|
|
|
|
),
|
2025-08-29 16:18:32 +02:00
|
|
|
},
|
2025-08-28 18:27:07 +02:00
|
|
|
];
|
|
|
|
|
const pinnedFiltri: PinnedFiltro[] = [
|
|
|
|
|
{
|
|
|
|
|
columnName: "isAdmin",
|
|
|
|
|
options: [
|
|
|
|
|
{ label: "Admin", value: "Admin" },
|
|
|
|
|
{ label: "Utente", value: "Utente" },
|
|
|
|
|
],
|
2025-08-29 16:18:32 +02:00
|
|
|
title: "Ruolo",
|
2025-08-28 18:27:07 +02:00
|
|
|
},
|
|
|
|
|
{
|
2026-03-10 16:56:26 +01:00
|
|
|
columnName: "isBlocked",
|
2025-08-28 18:27:07 +02:00
|
|
|
options: [
|
|
|
|
|
{ label: "Bloccato", value: "Bloccato" },
|
|
|
|
|
{ label: "Attivo", value: "Attivo" },
|
|
|
|
|
],
|
2025-08-29 16:18:32 +02:00
|
|
|
title: "Status",
|
2025-08-28 18:27:07 +02:00
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
const searchFiltro: SearchFiltro = {
|
2026-03-18 14:54:33 +01:00
|
|
|
columnName: null,
|
|
|
|
|
placeholder: "Cerca...",
|
2025-08-28 18:27:07 +02:00
|
|
|
};
|
|
|
|
|
return (
|
|
|
|
|
<div className="mx-auto w-full px-2 py-10">
|
|
|
|
|
<DataTable
|
|
|
|
|
columns={columns}
|
2025-08-29 16:18:32 +02:00
|
|
|
columns_titles={columns_titles}
|
2026-03-10 13:57:29 +01:00
|
|
|
contextMenuContent={(data) => (
|
|
|
|
|
<ContextMenuContent>
|
2026-03-10 15:05:36 +01:00
|
|
|
<ContextMenuLabel className="flex h-8 items-center gap-2">
|
|
|
|
|
<UserAvatar
|
|
|
|
|
className="size-5"
|
|
|
|
|
style={{ height: "1.25rem", width: "1.25rem" }}
|
|
|
|
|
userId={data.id}
|
|
|
|
|
username={data.username}
|
|
|
|
|
/>
|
|
|
|
|
<span className="font-semibold text-sm">{data.username}</span>
|
|
|
|
|
</ContextMenuLabel>
|
2026-03-10 13:57:29 +01:00
|
|
|
<ContextMenuItem>
|
|
|
|
|
<Link
|
|
|
|
|
aria-label="Visualizza Ricerca"
|
|
|
|
|
className="flex w-full items-center gap-2"
|
|
|
|
|
href={`/area-riservata/admin/user-view/ricerca/${data.id}`}
|
|
|
|
|
>
|
|
|
|
|
<Search className="text-muted-foreground" /> Ricerca
|
|
|
|
|
</Link>
|
|
|
|
|
</ContextMenuItem>
|
|
|
|
|
<ContextMenuItem>
|
|
|
|
|
<Link
|
|
|
|
|
aria-label="Visualizza Comunicazioni"
|
|
|
|
|
className="flex w-full items-center gap-2"
|
|
|
|
|
href={`/area-riservata/admin/user-view/comunicazioni/${data.id}`}
|
|
|
|
|
>
|
|
|
|
|
<Mail className="text-muted-foreground" /> Comunicazioni
|
|
|
|
|
</Link>
|
|
|
|
|
</ContextMenuItem>
|
|
|
|
|
<ContextMenuItem>
|
|
|
|
|
<Link
|
|
|
|
|
aria-label="Visualizza Profilo"
|
|
|
|
|
className="flex w-full items-center gap-2"
|
|
|
|
|
href={`/area-riservata/admin/user-view/edit-user/${data.id}`}
|
|
|
|
|
>
|
|
|
|
|
<UserCog className="text-muted-foreground" /> Profilo
|
|
|
|
|
</Link>
|
|
|
|
|
</ContextMenuItem>
|
|
|
|
|
|
|
|
|
|
<ContextMenuItem>
|
|
|
|
|
<Link
|
|
|
|
|
aria-label="Visualizza Ordini"
|
|
|
|
|
className="flex w-full items-center gap-2"
|
|
|
|
|
href={`/area-riservata/admin/user-view/ordini/${data.id}`}
|
|
|
|
|
>
|
|
|
|
|
<ShoppingBag className="text-muted-foreground" /> Ordini
|
|
|
|
|
</Link>
|
|
|
|
|
</ContextMenuItem>
|
|
|
|
|
<ContextMenuItem>
|
|
|
|
|
<Link
|
|
|
|
|
aria-label="Visualizza Allegati"
|
|
|
|
|
className="flex w-full items-center gap-2"
|
|
|
|
|
href={`/area-riservata/admin/user-view/allegati/${data.id}`}
|
|
|
|
|
>
|
|
|
|
|
<Paperclip className="text-muted-foreground" /> Allegati
|
|
|
|
|
</Link>
|
|
|
|
|
</ContextMenuItem>
|
|
|
|
|
<ContextMenuSeparator />
|
|
|
|
|
<ContextMenuItem>
|
|
|
|
|
<Link
|
|
|
|
|
aria-label="Visualizza Chat"
|
|
|
|
|
className={cn(
|
|
|
|
|
"flex w-full items-center gap-2",
|
|
|
|
|
!data.chatid && "text-neutral-200",
|
|
|
|
|
)}
|
|
|
|
|
href={
|
|
|
|
|
data.chatid
|
|
|
|
|
? {
|
|
|
|
|
pathname: "/area-riservata/admin/chats",
|
|
|
|
|
query: { chatId: data.chatid },
|
|
|
|
|
}
|
|
|
|
|
: "/area-riservata/admin/chats"
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
<MessagesSquare /> Chat
|
|
|
|
|
</Link>
|
|
|
|
|
</ContextMenuItem>
|
2026-03-10 15:05:36 +01:00
|
|
|
<ContextMenuItem>
|
|
|
|
|
<Link
|
|
|
|
|
className="flex w-full items-center gap-2"
|
|
|
|
|
href={`https://wa.me/${data.telefono}`}
|
|
|
|
|
target="_blank"
|
|
|
|
|
>
|
|
|
|
|
<WhatsAppIcon2 className="size-4 fill-muted-foreground stroke-0" />
|
|
|
|
|
WhatsApp
|
|
|
|
|
</Link>
|
|
|
|
|
</ContextMenuItem>
|
2026-03-10 13:57:29 +01:00
|
|
|
<ContextMenuSeparator />
|
|
|
|
|
<ContextMenuItem>
|
|
|
|
|
<button
|
|
|
|
|
aria-label="Login as User"
|
|
|
|
|
className="flex w-full cursor-pointer items-center gap-2"
|
|
|
|
|
onClick={async () => await swap({ id: data.id })}
|
|
|
|
|
type="button"
|
|
|
|
|
>
|
|
|
|
|
<User /> Login
|
|
|
|
|
</button>
|
|
|
|
|
</ContextMenuItem>
|
2026-03-10 16:56:26 +01:00
|
|
|
<ContextMenuItem>
|
|
|
|
|
<button
|
|
|
|
|
className="flex w-full cursor-pointer items-center gap-2"
|
|
|
|
|
onClick={() => {
|
|
|
|
|
setSelected({ id: data.id, etichette: data.etichette });
|
|
|
|
|
}}
|
|
|
|
|
type="button"
|
|
|
|
|
>
|
|
|
|
|
<Tags /> Etichette
|
|
|
|
|
</button>
|
|
|
|
|
</ContextMenuItem>
|
2026-03-10 13:57:29 +01:00
|
|
|
</ContextMenuContent>
|
|
|
|
|
)}
|
2025-08-28 18:27:07 +02:00
|
|
|
data={tabledata}
|
2026-03-10 13:57:29 +01:00
|
|
|
defaultColumnVisibility={{
|
|
|
|
|
created_at: true,
|
|
|
|
|
email: true,
|
|
|
|
|
telefono: true,
|
|
|
|
|
isAdmin: true,
|
2026-03-10 18:05:15 +01:00
|
|
|
isBlocked: false,
|
2026-03-10 13:57:29 +01:00
|
|
|
username: true,
|
|
|
|
|
}}
|
2025-08-29 16:18:32 +02:00
|
|
|
defaultSort={[{ desc: true, id: "created_at" }]}
|
2025-08-28 18:27:07 +02:00
|
|
|
pinnedFiltri={pinnedFiltri}
|
|
|
|
|
searchColumn={searchFiltro}
|
2026-03-10 13:57:29 +01:00
|
|
|
withContextMenu={true}
|
2025-08-28 18:27:07 +02:00
|
|
|
/>
|
2026-03-10 16:56:26 +01:00
|
|
|
<UsersEtichetteModal selected={selected} setSelected={setSelected} />
|
2025-08-28 18:27:07 +02:00
|
|
|
</div>
|
|
|
|
|
);
|
2025-08-04 17:45:44 +02:00
|
|
|
};
|
2026-03-10 16:56:26 +01:00
|
|
|
|
|
|
|
|
const UsersEtichetteModal = ({
|
|
|
|
|
selected,
|
|
|
|
|
setSelected,
|
|
|
|
|
}: {
|
|
|
|
|
selected: { id: UsersId; etichette: Etichette[] } | null;
|
|
|
|
|
setSelected: React.Dispatch<
|
|
|
|
|
React.SetStateAction<{ id: UsersId; etichette: Etichette[] } | null>
|
|
|
|
|
>;
|
|
|
|
|
}) => {
|
|
|
|
|
const utils = api.useUtils();
|
|
|
|
|
|
|
|
|
|
const { data: etichette } = api.etichette.getAllEtichette.useQuery();
|
|
|
|
|
|
|
|
|
|
const { mutate: addEtichetta } = api.etichette.addUserEtichetta.useMutation({
|
|
|
|
|
onSuccess: async () => {
|
|
|
|
|
toast.success("Etichetta aggiunta con successo");
|
|
|
|
|
await utils.etichette.getAllEtichette.invalidate();
|
|
|
|
|
await utils.users.getUsersWChatInfo.invalidate();
|
|
|
|
|
},
|
|
|
|
|
onError: () => {
|
|
|
|
|
toast.error("Errore nell'aggiunta dell'etichetta");
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
const { mutate: removeEtichetta } =
|
|
|
|
|
api.etichette.removeUserEtichetta.useMutation({
|
|
|
|
|
onSuccess: async () => {
|
|
|
|
|
toast.success("Etichetta rimossa con successo");
|
|
|
|
|
await utils.etichette.getAllEtichette.invalidate();
|
|
|
|
|
await utils.users.getUsersWChatInfo.invalidate();
|
|
|
|
|
},
|
|
|
|
|
onError: () => {
|
|
|
|
|
toast.error("Errore nella rimozione dell'etichetta");
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Dialog
|
|
|
|
|
onOpenChange={(v) => {
|
|
|
|
|
if (!v) setSelected(null);
|
|
|
|
|
}}
|
|
|
|
|
open={!!selected}
|
|
|
|
|
>
|
|
|
|
|
<DialogContent>
|
|
|
|
|
<DialogHeader>
|
|
|
|
|
<DialogTitle>Etichette</DialogTitle>
|
|
|
|
|
<DialogDescription className="sr-only">Etichette</DialogDescription>
|
|
|
|
|
</DialogHeader>
|
|
|
|
|
<div className="space-y-5">
|
|
|
|
|
<div className="flex flex-col gap-2">
|
|
|
|
|
<h3>Etichette Attive</h3>
|
|
|
|
|
{selected?.etichette.map((etichetta) => (
|
|
|
|
|
<div
|
|
|
|
|
className="flex items-center gap-2"
|
|
|
|
|
key={`${etichetta.id_etichetta}${selected.id}`}
|
|
|
|
|
>
|
|
|
|
|
<Etichetta
|
|
|
|
|
color_hex={etichetta.color_hex}
|
|
|
|
|
title={etichetta.title}
|
|
|
|
|
/>
|
|
|
|
|
<Button
|
|
|
|
|
onClick={() => {
|
|
|
|
|
removeEtichetta({
|
|
|
|
|
userId: selected.id,
|
|
|
|
|
etichettaId: etichetta.id_etichetta,
|
|
|
|
|
});
|
|
|
|
|
setSelected((prev) => {
|
|
|
|
|
if (!prev) return prev;
|
|
|
|
|
return {
|
|
|
|
|
...prev,
|
|
|
|
|
etichette: prev.etichette.filter(
|
|
|
|
|
(e) => e.id_etichetta !== etichetta.id_etichetta,
|
|
|
|
|
),
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
}}
|
|
|
|
|
size="sm"
|
|
|
|
|
variant="destructive"
|
|
|
|
|
>
|
|
|
|
|
<X className="size-4" />
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
<Separator />
|
|
|
|
|
<div className="flex flex-col gap-2">
|
|
|
|
|
<h3>Aggiungi Etichetta</h3>
|
|
|
|
|
{etichette
|
|
|
|
|
?.filter(
|
|
|
|
|
(e) =>
|
|
|
|
|
!selected?.etichette.some(
|
|
|
|
|
(etichetta) => etichetta.id_etichetta === e.id_etichetta,
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
.map((e) => (
|
|
|
|
|
<div className="flex items-center gap-2" key={e.id_etichetta}>
|
|
|
|
|
<Etichetta color_hex={e.color_hex} title={e.title} />
|
|
|
|
|
<Button
|
|
|
|
|
onClick={() => {
|
|
|
|
|
if (selected) {
|
|
|
|
|
addEtichetta({
|
|
|
|
|
userId: selected.id,
|
|
|
|
|
etichettaId: e.id_etichetta,
|
|
|
|
|
});
|
|
|
|
|
setSelected((prev) => {
|
|
|
|
|
if (!prev) return prev;
|
|
|
|
|
return {
|
|
|
|
|
...prev,
|
|
|
|
|
etichette: [
|
|
|
|
|
...prev.etichette,
|
|
|
|
|
{
|
|
|
|
|
id_etichetta: e.id_etichetta,
|
|
|
|
|
color_hex: e.color_hex,
|
|
|
|
|
title: e.title,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
size="sm"
|
|
|
|
|
variant="success"
|
|
|
|
|
>
|
|
|
|
|
<Plus className="size-4" />
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</DialogContent>
|
|
|
|
|
</Dialog>
|
|
|
|
|
);
|
|
|
|
|
};
|