273 lines
8.1 KiB
TypeScript
273 lines
8.1 KiB
TypeScript
"use client";
|
|
|
|
import { CornerDownLeft, MoreHorizontalIcon, Search } from "lucide-react";
|
|
import { useMemo, useState } from "react";
|
|
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogFooter,
|
|
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 { cn } from "@/lib/utils";
|
|
|
|
interface User {
|
|
name: string;
|
|
email: string;
|
|
accessLevel: string;
|
|
status?: string;
|
|
image?: string;
|
|
}
|
|
|
|
interface Cta {
|
|
title: string;
|
|
ctaText: string;
|
|
ctaLink: string;
|
|
}
|
|
|
|
interface SettingsMembers2Props {
|
|
heading?: string;
|
|
subHeading?: Cta;
|
|
users?: User[];
|
|
className?: string;
|
|
}
|
|
|
|
const SettingsMembers2 = ({
|
|
heading = "اعضای فضای کاری",
|
|
subHeading = {
|
|
title:
|
|
"همکاران فروش و پشتیبانی را دعوت کنید و سطح دسترسی هر عضو به CRM را تعیین کنید.",
|
|
ctaText: "راهنمای نقشها و دسترسیها",
|
|
ctaLink: "#",
|
|
},
|
|
users = [
|
|
{
|
|
name: "سارا مرتضوی",
|
|
email: "sofia.m@example.com",
|
|
accessLevel: "مالک فضای کاری",
|
|
image:
|
|
"/block-media/shadcnblocks/block/avatar/avatar2.jpg",
|
|
},
|
|
{
|
|
name: "امیر چناری",
|
|
email: "alex.c@example.com",
|
|
accessLevel: "فروشنده",
|
|
status: "دعوت در انتظار",
|
|
},
|
|
{
|
|
name: "ژوبین بلاکی",
|
|
email: "jordan.b@example.com",
|
|
accessLevel: "فقط مشاهده",
|
|
image:
|
|
"/block-media/shadcnblocks/block/avatar/avatar3.jpg",
|
|
},
|
|
{
|
|
name: "مریم رئیسی",
|
|
email: "morgan.r@example.com",
|
|
accessLevel: "فروشنده",
|
|
status: "دعوت در انتظار",
|
|
},
|
|
],
|
|
className,
|
|
}: SettingsMembers2Props) => {
|
|
const [searchValue, setSearchValue] = useState("");
|
|
|
|
const filteredUsers = useMemo(() => {
|
|
return users.filter((user) => {
|
|
return (
|
|
user.name.toLowerCase().includes(searchValue.toLowerCase()) ||
|
|
user.email.toLowerCase().includes(searchValue.toLowerCase())
|
|
);
|
|
});
|
|
}, [users, searchValue]);
|
|
|
|
return (
|
|
<section dir="rtl" lang="fa" className={cn("w-full py-32", className)}>
|
|
<div className="w-full px-4 sm:px-6 lg:px-8">
|
|
<div className="flex w-full flex-col gap-6">
|
|
<div className="space-y-4">
|
|
<h3 className="text-xl font-semibold tracking-tight">{heading}</h3>
|
|
<CtaText cta={subHeading} />
|
|
</div>
|
|
<div className="space-y-4">
|
|
<div className="flex items-center justify-between gap-3">
|
|
<div className="relative w-full max-w-56 min-w-20">
|
|
<Search className="absolute top-1/2 start-2 size-4 -translate-y-1/2 text-muted-foreground" />
|
|
<Input
|
|
placeholder="جستجوی عضو…"
|
|
className="ps-7"
|
|
value={searchValue}
|
|
onChange={(e) => setSearchValue(e.target.value)}
|
|
/>
|
|
</div>
|
|
<InviteUserForm />
|
|
</div>
|
|
|
|
<p className="text-xs font-semibold text-muted-foreground">
|
|
{filteredUsers.length.toLocaleString("fa-IR")} عضو فعال
|
|
</p>
|
|
|
|
<UsersList users={filteredUsers} />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
};
|
|
|
|
export { SettingsMembers2 };
|
|
|
|
const InviteUserForm = () => {
|
|
return (
|
|
<Dialog>
|
|
<DialogTrigger asChild>
|
|
<Button>دعوت عضو</Button>
|
|
</DialogTrigger>
|
|
<DialogContent className="gap-0 overflow-hidden p-0">
|
|
<DialogTitle className="flex items-center gap-2 border-b p-4 text-sm font-medium">
|
|
دعوت به فضای کاری
|
|
</DialogTitle>
|
|
<form
|
|
autoComplete="off"
|
|
onSubmit={(e) => e.preventDefault()}
|
|
className="flex flex-col gap-4 bg-muted pt-4"
|
|
>
|
|
<div className="flex flex-col gap-4 px-4">
|
|
<div className="space-y-1">
|
|
<Label className="text-xs">ایمیل سازمانی</Label>
|
|
<Input
|
|
placeholder="name@yourcompany.com"
|
|
className="bg-background"
|
|
/>
|
|
</div>
|
|
<div className="space-y-1">
|
|
<Label className="text-xs">انتخاب نقش</Label>
|
|
<Select defaultValue="editor">
|
|
<SelectTrigger className="w-full bg-background">
|
|
<SelectValue placeholder="انتخاب نقش" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="owner">مالک فضای کاری</SelectItem>
|
|
<SelectItem value="editor">فروشنده</SelectItem>
|
|
<SelectItem value="viewer">فقط مشاهده</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
</div>
|
|
<DialogFooter className="border-t bg-background px-4 py-3">
|
|
<Button size="sm" type="submit">
|
|
ارسال دعوتنامه <CornerDownLeft className="rtl:rotate-180" />
|
|
</Button>
|
|
</DialogFooter>
|
|
</form>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
};
|
|
|
|
interface CtaTextProps {
|
|
cta: Cta;
|
|
}
|
|
|
|
const CtaText = ({ cta }: CtaTextProps) => {
|
|
return (
|
|
<p className="text-xs text-muted-foreground sm:text-sm">
|
|
{cta.title}{" "}
|
|
<a href={cta.ctaLink} className="whitespace-nowrap underline">
|
|
{cta.ctaText}
|
|
</a>
|
|
</p>
|
|
);
|
|
};
|
|
|
|
interface UserCardProps {
|
|
user: User;
|
|
}
|
|
|
|
const UserCard = ({ user }: UserCardProps) => {
|
|
return (
|
|
<div className="flex w-full items-center justify-between">
|
|
<div className="flex items-center gap-2 sm:flex-2/3">
|
|
<div className="flex size-10 items-center justify-center overflow-hidden rounded-full bg-muted">
|
|
{user.image ? (
|
|
<img
|
|
src={user.image}
|
|
alt={`آواتار ${user.name}`}
|
|
className="size-full object-cover"
|
|
/>
|
|
) : (
|
|
<span className="text-sm font-medium">{user.name.charAt(0)}</span>
|
|
)}
|
|
</div>
|
|
<div className="text-sm font-medium">
|
|
<p>{user.name}</p>
|
|
<p className="text-xs text-muted-foreground">{user.email}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex items-center justify-between gap-3 sm:flex-1/3">
|
|
<Select defaultValue={user.accessLevel}>
|
|
<SelectTrigger className="min-w-24">
|
|
<SelectValue placeholder="انتخاب نقش" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="مالک فضای کاری">مالک فضای کاری</SelectItem>
|
|
<SelectItem value="فروشنده">فروشنده</SelectItem>
|
|
<SelectItem value="فقط مشاهده">فقط مشاهده</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild>
|
|
<Button variant="outline" aria-label="گزینههای بیشتر" size="icon-sm">
|
|
<MoreHorizontalIcon />
|
|
</Button>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent className="w-fit max-w-56" align="end">
|
|
<DropdownMenuItem>انتقال مالکیت فضای کاری</DropdownMenuItem>
|
|
<DropdownMenuItem>حذف از فضای کاری</DropdownMenuItem>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
interface UsersListProps {
|
|
users: User[];
|
|
}
|
|
|
|
const UsersList = ({ users }: UsersListProps) => {
|
|
return (
|
|
<ul className="overflow-x-auto">
|
|
{users.map((user, i) => {
|
|
return (
|
|
<li
|
|
key={`user-card-${i}`}
|
|
className="w-full min-w-80 shrink-0 border-b py-3 first:pt-0"
|
|
>
|
|
<UserCard user={user} />
|
|
</li>
|
|
);
|
|
})}
|
|
</ul>
|
|
);
|
|
};
|