Files
reui-blocks/blocks/settings-members5.tsx
T

353 lines
13 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import {
Clock,
MoreVertical,
Send,
UserCheck,
UserPlus,
X,
} from "lucide-react";
import { useState } from "react";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { cn } from "@/lib/utils";
interface ActiveMember {
id: string;
name: string;
email: string;
role: string;
avatar?: string;
lastActive: string;
}
interface PendingInvite {
id: string;
email: string;
role: string;
sentAt: string;
expiresIn: string;
}
interface SettingsMembers5Props {
heading?: string;
description?: string;
activeMembers?: ActiveMember[];
pendingInvites?: PendingInvite[];
className?: string;
}
const SettingsMembers5 = ({
heading = "مدیریت تیم",
description = "اعضای فعال را ببینید و دعوت‌های در انتظار را مدیریت کنید.",
activeMembers = [
{
id: "1",
name: "Priya Sharma",
email: "priya@designlab.io",
role: "مالک",
avatar:
"/block-media/shadcnblocks/block/avatar/avatar11.jpg",
lastActive: "الان",
},
{
id: "2",
name: "Kevin O'Brien",
email: "kevin@designlab.io",
role: "مدیر",
avatar:
"/block-media/shadcnblocks/block/avatar/avatar12.jpg",
lastActive: "۲ ساعت پیش",
},
{
id: "3",
name: "Yuki Tanaka",
email: "yuki@designlab.io",
role: "ویرایشگر",
avatar:
"/block-media/shadcnblocks/block/avatar/avatar13.jpg",
lastActive: "دیروز",
},
{
id: "4",
name: "Carlos Mendez",
email: "carlos@designlab.io",
role: "ویرایشگر",
avatar:
"/block-media/shadcnblocks/block/avatar/avatar14.jpg",
lastActive: "۳ روز پیش",
},
],
pendingInvites = [
{
id: "p1",
email: "maya.wilson@gmail.com",
role: "ویرایشگر",
sentAt: "۱۵ ژانویه ۲۲۶",
expiresIn: "۵ روز",
},
{
id: "p2",
email: "alex.foster@outlook.com",
role: "بیننده",
sentAt: "۲۰ ژانویه ۲۲۶",
expiresIn: "۱۰ روز",
},
],
className,
}: SettingsMembers5Props) => {
const [isInviteOpen, setIsInviteOpen] = useState(false);
return (
<section className="py-32">
<div className="container max-w-3xl">
<div className={cn("space-y-6", className)}>
<div className="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
<div className="space-y-1">
<h2 className="text-xl font-semibold tracking-tight">
{heading}
</h2>
<p className="text-sm text-muted-foreground">{description}</p>
</div>
<Dialog open={isInviteOpen} onOpenChange={setIsInviteOpen}>
<DialogTrigger asChild>
<Button>
<UserPlus className="size-4" />
دعوت
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>دعوت عضو جدید</DialogTitle>
<DialogDescription>
دعوتنامه ایمیلی برای پیوستن به تیم ارسال کنید.
</DialogDescription>
</DialogHeader>
<form
onSubmit={(e) => {
e.preventDefault();
setIsInviteOpen(false);
}}
className="space-y-4"
>
<div className="space-y-2">
<Label htmlFor="new-email">آدرس ایمیل</Label>
<Input
id="new-email"
type="email"
placeholder="colleague@example.com"
/>
</div>
<div className="space-y-2">
<Label htmlFor="new-role">تعیین نقش</Label>
<Select defaultValue="editor">
<SelectTrigger id="new-role">
<SelectValue placeholder="انتخاب نقش" />
</SelectTrigger>
<SelectContent>
<SelectItem value="admin">مدیر</SelectItem>
<SelectItem value="editor">ویرایشگر</SelectItem>
<SelectItem value="viewer">بیننده</SelectItem>
</SelectContent>
</Select>
</div>
<DialogFooter>
<Button
type="button"
variant="outline"
onClick={() => setIsInviteOpen(false)}
>
انصراف
</Button>
<Button type="submit">
<Send className="size-4" />
ارسال دعوت
</Button>
</DialogFooter>
</form>
</DialogContent>
</Dialog>
</div>
<Tabs defaultValue="active" className="w-full">
<TabsList className="w-full justify-start">
<TabsTrigger value="active" className="gap-2">
<UserCheck className="size-4" />
فعال
<Badge
variant="secondary"
className="ms-1 size-5 justify-center rounded-full p-0 text-xs"
>
{activeMembers.length.toLocaleString("fa-IR")}
</Badge>
</TabsTrigger>
<TabsTrigger value="pending" className="gap-2">
<Clock className="size-4" />
در انتظار
{pendingInvites.length > 0 && (
<Badge
variant="secondary"
className="ms-1 size-5 justify-center rounded-full bg-amber-100 p-0 text-xs text-amber-700 dark:bg-amber-900/30 dark:text-amber-400"
>
{pendingInvites.length.toLocaleString("fa-IR")}
</Badge>
)}
</TabsTrigger>
</TabsList>
<TabsContent value="active" className="mt-4">
<div className="rounded-lg border">
<ul className="divide-y">
{activeMembers.map((member) => (
<li
key={member.id}
className="flex items-center justify-between gap-4 px-4 py-3"
>
<div className="flex items-center gap-3">
<Avatar className="size-10">
<AvatarImage src={member.avatar} alt={`تصویر ${member.name}`} />
<AvatarFallback>
{member.name
.split(" ")
.map((n) => n[0])
.join("")}
</AvatarFallback>
</Avatar>
<div>
<p className="text-sm font-medium">{member.name}</p>
<p className="text-xs text-muted-foreground">
{member.email}
</p>
</div>
</div>
<div className="flex items-center gap-3">
<div className="hidden text-end sm:block">
<Badge variant="outline" className="font-normal">
{member.role}
</Badge>
<p className="mt-1 text-xs text-muted-foreground">
{member.lastActive === "الان" ? (
<span className="flex items-center gap-1">
<span className="size-2 rounded-full bg-green-500" />
آنلاین
</span>
) : (
`فعال، ${member.lastActive}`
)}
</p>
</div>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
size="icon"
className="size-8"
>
<MoreVertical className="size-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem>ویرایش نقش</DropdownMenuItem>
<DropdownMenuItem>مشاهده پروفایل</DropdownMenuItem>
<DropdownMenuItem className="text-destructive">
حذف
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
</li>
))}
</ul>
</div>
</TabsContent>
<TabsContent value="pending" className="mt-4">
{pendingInvites.length === 0 ? (
<div className="flex flex-col items-center justify-center rounded-lg border border-dashed py-12 text-center">
<Clock className="mb-3 size-10 text-muted-foreground/50" />
<p className="text-sm font-medium">دعوت در انتظاری وجود ندارد</p>
<p className="text-xs text-muted-foreground">
برای شروع، اعضای تیم را دعوت کنید
</p>
</div>
) : (
<div className="rounded-lg border">
<ul className="divide-y">
{pendingInvites.map((invite) => (
<li
key={invite.id}
className="flex items-center justify-between gap-4 px-4 py-3"
>
<div className="flex items-center gap-3">
<div className="flex size-10 items-center justify-center rounded-full bg-muted">
<Clock className="size-4 text-muted-foreground" />
</div>
<div>
<p className="text-sm font-medium">
{invite.email}
</p>
<p className="text-xs text-muted-foreground">
ارسال‌شده {invite.sentAt} · انقضا تا{" "}
{invite.expiresIn}
</p>
</div>
</div>
<div className="flex items-center gap-2">
<Badge variant="outline" className="font-normal">
{invite.role}
</Badge>
<Button variant="ghost" size="sm">
<Send className="size-4" />
ارسال مجدد
</Button>
<Button
variant="ghost"
size="icon"
className="size-8 text-muted-foreground hover:text-destructive"
>
<X className="size-4" />
</Button>
</div>
</li>
))}
</ul>
</div>
)}
</TabsContent>
</Tabs>
</div>
</div>
</section>
);
};
export { SettingsMembers5 };