- Updated biome schema version from 2.2.2 to 2.3.1 in biome.json. - Removed experimentalScannerIgnores from files section and replaced with ignore patterns. - Added CSS parser configuration for Tailwind directives. - Updated linter rules for better code quality. - Refactored key usage in various components to use unique identifiers instead of array indices. - Updated package-lock.json and package.json to reflect new biome version. - General code cleanup and improvements across multiple components for better maintainability.
269 lines
6.8 KiB
TypeScript
269 lines
6.8 KiB
TypeScript
"use client";
|
|
import {
|
|
Info,
|
|
Paperclip,
|
|
ShieldUser,
|
|
ShoppingBag,
|
|
User,
|
|
UserCog,
|
|
} from "lucide-react";
|
|
import Image from "next/image";
|
|
import Link from "next/link";
|
|
import { useRouter } from "next/router";
|
|
import { useCallback } from "react";
|
|
import toast from "react-hot-toast";
|
|
import { EtichetteDisplayer } from "~/components/etichette";
|
|
import {
|
|
AlertDialog,
|
|
AlertDialogAction,
|
|
AlertDialogCancel,
|
|
AlertDialogContent,
|
|
AlertDialogDescription,
|
|
AlertDialogFooter,
|
|
AlertDialogHeader,
|
|
AlertDialogTitle,
|
|
AlertDialogTrigger,
|
|
} from "~/components/ui/alert-dialog";
|
|
import { Button, buttonVariants } from "~/components/ui/button";
|
|
import {
|
|
Popover,
|
|
PopoverContent,
|
|
PopoverTrigger,
|
|
} from "~/components/ui/popover";
|
|
import { Separator } from "~/components/ui/separator";
|
|
import {
|
|
Tooltip,
|
|
TooltipContent,
|
|
TooltipProvider,
|
|
TooltipTrigger,
|
|
} from "~/components/ui/tooltip";
|
|
import { UserAvatar } from "~/components/user_avatar";
|
|
import { cn } from "~/lib/utils";
|
|
import type { ChatsChatid } from "~/schemas/public/Chats";
|
|
import type { Session } from "~/server/api/trpc";
|
|
import type { ChatUserInfo } from "~/server/services/chat.service";
|
|
import type { OnlineStatus } from "~/server/sse";
|
|
import { api } from "~/utils/api";
|
|
|
|
type ChatTopbarProps = {
|
|
chatId: ChatsChatid;
|
|
userData: Session;
|
|
chatUserData: ChatUserInfo;
|
|
onlineStatus: OnlineStatus[];
|
|
};
|
|
export default function ChatTopbar({
|
|
chatId,
|
|
userData,
|
|
chatUserData,
|
|
onlineStatus,
|
|
}: ChatTopbarProps) {
|
|
const utils = api.useUtils();
|
|
const { mutate: deletechat } = api.chat.deleteChat.useMutation({
|
|
onSuccess: async () => {
|
|
await utils.chat.getActiveChats.invalidate();
|
|
await utils.users.getActiveUsersWithoutChat.invalidate();
|
|
await router.push("/area-riservata/admin/chats/");
|
|
},
|
|
});
|
|
|
|
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();
|
|
},
|
|
});
|
|
|
|
const handleDeleteChat = useCallback(() => {
|
|
deletechat({ chatId });
|
|
}, [chatId, deletechat]);
|
|
|
|
const handleSwapUser = useCallback(() => {
|
|
swap({ id: chatUserData.id });
|
|
}, [chatUserData, swap]);
|
|
|
|
return (
|
|
<div className="flex h-18 w-full items-center justify-between border-b px-4 py-2">
|
|
<div className="flex items-center gap-2">
|
|
{!userData.isAdmin ? (
|
|
<Image
|
|
alt="Infoalloggi logo"
|
|
className="size-10 rounded-full"
|
|
height={40}
|
|
src={"/favicon/favicon.png"}
|
|
width={40}
|
|
/>
|
|
) : (
|
|
<UserAvatar
|
|
className="size-10"
|
|
userId={chatUserData.id}
|
|
username={chatUserData.username}
|
|
/>
|
|
)}
|
|
<div className="flex flex-col gap-1">
|
|
<div className="flex gap-4">
|
|
<span className="font-medium">
|
|
{!userData.isAdmin ? "Chat Infoalloggi" : chatUserData.username}
|
|
</span>
|
|
{userData.isAdmin && <EtichetteDisplayer chatId={chatId} />}
|
|
</div>
|
|
<div className="flex flex-row items-center gap-2">
|
|
<UserStatus onlineStatus={onlineStatus} userData={userData} />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
{userData.isAdmin && (
|
|
<AdminPopover
|
|
chatUserData={chatUserData}
|
|
handleDeleteChat={handleDeleteChat}
|
|
handleSwapUser={handleSwapUser}
|
|
/>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const UserStatus = ({
|
|
onlineStatus,
|
|
userData,
|
|
}: {
|
|
onlineStatus: OnlineStatus[];
|
|
userData: Session;
|
|
}) => (
|
|
<div className="flex flex-row items-center gap-2">
|
|
{onlineStatus.map((user, idx) =>
|
|
user.isAdmin ? (
|
|
<TooltipProvider delayDuration={0} key={user.userId}>
|
|
<Tooltip>
|
|
<TooltipTrigger>
|
|
<span
|
|
className={cn(
|
|
"flex flex-row items-center font-bold text-green-500 text-xs",
|
|
)}
|
|
>
|
|
<ShieldUser className="mr-[0.2rem]" size={15} />
|
|
<span>
|
|
{user.nome}
|
|
{idx < onlineStatus.length - 1 && ","}
|
|
</span>
|
|
</span>
|
|
</TooltipTrigger>
|
|
<TooltipContent>
|
|
<p>Admin Infoalloggi</p>
|
|
</TooltipContent>
|
|
</Tooltip>
|
|
</TooltipProvider>
|
|
) : (
|
|
<span
|
|
className={cn("flex flex-row font-bold text-green-500 text-xs")}
|
|
key={user.userId}
|
|
>
|
|
<span>
|
|
{user.nome}
|
|
{!userData.isAdmin && " (Tu)"}
|
|
{idx < onlineStatus.length - 1 && ", "}
|
|
</span>
|
|
</span>
|
|
),
|
|
)}
|
|
</div>
|
|
);
|
|
|
|
const AdminPopover = ({
|
|
chatUserData,
|
|
handleSwapUser,
|
|
handleDeleteChat,
|
|
}: {
|
|
chatUserData: ChatUserInfo;
|
|
handleSwapUser: () => void;
|
|
handleDeleteChat: () => void;
|
|
}) => (
|
|
<Popover>
|
|
<PopoverTrigger
|
|
className={cn(
|
|
buttonVariants({ size: "icon", variant: "outline" }),
|
|
"size-10",
|
|
"dark:bg-muted dark:text-muted-foreground dark:hover:bg-muted dark:hover:text-white",
|
|
)}
|
|
>
|
|
<Info className="text-muted-foreground" size={24} />
|
|
</PopoverTrigger>
|
|
<PopoverContent className="mr-4 w-fit px-4">
|
|
<div className="flex flex-col gap-2">
|
|
<Link
|
|
aria-label="Visualizza Profilo Utente"
|
|
className={cn(
|
|
buttonVariants({ variant: "outline" }),
|
|
"justify-start gap-2",
|
|
)}
|
|
href={`/area-riservata/admin/user-view/edit-user/${chatUserData.id}`}
|
|
>
|
|
<UserCog /> Profilo
|
|
</Link>
|
|
|
|
<Link
|
|
aria-label="Visualizza Ordini Utente"
|
|
className={cn(
|
|
buttonVariants({ variant: "outline" }),
|
|
"justify-start gap-2",
|
|
)}
|
|
href={`/area-riservata/admin/user-view/ordini/${chatUserData.id}`}
|
|
>
|
|
<ShoppingBag /> Ordini
|
|
</Link>
|
|
<Link
|
|
aria-label="Visualizza Allegati Utente"
|
|
className={cn(
|
|
buttonVariants({ variant: "outline" }),
|
|
"justify-start gap-2",
|
|
)}
|
|
href={`/area-riservata/admin/user-view/allegati/${chatUserData.id}`}
|
|
>
|
|
<Paperclip /> Allegati
|
|
</Link>
|
|
<button
|
|
aria-label="Cambia Utente"
|
|
className={cn(
|
|
buttonVariants({ variant: "outline" }),
|
|
"justify-start gap-2",
|
|
)}
|
|
onClick={handleSwapUser}
|
|
type="button"
|
|
>
|
|
<User /> Login
|
|
</button>
|
|
<Separator />
|
|
<AlertDialog>
|
|
<AlertDialogTrigger asChild>
|
|
<Button size="sm" variant="destructive">
|
|
Cancella Chat
|
|
</Button>
|
|
</AlertDialogTrigger>
|
|
<AlertDialogContent>
|
|
<AlertDialogHeader>
|
|
<AlertDialogTitle>Sei assolutamente sicuro?</AlertDialogTitle>
|
|
<AlertDialogDescription>
|
|
Questa azione non può essere annullata. Questo eliminerà
|
|
definitivamente la chat e rimuoverà i dati dai nostri server.
|
|
</AlertDialogDescription>
|
|
</AlertDialogHeader>
|
|
<AlertDialogFooter>
|
|
<AlertDialogCancel>Annulla</AlertDialogCancel>
|
|
<AlertDialogAction
|
|
aria-label="Continua Eliminazione Chat"
|
|
className={cn(buttonVariants({ variant: "destructive" }))}
|
|
onClick={handleDeleteChat}
|
|
>
|
|
Continua
|
|
</AlertDialogAction>
|
|
</AlertDialogFooter>
|
|
</AlertDialogContent>
|
|
</AlertDialog>
|
|
</div>
|
|
</PopoverContent>
|
|
</Popover>
|
|
);
|