feat: enhance Potenziali management with delete functionality and user assignment
This commit is contained in:
parent
c459da5d23
commit
2ef18a0b5b
3 changed files with 316 additions and 111 deletions
|
|
@ -1,8 +1,8 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import { Plus } from "lucide-react";
|
import { Plus, Trash2 } from "lucide-react";
|
||||||
import { useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import {
|
import {
|
||||||
KanbanBoard,
|
KanbanBoard,
|
||||||
KanbanCard,
|
KanbanCard,
|
||||||
|
|
@ -12,7 +12,10 @@ import {
|
||||||
} from "~/components/ui/kanban";
|
} from "~/components/ui/kanban";
|
||||||
import { usePotenziali } from "~/providers/PotenzialiProvider";
|
import { usePotenziali } from "~/providers/PotenzialiProvider";
|
||||||
import type { PotenzialiGroupsId } from "~/schemas/public/PotenzialiGroups";
|
import type { PotenzialiGroupsId } from "~/schemas/public/PotenzialiGroups";
|
||||||
|
import type { UsersId } from "~/schemas/public/Users";
|
||||||
import type { PotenzialeData } from "~/server/services/potenziali.service";
|
import type { PotenzialeData } from "~/server/services/potenziali.service";
|
||||||
|
import { api } from "~/utils/api";
|
||||||
|
import { Confirm } from "../confirm";
|
||||||
import {
|
import {
|
||||||
Credenza,
|
Credenza,
|
||||||
CredenzaBody,
|
CredenzaBody,
|
||||||
|
|
@ -28,11 +31,19 @@ import Input from "../custom_ui/input";
|
||||||
import { Textarea } from "../custom_ui/textarea";
|
import { Textarea } from "../custom_ui/textarea";
|
||||||
import { Button } from "../ui/button";
|
import { Button } from "../ui/button";
|
||||||
import { Label } from "../ui/label";
|
import { Label } from "../ui/label";
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectGroup,
|
||||||
|
SelectItem,
|
||||||
|
SelectLabel,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "../ui/select";
|
||||||
import { UserAvatar } from "../user_avatar";
|
import { UserAvatar } from "../user_avatar";
|
||||||
|
|
||||||
export const Potenziali = () => {
|
export const Potenziali = () => {
|
||||||
const { data, columns, setData, updateCall, setEditing, editingItem } =
|
const { data, columns, setData, updateCall, removeColumn } = usePotenziali();
|
||||||
usePotenziali();
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<KanbanProvider
|
<KanbanProvider
|
||||||
|
|
@ -59,24 +70,57 @@ export const Potenziali = () => {
|
||||||
<span>{column.name}</span>
|
<span>{column.name}</span>
|
||||||
|
|
||||||
<NewCard columnId={column.id} />
|
<NewCard columnId={column.id} />
|
||||||
|
<Confirm
|
||||||
|
description="Sei sicuro di voler eliminare?"
|
||||||
|
onConfirm={() => {
|
||||||
|
removeColumn(column.id);
|
||||||
|
}}
|
||||||
|
title="Elimina"
|
||||||
|
>
|
||||||
|
<Button aria-label="Delete" variant="destructive">
|
||||||
|
<Trash2 />
|
||||||
|
</Button>
|
||||||
|
</Confirm>
|
||||||
</div>
|
</div>
|
||||||
</KanbanHeader>
|
</KanbanHeader>
|
||||||
<KanbanCards className="w-68" id={column.id}>
|
<KanbanCards className="w-68" id={column.id}>
|
||||||
{(data: PotenzialeData) => (
|
{(data: PotenzialeData) => (
|
||||||
|
<PotenzialeCardItem
|
||||||
|
columnId={column.id}
|
||||||
|
data={data}
|
||||||
|
key={data.id}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</KanbanCards>
|
||||||
|
</KanbanBoard>
|
||||||
|
)}
|
||||||
|
</KanbanProvider>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
// 1. Extract the card logic into a separate component
|
||||||
|
const PotenzialeCardItem = ({
|
||||||
|
data,
|
||||||
|
columnId,
|
||||||
|
}: {
|
||||||
|
data: PotenzialeData;
|
||||||
|
columnId: string;
|
||||||
|
}) => {
|
||||||
|
const [isEditingOpen, setIsEditingOpen] = useState(false);
|
||||||
|
return (
|
||||||
<KanbanCard
|
<KanbanCard
|
||||||
cardOnClick={() => {
|
cardOnClick={() => {
|
||||||
setEditing(data.id);
|
setIsEditingOpen(true);
|
||||||
}}
|
}}
|
||||||
column={column.id}
|
column={columnId}
|
||||||
id={data.id}
|
id={data.id}
|
||||||
key={data.id}
|
key={data.id}
|
||||||
name={data.name}
|
name={data.name}
|
||||||
>
|
>
|
||||||
|
<>
|
||||||
<div className="flex items-start justify-between gap-2">
|
<div className="flex items-start justify-between gap-2">
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<p className="m-0 flex-1 font-medium text-sm">
|
<p className="m-0 flex-1 font-medium text-sm">{data.name}</p>
|
||||||
{data.name}
|
|
||||||
</p>
|
|
||||||
<p className="m-0 text-muted-foreground text-xs">
|
<p className="m-0 text-muted-foreground text-xs">
|
||||||
{data.descrizione}
|
{data.descrizione}
|
||||||
</p>
|
</p>
|
||||||
|
|
@ -92,31 +136,27 @@ export const Potenziali = () => {
|
||||||
<p className="mt-2 text-muted-foreground text-xs">
|
<p className="mt-2 text-muted-foreground text-xs">
|
||||||
{format(data.created_at, "dd/MM/yyyy HH:mm")}
|
{format(data.created_at, "dd/MM/yyyy HH:mm")}
|
||||||
</p>
|
</p>
|
||||||
</KanbanCard>
|
{/** biome-ignore lint/a11y/noNoninteractiveElementInteractions: <ok> */}
|
||||||
)}
|
{/** biome-ignore lint/a11y/noStaticElementInteractions: <ok> */}
|
||||||
</KanbanCards>
|
{/** biome-ignore lint/a11y/useKeyWithClickEvents: <ok> */}
|
||||||
</KanbanBoard>
|
<div onClick={(e) => e.stopPropagation()}>
|
||||||
)}
|
<EditingItem
|
||||||
</KanbanProvider>
|
data={data}
|
||||||
<Credenza
|
open={isEditingOpen}
|
||||||
onOpenChange={(v) => {
|
setOpen={setIsEditingOpen}
|
||||||
if (!v) {
|
/>
|
||||||
setEditing(null);
|
</div>
|
||||||
}
|
|
||||||
}}
|
|
||||||
open={!!editingItem}
|
|
||||||
>
|
|
||||||
<EditingContent />
|
|
||||||
</Credenza>
|
|
||||||
</>
|
</>
|
||||||
|
</KanbanCard>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const NewColumn = () => {
|
export const NewColumn = () => {
|
||||||
const [newColumnName, setNewColumnName] = useState("");
|
const [newColumnName, setNewColumnName] = useState("");
|
||||||
const { addColumn } = usePotenziali();
|
const { addColumn } = usePotenziali();
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
return (
|
return (
|
||||||
<Credenza>
|
<Credenza onOpenChange={setOpen} open={open}>
|
||||||
<CredenzaTrigger asChild>
|
<CredenzaTrigger asChild>
|
||||||
<Button>Nuova colonna</Button>
|
<Button>Nuova colonna</Button>
|
||||||
</CredenzaTrigger>
|
</CredenzaTrigger>
|
||||||
|
|
@ -141,6 +181,7 @@ export const NewColumn = () => {
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
addColumn(newColumnName);
|
addColumn(newColumnName);
|
||||||
setNewColumnName("");
|
setNewColumnName("");
|
||||||
|
setOpen(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Aggiungi
|
Aggiungi
|
||||||
|
|
@ -154,18 +195,32 @@ export const NewColumn = () => {
|
||||||
export const NewCard = ({ columnId }: { columnId: PotenzialiGroupsId }) => {
|
export const NewCard = ({ columnId }: { columnId: PotenzialiGroupsId }) => {
|
||||||
const [newItemName, setNewItemName] = useState("");
|
const [newItemName, setNewItemName] = useState("");
|
||||||
const [newItemDescrizione, setNewItemDescrizione] = useState("");
|
const [newItemDescrizione, setNewItemDescrizione] = useState("");
|
||||||
|
const [newItemUserid, setNewItemUserid] = useState<UsersId | null>(null);
|
||||||
const { addItem } = usePotenziali();
|
const { addItem } = usePotenziali();
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
|
const resetState = () => {
|
||||||
|
setNewItemName("");
|
||||||
|
setNewItemDescrizione("");
|
||||||
|
setNewItemUserid(null);
|
||||||
|
};
|
||||||
const handleAddItem = () => {
|
const handleAddItem = () => {
|
||||||
addItem({
|
addItem({
|
||||||
name: newItemName,
|
name: newItemName,
|
||||||
descrizione: newItemDescrizione,
|
descrizione: newItemDescrizione,
|
||||||
potenziali_group_id: columnId,
|
potenziali_group_id: columnId,
|
||||||
|
userid: newItemUserid,
|
||||||
});
|
});
|
||||||
setNewItemName("");
|
resetState();
|
||||||
setNewItemDescrizione("");
|
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (open) {
|
||||||
|
resetState();
|
||||||
|
}
|
||||||
|
}, [open]);
|
||||||
|
const { data: admins, isLoading } = api.users.getAdmins.useQuery();
|
||||||
return (
|
return (
|
||||||
<Credenza onOpenChange={setOpen} open={open}>
|
<Credenza onOpenChange={setOpen} open={open}>
|
||||||
<CredenzaTrigger asChild>
|
<CredenzaTrigger asChild>
|
||||||
|
|
@ -197,26 +252,86 @@ export const NewCard = ({ columnId }: { columnId: PotenzialiGroupsId }) => {
|
||||||
placeholder=""
|
placeholder=""
|
||||||
value={newItemDescrizione}
|
value={newItemDescrizione}
|
||||||
/>
|
/>
|
||||||
|
<Label htmlFor="utente">Utente Assegnato</Label>
|
||||||
|
{isLoading ? (
|
||||||
|
<p>Loading...</p>
|
||||||
|
) : (
|
||||||
|
<Select
|
||||||
|
onValueChange={(v) => {
|
||||||
|
setNewItemUserid(v === "empty" ? null : (v as UsersId));
|
||||||
|
}}
|
||||||
|
value={newItemUserid || "empty"}
|
||||||
|
>
|
||||||
|
<SelectTrigger
|
||||||
|
className="w-full data-[size=default]:h-10"
|
||||||
|
id="utente"
|
||||||
|
>
|
||||||
|
<SelectValue placeholder="Assegna un Utente" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectGroup>
|
||||||
|
<SelectLabel>Utente Assegnato</SelectLabel>
|
||||||
|
|
||||||
|
<SelectItem className="h-10" key="empty" value="empty">
|
||||||
|
nessuno
|
||||||
|
</SelectItem>
|
||||||
|
{admins?.map((admin) => (
|
||||||
|
<SelectItem key={admin.id} value={admin.id.toString()}>
|
||||||
|
<span className="flex items-center gap-2">
|
||||||
|
<UserAvatar
|
||||||
|
className="size-8"
|
||||||
|
userId={admin.id}
|
||||||
|
username={admin.username}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<span>
|
||||||
|
<span className="block font-medium">
|
||||||
|
{admin.username}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectGroup>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
)}
|
||||||
</CredenzaBody>
|
</CredenzaBody>
|
||||||
<CredenzaFooter>
|
<CredenzaFooter>
|
||||||
<Button disabled={!newItemName.length} onClick={handleAddItem}>
|
<Button disabled={!newItemName.length} onClick={handleAddItem}>
|
||||||
Aggiungi
|
Aggiungi
|
||||||
</Button>
|
</Button>
|
||||||
<CredenzaClose>Chiudi</CredenzaClose>
|
<CredenzaClose asChild>
|
||||||
|
<Button>Chiudi</Button>
|
||||||
|
</CredenzaClose>
|
||||||
</CredenzaFooter>
|
</CredenzaFooter>
|
||||||
</CredenzaContent>
|
</CredenzaContent>
|
||||||
</Credenza>
|
</Credenza>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const EditingContent = () => {
|
const EditingItem = ({
|
||||||
const { editingItem, updateItem } = usePotenziali();
|
open,
|
||||||
|
setOpen,
|
||||||
|
data,
|
||||||
|
}: {
|
||||||
|
open: boolean;
|
||||||
|
setOpen: (open: boolean) => void;
|
||||||
|
data: PotenzialeData;
|
||||||
|
}) => {
|
||||||
|
const { updateItem, removeItem } = usePotenziali();
|
||||||
|
|
||||||
const [state, setState] = useState<PotenzialeData | null>(editingItem);
|
const [state, setState] = useState<PotenzialeData>(data);
|
||||||
const [hasChanges, setHasChanges] = useState(false);
|
const [hasChanges, setHasChanges] = useState(false);
|
||||||
if (!state) return null;
|
const { data: admins, isLoading } = api.users.getAdmins.useQuery();
|
||||||
|
useEffect(() => {
|
||||||
|
if (open) {
|
||||||
|
setState(data);
|
||||||
|
setHasChanges(false);
|
||||||
|
}
|
||||||
|
}, [open]);
|
||||||
return (
|
return (
|
||||||
|
<Credenza onOpenChange={setOpen} open={open}>
|
||||||
<CredenzaContent className="max-h-[90vh]">
|
<CredenzaContent className="max-h-[90vh]">
|
||||||
<CredenzaHeader>
|
<CredenzaHeader>
|
||||||
<CredenzaTitle className="text-center font-semibold text-2xl">
|
<CredenzaTitle className="text-center font-semibold text-2xl">
|
||||||
|
|
@ -249,19 +364,89 @@ const EditingContent = () => {
|
||||||
placeholder=""
|
placeholder=""
|
||||||
value={state.descrizione || undefined}
|
value={state.descrizione || undefined}
|
||||||
/>
|
/>
|
||||||
|
<Label htmlFor="utente">Utente Assegnato</Label>
|
||||||
|
{isLoading ? (
|
||||||
|
<p>Loading...</p>
|
||||||
|
) : (
|
||||||
|
<Select
|
||||||
|
onValueChange={(v) => {
|
||||||
|
setState(
|
||||||
|
(prev) =>
|
||||||
|
prev && {
|
||||||
|
...prev,
|
||||||
|
userid: v === "empty" ? null : (v as UsersId),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
setHasChanges(true);
|
||||||
|
}}
|
||||||
|
value={state.userid?.toString() || "empty"}
|
||||||
|
>
|
||||||
|
<SelectTrigger
|
||||||
|
className="w-full data-[size=default]:h-10"
|
||||||
|
id="utente"
|
||||||
|
>
|
||||||
|
<SelectValue placeholder="Assegna un Utente" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectGroup>
|
||||||
|
<SelectLabel>Utente Assegnato</SelectLabel>
|
||||||
|
|
||||||
|
<SelectItem className="h-10" key="empty" value="empty">
|
||||||
|
nessuno
|
||||||
|
</SelectItem>
|
||||||
|
{admins?.map((admin) => (
|
||||||
|
<SelectItem key={admin.id} value={admin.id.toString()}>
|
||||||
|
<span className="flex items-center gap-2">
|
||||||
|
<UserAvatar
|
||||||
|
className="size-8"
|
||||||
|
userId={admin.id}
|
||||||
|
username={admin.username}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<span>
|
||||||
|
<span className="block font-medium">
|
||||||
|
{admin.username}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectGroup>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
)}
|
||||||
</CredenzaBody>
|
</CredenzaBody>
|
||||||
<CredenzaFooter>
|
<CredenzaFooter>
|
||||||
<Button
|
<Button
|
||||||
disabled={!hasChanges || !state}
|
disabled={!hasChanges || !state}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
updateItem(state);
|
updateItem(state);
|
||||||
|
setHasChanges(false);
|
||||||
}}
|
}}
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
Salva
|
Salva
|
||||||
</Button>
|
</Button>
|
||||||
<CredenzaClose>Chiudi</CredenzaClose>
|
<Confirm
|
||||||
|
description="Sei sicuro di voler eliminare?"
|
||||||
|
onConfirm={() => {
|
||||||
|
if (state) {
|
||||||
|
setOpen(false);
|
||||||
|
removeItem(state.id);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
title="Elimina"
|
||||||
|
>
|
||||||
|
<Button aria-label="Delete" variant="destructive">
|
||||||
|
<Trash2 />
|
||||||
|
<span>Elimina</span>
|
||||||
|
</Button>
|
||||||
|
</Confirm>
|
||||||
|
<CredenzaClose asChild>
|
||||||
|
<Button>Chiudi</Button>
|
||||||
|
</CredenzaClose>
|
||||||
</CredenzaFooter>
|
</CredenzaFooter>
|
||||||
</CredenzaContent>
|
</CredenzaContent>
|
||||||
|
</Credenza>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,21 @@
|
||||||
import { createContext, useContext, useState } from "react";
|
import { createContext, useContext } from "react";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
import type { NewPotenziali, PotenzialiId } from "~/schemas/public/Potenziali";
|
import type { NewPotenziali, PotenzialiId } from "~/schemas/public/Potenziali";
|
||||||
import type { PotenzialiGroups } from "~/schemas/public/PotenzialiGroups";
|
import type {
|
||||||
|
PotenzialiGroups,
|
||||||
|
PotenzialiGroupsId,
|
||||||
|
} from "~/schemas/public/PotenzialiGroups";
|
||||||
import type { PotenzialeData } from "~/server/services/potenziali.service";
|
import type { PotenzialeData } from "~/server/services/potenziali.service";
|
||||||
import { api } from "~/utils/api";
|
import { api } from "~/utils/api";
|
||||||
|
|
||||||
type PotenzialiContextType = {
|
type PotenzialiContextType = {
|
||||||
data: PotenzialeData[];
|
data: PotenzialeData[];
|
||||||
columns: PotenzialiGroups[];
|
columns: PotenzialiGroups[];
|
||||||
editingItem: PotenzialeData | null;
|
|
||||||
setData: (data: PotenzialeData[]) => void;
|
setData: (data: PotenzialeData[]) => void;
|
||||||
updateCall: () => void;
|
updateCall: () => void;
|
||||||
setEditing: (id: PotenzialiId | null) => void;
|
|
||||||
addItem: (item: NewPotenziali) => void;
|
addItem: (item: NewPotenziali) => void;
|
||||||
removeItem: (id: PotenzialiId) => void;
|
removeItem: (id: PotenzialiId) => void;
|
||||||
|
removeColumn: (id: PotenzialiGroupsId) => void;
|
||||||
addColumn: (name: string) => void;
|
addColumn: (name: string) => void;
|
||||||
updateItem: (item: PotenzialeData) => void;
|
updateItem: (item: PotenzialeData) => void;
|
||||||
};
|
};
|
||||||
|
|
@ -28,13 +30,6 @@ export const PotenzialiProvider = ({ children }: PotenzialiProviderProps) => {
|
||||||
|
|
||||||
const { data: columns } = api.potenziali.getPotenzialiGroups.useQuery();
|
const { data: columns } = api.potenziali.getPotenzialiGroups.useQuery();
|
||||||
|
|
||||||
const [editingItem, setEditingItem] = useState<PotenzialeData | null>(null);
|
|
||||||
|
|
||||||
const setEditing = (id: PotenzialiId | null) => {
|
|
||||||
const item = data?.find((item) => item.id === id) || null;
|
|
||||||
setEditingItem(item);
|
|
||||||
};
|
|
||||||
|
|
||||||
const utils = api.useUtils();
|
const utils = api.useUtils();
|
||||||
const { mutate: addItemMutation } = api.potenziali.addPotenziale.useMutation({
|
const { mutate: addItemMutation } = api.potenziali.addPotenziale.useMutation({
|
||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
|
|
@ -100,9 +95,27 @@ export const PotenzialiProvider = ({ children }: PotenzialiProviderProps) => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const updateItem = (item: PotenzialeData) => {
|
const updateItem = (item: PotenzialeData) => {
|
||||||
|
const { column, username: _username, ...rest } = item;
|
||||||
updateItemMutation({
|
updateItemMutation({
|
||||||
potenzialiId: item.id,
|
potenzialiId: item.id,
|
||||||
data: item,
|
data: {
|
||||||
|
...rest,
|
||||||
|
potenziali_group_id: column as PotenzialiGroupsId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const { mutate: removeColumnMutation } =
|
||||||
|
api.potenziali.deletePotenzialeGroup.useMutation({
|
||||||
|
onSuccess: async () => {
|
||||||
|
toast.success("Colonna rimossa con successo");
|
||||||
|
await utils.potenziali.getPotenziali.invalidate();
|
||||||
|
await utils.potenziali.getPotenzialiGroups.invalidate();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const removeColumn = (id: PotenzialiGroupsId) => {
|
||||||
|
removeColumnMutation({
|
||||||
|
potenzialiGroupId: id,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -111,14 +124,13 @@ export const PotenzialiProvider = ({ children }: PotenzialiProviderProps) => {
|
||||||
value={{
|
value={{
|
||||||
data: data || [],
|
data: data || [],
|
||||||
columns: columns || [],
|
columns: columns || [],
|
||||||
editingItem,
|
|
||||||
setData,
|
setData,
|
||||||
updateCall,
|
updateCall,
|
||||||
setEditing,
|
|
||||||
addItem,
|
addItem,
|
||||||
removeItem,
|
removeItem,
|
||||||
addColumn,
|
addColumn,
|
||||||
updateItem,
|
updateItem,
|
||||||
|
removeColumn,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|
|
||||||
|
|
@ -98,4 +98,12 @@ export const usersRouter = createTRPCRouter({
|
||||||
getUsersWChatInfo: adminProcedure.query(async () => {
|
getUsersWChatInfo: adminProcedure.query(async () => {
|
||||||
return await getUsersWithChatInfoHandler({ db });
|
return await getUsersWithChatInfoHandler({ db });
|
||||||
}),
|
}),
|
||||||
|
getAdmins: adminProcedure.query(async () => {
|
||||||
|
return await db
|
||||||
|
.selectFrom("users")
|
||||||
|
.selectAll()
|
||||||
|
.where("isAdmin", "=", true)
|
||||||
|
.orderBy("id", "desc")
|
||||||
|
.execute();
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue