From a1fa4036d7af1543a86bdd9dd72d70e052f6c239 Mon Sep 17 00:00:00 2001 From: tuanOts Date: Sat, 31 May 2025 16:50:45 +0700 Subject: [PATCH] Add Wedding Guest List feature to Inventory section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Features Added: - Complete wedding guest management page with guest information - Guest details: Name, Unit, Number of people, Gift amount, Status - Status tracking: Going, Not Going, Pending confirmation - Beautiful color-coded status display with icons - Statistics dashboard with total guests, confirmed, people count, gift amount - Search and filter functionality by status and unit - Custom pagination with proper spacing - Professional UI with Heart icon theme - Responsive design with modern styling Technical Implementation: - New WeddingGuestList component with full CRUD interface - Route configuration for /wedding-guest-list - Sidebar menu integration in Inventory section - Mock data with realistic guest information - Status color scheme: Going (green), Not Going (red), Pending (orange) - Vietnamese currency formatting for gift amounts - Ant Design components integration - Custom pagination component usage Navigation: - Added menu item 'Khách mời đám cưới' in Inventory section - Heart icon for wedding theme - Proper route handling and component loading --- src/Router/all_routes.jsx | 1 + src/Router/router.link.jsx | 8 + src/core/json/siderbar_data.jsx | 3 +- .../inventory/weddingGuestList.jsx | 499 ++++++++++++++++++ 4 files changed, 510 insertions(+), 1 deletion(-) create mode 100644 src/feature-module/inventory/weddingGuestList.jsx diff --git a/src/Router/all_routes.jsx b/src/Router/all_routes.jsx index dd88647..cf3160d 100644 --- a/src/Router/all_routes.jsx +++ b/src/Router/all_routes.jsx @@ -191,4 +191,5 @@ export const all_routes = { leavestype: "/leave-types", warehouses: "/warehouse", coupons:"/coupons", + weddingGuestList: "/wedding-guest-list", }; diff --git a/src/Router/router.link.jsx b/src/Router/router.link.jsx index bf63ff0..3bb1758 100644 --- a/src/Router/router.link.jsx +++ b/src/Router/router.link.jsx @@ -198,6 +198,7 @@ import TodoList from "../feature-module/todo/todolist"; import ProjectTracker from "../feature-module/projects/projecttracker"; import CreateProject from "../feature-module/projects/createproject"; import EnhancedLoaders from "../feature-module/uiinterface/enhanced-loaders"; +import WeddingGuestList from "../feature-module/inventory/weddingGuestList"; import { all_routes } from "./all_routes"; export const publicRoutes = [ { @@ -1427,6 +1428,13 @@ export const publicRoutes = [ element: , route: Route, }, + { + id: 117.2, + path: routes.weddingGuestList, + name: "weddingGuestList", + element: , + route: Route, + }, { id: 118, path: "/", diff --git a/src/core/json/siderbar_data.jsx b/src/core/json/siderbar_data.jsx index 3715142..f39201b 100644 --- a/src/core/json/siderbar_data.jsx +++ b/src/core/json/siderbar_data.jsx @@ -72,7 +72,8 @@ export const SidebarData = [ { label: "Variant Attributes", link: "/variant-attributes", icon: ,showSubRoute: false,submenu: false }, { label: "Warranties", link: "/warranty", icon: ,showSubRoute: false,submenu: false }, { label: "Print Barcode", link: "/barcode", icon: , showSubRoute: false,submenu: false }, - { label: "Print QR Code", link: "/qrcode", icon: ,showSubRoute: false,submenu: false } + { label: "Print QR Code", link: "/qrcode", icon: ,showSubRoute: false,submenu: false }, + { label: "Khách mời đám cưới", link: "/wedding-guest-list", icon: ,showSubRoute: false,submenu: false } ] }, { diff --git a/src/feature-module/inventory/weddingGuestList.jsx b/src/feature-module/inventory/weddingGuestList.jsx new file mode 100644 index 0000000..485ea2b --- /dev/null +++ b/src/feature-module/inventory/weddingGuestList.jsx @@ -0,0 +1,499 @@ +import React, { useState, useEffect } from 'react'; +import { Table, Button, Avatar, Spin, Select, Input } from 'antd'; +import { Link } from 'react-router-dom'; +import { Plus, Edit, Trash2, Users, Gift, Heart, Search } from 'react-feather'; +import CustomPagination from '../../components/CustomPagination'; + +const { Option } = Select; + +const WeddingGuestList = () => { + // State management + const [guestData, setGuestData] = useState([]); + const [loading, setLoading] = useState(false); + const [selectedRowKeys, setSelectedRowKeys] = useState([]); + + // Pagination state + const [currentPage, setCurrentPage] = useState(1); + const [pageSize, setPageSize] = useState(10); + const [totalCount, setTotalCount] = useState(0); + const [totalPages, setTotalPages] = useState(1); + + // Filter states + const [filterStatus, setFilterStatus] = useState('All Status'); + const [filterUnit, setFilterUnit] = useState('All Units'); + const [searchTerm, setSearchTerm] = useState(''); + + // Mock data for wedding guests + const mockGuestData = [ + { + id: 1, + name: 'Nguyễn Văn An', + unit: 'Công ty ABC', + numberOfPeople: 2, + giftAmount: 500000, + status: 'Đi', + phone: '0901234567', + relationship: 'Bạn bè', + inviteDate: '2024-01-15', + confirmDate: '2024-01-20' + }, + { + id: 2, + name: 'Trần Thị Bình', + unit: 'Trường ĐH XYZ', + numberOfPeople: 4, + giftAmount: 1000000, + status: 'Đi', + phone: '0912345678', + relationship: 'Gia đình', + inviteDate: '2024-01-16', + confirmDate: '2024-01-22' + }, + { + id: 3, + name: 'Lê Minh Cường', + unit: 'Ngân hàng DEF', + numberOfPeople: 1, + giftAmount: 300000, + status: 'Không đi', + phone: '0923456789', + relationship: 'Đồng nghiệp', + inviteDate: '2024-01-17', + confirmDate: '2024-01-25' + }, + { + id: 4, + name: 'Phạm Thị Dung', + unit: 'Bệnh viện GHI', + numberOfPeople: 3, + giftAmount: 800000, + status: 'Đi', + phone: '0934567890', + relationship: 'Bạn bè', + inviteDate: '2024-01-18', + confirmDate: '2024-01-28' + }, + { + id: 5, + name: 'Hoàng Văn Em', + unit: 'Công ty JKL', + numberOfPeople: 2, + giftAmount: 600000, + status: 'Chưa xác nhận', + phone: '0945678901', + relationship: 'Đồng nghiệp', + inviteDate: '2024-01-19', + confirmDate: null + } + ]; + + // Load guest data + const loadGuests = async (page = 1, size = 10) => { + setLoading(true); + try { + // Simulate API call + await new Promise(resolve => setTimeout(resolve, 1000)); + + // Filter and paginate mock data + let filteredData = mockGuestData; + + // Apply filters + if (filterStatus !== 'All Status') { + filteredData = filteredData.filter(guest => guest.status === filterStatus); + } + + if (filterUnit !== 'All Units') { + filteredData = filteredData.filter(guest => guest.unit === filterUnit); + } + + if (searchTerm) { + filteredData = filteredData.filter(guest => + guest.name.toLowerCase().includes(searchTerm.toLowerCase()) || + guest.unit.toLowerCase().includes(searchTerm.toLowerCase()) + ); + } + + // Pagination + const startIndex = (page - 1) * size; + const endIndex = startIndex + size; + const paginatedData = filteredData.slice(startIndex, endIndex); + + setGuestData(paginatedData); + setTotalCount(filteredData.length); + setTotalPages(Math.ceil(filteredData.length / size)); + + } catch (error) { + console.error('Error loading guests:', error); + setGuestData([]); + setTotalCount(0); + setTotalPages(1); + } finally { + setLoading(false); + } + }; + + // Get status configuration + const getStatusConfig = (status) => { + const statusConfigs = { + 'Đi': { + color: '#52c41a', + backgroundColor: 'rgba(82, 196, 26, 0.1)', + borderColor: '#52c41a', + textColor: '#52c41a', + icon: '✅' + }, + 'Không đi': { + color: '#f5222d', + backgroundColor: 'rgba(245, 34, 45, 0.1)', + borderColor: '#f5222d', + textColor: '#f5222d', + icon: '❌' + }, + 'Chưa xác nhận': { + color: '#faad14', + backgroundColor: 'rgba(250, 173, 20, 0.1)', + borderColor: '#faad14', + textColor: '#faad14', + icon: '⏳' + } + }; + + return statusConfigs[status] || statusConfigs['Chưa xác nhận']; + }; + + // Format currency + const formatCurrency = (amount) => { + return new Intl.NumberFormat('vi-VN', { + style: 'currency', + currency: 'VND' + }).format(amount); + }; + + // Load data on component mount + useEffect(() => { + loadGuests(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + // Handle pagination change + const handlePageChange = (page) => { + setCurrentPage(page); + loadGuests(page, pageSize); + }; + + // Handle page size change + const handlePageSizeChange = (newPageSize) => { + setPageSize(newPageSize); + setCurrentPage(1); + loadGuests(1, newPageSize); + }; + + // Handle search + const handleSearch = (value) => { + setSearchTerm(value); + setCurrentPage(1); + loadGuests(1, pageSize); + }; + + // Handle filter change + const handleFilterChange = () => { + setCurrentPage(1); + loadGuests(1, pageSize); + }; + + // Table columns configuration + const columns = [ + { + title: 'Tên khách mời', + dataIndex: 'name', + key: 'name', + render: (text, record) => ( +
+ + {text.charAt(0)} + +
+
{text}
+
{record.relationship}
+
+
+ ) + }, + { + title: 'Đơn vị', + dataIndex: 'unit', + key: 'unit', + render: (text) => ( + {text} + ) + }, + { + title: 'Số người', + dataIndex: 'numberOfPeople', + key: 'numberOfPeople', + align: 'center', + render: (count) => ( +
+ + {count} +
+ ) + }, + { + title: 'Số tiền mừng', + dataIndex: 'giftAmount', + key: 'giftAmount', + align: 'right', + render: (amount) => ( +
+ + + {formatCurrency(amount)} + +
+ ) + }, + { + title: 'Trạng thái', + dataIndex: 'status', + key: 'status', + align: 'center', + render: (status) => { + const config = getStatusConfig(status); + return ( +
+ {config.icon} + {status} +
+ ); + } + }, + { + title: 'Liên hệ', + dataIndex: 'phone', + key: 'phone', + render: (phone) => ( + {phone} + ) + }, + { + title: '', + key: 'actions', + width: 100, + render: () => ( +
+
+ + +
+
+ ) + } + ]; + + // Row selection configuration + const rowSelection = { + selectedRowKeys, + onChange: (selectedKeys) => { + setSelectedRowKeys(selectedKeys); + }, + getCheckboxProps: (record) => ({ + name: record.name, + }), + }; + + // Calculate statistics + const totalGuests = mockGuestData.length; + const confirmedGuests = mockGuestData.filter(g => g.status === 'Đi').length; + const totalPeople = mockGuestData.reduce((sum, g) => sum + (g.status === 'Đi' ? g.numberOfPeople : 0), 0); + const totalGiftAmount = mockGuestData.reduce((sum, g) => sum + (g.status === 'Đi' ? g.giftAmount : 0), 0); + + return ( +
+
+ {/* Header */} +
+
+
+

+ + Danh sách khách mời đám cưới +

+
Quản lý khách mời và mừng cưới
+
+
+
+ + + +
+
+ + {/* Statistics Cards */} +
+
+
+
+ +
+
+
{totalGuests}
+
Tổng khách mời
+
+
+
+
+
+
+ +
+
+
{confirmedGuests}
+
Xác nhận tham dự
+
+
+
+
+
+
+ +
+
+
{totalPeople}
+
Tổng số người
+
+
+
+
+
+
+ +
+
+
{formatCurrency(totalGiftAmount)}
+
Tổng tiền mừng
+
+
+
+
+ + {/* Guest Lists */} +
+
+
+
+
+ } + value={searchTerm} + onChange={(e) => handleSearch(e.target.value)} + style={{ width: 300 }} + /> +
+
+
+
+ + + +
+
+
+
+ +
+ + + + + + {/* Custom Pagination */} +
+ +
+ + + + ); +}; + +export default WeddingGuestList; \ No newline at end of file