Files
reui-blocks/blocks/invite-user3.tsx
T

313 lines
8.2 KiB
TypeScript

"use client";
import { Check, MailIcon, MoreHorizontal, UserIcon } from "lucide-react";
import { useState } from "react";
import {
Tags,
TagsContent,
TagsEmpty,
TagsGroup,
TagsInput,
TagsItem,
TagsList,
TagsTrigger,
TagsValue,
} from "@/components/kibo-ui/tags";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { cn } from "@/lib/utils";
interface User {
id: number;
name: string;
email: string;
status?: "Pending" | "Accepted";
}
interface UsersTableProps {
users: User[];
}
const UsersTable = ({ users }: UsersTableProps) => {
const columns = [
{
label: "نام",
icon: UserIcon,
},
{
label: "ایمیل",
icon: MailIcon,
},
];
return (
<div className="space-y-2 text-start">
<p className="text-sm font-medium sm:text-base">کاربران دعوت‌شده</p>
<Table>
<TableHeader>
<TableRow>
{columns.map((column, i) => (
<TableHead key={`col-${column.label}-${i}`}>
<div className="flex items-center gap-1 text-xs text-muted-foreground">
<column.icon className="size-3.5" />
<span>{column.label}</span>
</div>
</TableHead>
))}
<TableHead />
<TableHead />
</TableRow>
</TableHeader>
<TableBody>
{users.map((user) => (
<TableRow key={`user-${user.id}`}>
<TableCell>{user.name}</TableCell>
<TableCell dir="rtl" className="text-end">{user.email}</TableCell>
<TableCell>
<Badge
className={
user.status === "Accepted"
? "bg-green-100 text-green-800"
: "bg-yellow-100 text-yellow-800"
}
>
{user.status === "Accepted" ? "پذیرفته" : "در انتظار"}
</Badge>
</TableCell>
<TableCell>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon-sm">
<MoreHorizontal className="size-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem variant="destructive">
لغو دسترسی
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
);
};
interface InviteUserFormProps {
value: string[];
options: {
value: string;
label: string;
}[];
onToggle: (value: string) => void;
}
const InviteUserForm = ({ value, options, onToggle }: InviteUserFormProps) => {
const [searchValue, setSearchValue] = useState("");
const handleCreateEmail = () => {
if (searchValue.trim() && !value.includes(searchValue.trim())) {
onToggle(searchValue.trim());
setSearchValue("");
}
};
return (
<form
autoComplete="off"
onSubmit={(e) => e.preventDefault()}
className="space-y-2 text-start"
>
<p className="text-sm font-medium sm:text-base">دعوت کاربر</p>
<div className="flex flex-wrap items-start gap-2 sm:flex-nowrap">
<Tags>
<TagsTrigger>
{value.map((tagValue) => {
const option = options.find((opt) => opt.value === tagValue);
return (
<TagsValue key={tagValue} onRemove={() => onToggle(tagValue)}>
{option?.label || tagValue}
</TagsValue>
);
})}
</TagsTrigger>
<TagsContent>
<TagsInput
placeholder="جستجوی کاربران..."
value={searchValue}
onValueChange={setSearchValue}
/>
<TagsList>
<TagsEmpty>
{searchValue.trim() && (
<Button
variant="ghost"
onClick={handleCreateEmail}
className="m-1 w-full justify-start"
>
ایجاد «{searchValue.trim()}»
</Button>
)}
</TagsEmpty>
<TagsGroup>
{options.map((option) => (
<TagsItem
key={option.value}
value={option.value}
onSelect={() => onToggle(option.value)}
className="justify-start"
>
<Check
className={cn(
"size-4 opacity-0",
value.includes(option.value) && "opacity-100",
)}
/>
{option.label}
</TagsItem>
))}
</TagsGroup>
</TagsList>
</TagsContent>
</Tags>
<Button
type="submit"
className="w-full sm:h-10 sm:w-auto"
disabled={value.length === 0}
>
دعوت کاربران
</Button>
</div>
</form>
);
};
interface InviteUser3Props {
heading?: string;
description?: string;
companyLogo?: string;
className?: string;
nonInvitedConnections?: User[];
invitedUsers?: User[];
}
const InviteUser3 = ({
heading = "افراد را به فضای کار خود دعوت کنید",
description =
"برای آن‌ها ایمیل دعوت ارسال می‌کنیم تا به فضای کار شما بپیوندند.",
companyLogo = "/block-media/shadcnblocks/block/logos/ShadcnBlocks-logo-word.png",
className,
nonInvitedConnections = [
{
id: 3,
name: "آلیس اسمیت",
email: "alice.smith@example.com",
},
{
id: 5,
name: "چارلی براون",
email: "charlie.brown@example.com",
},
{
id: 13,
name: "کوین هارت",
email: "kevin.hart@example.com",
},
{
id: 15,
name: "مایکل اسکات",
email: "michael.scott@example.com",
},
{
id: 17,
name: "اسکار ویلد",
email: "oscar.wilde@example.com",
},
],
invitedUsers = [
{
id: 1,
name: "جین دو",
email: "jane.doe@example.com",
status: "Pending",
},
{
id: 2,
name: "جان دو",
email: "john.doe@example.com",
status: "Accepted",
},
{
id: 6,
name: "دایانا روس",
email: "diana.ross@example.com",
status: "Accepted",
},
],
}: InviteUser3Props) => {
const [value, setValue] = useState<string[]>([]);
const options = nonInvitedConnections.map((user) => ({
value: user.email,
label: user.name,
}));
const handleToggle = (selectedValue: string) => {
setValue((prev) =>
prev.includes(selectedValue)
? prev.filter((v) => v !== selectedValue)
: [...prev, selectedValue],
);
};
return (
<section className="py-32">
<div className="container">
<div className={cn("mx-auto max-w-3xl space-y-12", className)}>
<img
src={companyLogo}
alt="لوگوی شرکت"
className="w-56 sm:w-68 dark:invert"
/>
<div className="text-start">
<p className="text-xl font-medium sm:text-xl">{heading}</p>
<p className="text-sm text-muted-foreground sm:text-base">
{description}
</p>
</div>
<div className="space-y-8">
<InviteUserForm
value={value}
options={options}
onToggle={handleToggle}
/>
<UsersTable users={invitedUsers} />
</div>
</div>
</div>
</section>
);
};
export { InviteUser3 };