Add guests list table MOCK component with search and actions

Introduce a dynamic guests list table featuring search, filters, and status badges. Includes functionality to add new guests, perform actions like editing or deleting, and view summarized data for confirmations and additional guests. just the mock
This commit is contained in:
2025-03-15 21:03:13 +01:00
parent 3800fcea19
commit 22e11e9bfe

View File

@@ -0,0 +1,245 @@
import React, { useState } from "react";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { MoreHorizontal, Plus, Search, Filter, Send, Copy } from "lucide-react";
const GuestListTable = () => {
const [open, setOpen] = useState(false);
const [searchQuery, setSearchQuery] = useState("");
// Mock data
const guests = [
{
id: "1",
fullName: "John Smith",
email: "john.smith@example.com",
phone: "+1 555-123-4567",
invitationCode: "JSMITH21",
status: "CONFIRMED",
additionalGuests: 2,
},
{
id: "2",
fullName: "Emma Johnson",
email: "emma.j@example.com",
phone: "+1 555-987-6543",
invitationCode: "EJOHN45",
status: "INVITED",
additionalGuests: 0,
},
{
id: "3",
fullName: "Michael Brown",
email: "mbrown@example.com",
phone: "+1 555-555-5555",
invitationCode: "MBROWN3",
status: "DECLINED",
additionalGuests: 0,
},
{
id: "4",
fullName: "Olivia Davis",
email: "olivia.d@example.com",
phone: "+1 555-111-2222",
invitationCode: "ODAVIS7",
status: "PENDING",
additionalGuests: 1,
},
{
id: "5",
fullName: "William Wilson",
email: "will.w@example.com",
phone: "+1 555-333-4444",
invitationCode: "WWILSON",
status: "CONFIRMED",
additionalGuests: 3,
},
];
const getStatusBadge = (status) => {
const statusStyles = {
INVITED: "bg-blue-100 text-blue-800",
PENDING: "bg-yellow-100 text-yellow-800",
CONFIRMED: "bg-green-100 text-green-800",
DECLINED: "bg-red-100 text-red-800",
WAITLISTED: "bg-purple-100 text-purple-800",
CANCELLED: "bg-gray-100 text-gray-800",
};
return <Badge className={statusStyles[status]}>{status}</Badge>;
};
const filteredGuests = guests.filter(
(guest) =>
guest.fullName.toLowerCase().includes(searchQuery.toLowerCase()) ||
guest.email.toLowerCase().includes(searchQuery.toLowerCase()) ||
guest.invitationCode.toLowerCase().includes(searchQuery.toLowerCase()),
);
return (
<div className="space-y-4 w-full">
<div className="flex items-center justify-between">
<h2 className="text-2xl font-bold">Guest List</h2>
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button className="bg-blue-600 hover:bg-blue-700">
<Plus className="mr-2 h-4 w-4" /> Add Guest
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Add New Guest</DialogTitle>
</DialogHeader>
<div className="grid gap-4 py-4">
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="name" className="text-right">
Full Name
</Label>
<Input id="name" className="col-span-3" />
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="email" className="text-right">
Email
</Label>
<Input id="email" type="email" className="col-span-3" />
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="phone" className="text-right">
Phone
</Label>
<Input id="phone" className="col-span-3" />
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="additionalGuests" className="text-right">
Additional Guests
</Label>
<Input
id="additionalGuests"
type="number"
min="0"
className="col-span-3"
/>
</div>
</div>
<div className="flex justify-end gap-2">
<Button variant="outline" onClick={() => setOpen(false)}>
Cancel
</Button>
<Button className="bg-blue-600 hover:bg-blue-700">
Add Guest
</Button>
</div>
</DialogContent>
</Dialog>
</div>
<div className="flex justify-between items-center">
<div className="relative w-64">
<Search className="absolute left-2 top-2.5 h-4 w-4 text-gray-500" />
<Input
placeholder="Search guests..."
className="pl-8"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
/>
</div>
<div className="flex gap-2">
<Button variant="outline" size="sm">
<Filter className="mr-2 h-4 w-4" /> Filter
</Button>
<Button variant="outline" size="sm">
<Send className="mr-2 h-4 w-4" /> Send Invites
</Button>
</div>
</div>
<div className="rounded-md border">
<Table>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Email</TableHead>
<TableHead>Phone</TableHead>
<TableHead>Invitation Code</TableHead>
<TableHead>Status</TableHead>
<TableHead>Additional Guests</TableHead>
<TableHead className="text-right">Actions</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{filteredGuests.map((guest) => (
<TableRow key={guest.id}>
<TableCell className="font-medium">{guest.fullName}</TableCell>
<TableCell>{guest.email}</TableCell>
<TableCell>{guest.phone}</TableCell>
<TableCell>
<div className="flex items-center gap-1">
{guest.invitationCode}
<Button variant="ghost" size="icon" className="h-6 w-6">
<Copy className="h-3 w-3" />
</Button>
</div>
</TableCell>
<TableCell>{getStatusBadge(guest.status)}</TableCell>
<TableCell>{guest.additionalGuests}</TableCell>
<TableCell className="text-right">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" className="h-8 w-8">
<MoreHorizontal className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem>Edit</DropdownMenuItem>
<DropdownMenuItem>Resend Invitation</DropdownMenuItem>
<DropdownMenuItem className="text-red-600">
Delete
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
<div className="flex justify-between text-sm text-gray-500">
<div>
Showing {filteredGuests.length} of {guests.length} guests
</div>
<div>
Total Confirmed:{" "}
{guests.filter((g) => g.status === "CONFIRMED").length} | Total
Additional Guests:{" "}
{guests.reduce((acc, g) => acc + g.additionalGuests, 0)}
</div>
</div>
</div>
);
};
export default GuestListTable;