new src change
This commit is contained in:
@@ -7,7 +7,7 @@ import { Mail, Lock, Eye, EyeOff, Search, Users, Calendar, TrendingUp, Clock, Us
|
||||
import { useState } from "react";
|
||||
import { motion, AnimatePresence } from "motion/react";
|
||||
import FlightBookingRafiki from "./imports/FlightBookingRafiki";
|
||||
import cityCardsLogo from './assets/city-card-logo.png';
|
||||
import cityCardsLogo from './assets/cityLogo.png';
|
||||
import { ImageWithFallback } from "./components/figma/ImageWithFallback";
|
||||
import Sidebar from "./components/Sidebar";
|
||||
import Header from "./components/Header";
|
||||
@@ -19,6 +19,7 @@ import BookingManagementPage from "./components/BookingManagementPage";
|
||||
import RecurringBlockPage from "./components/RecurringBlockPage";
|
||||
import NotificationsPage from "./components/NotificationsPage";
|
||||
import ProfilePage from "./components/ProfilePage";
|
||||
import HowItWorksPage from "./components/HowItWorksPage";
|
||||
|
||||
export default function App() {
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
@@ -95,6 +96,7 @@ export default function App() {
|
||||
{activeNavItem === "support" && <SupportPage />}
|
||||
{activeNavItem === "notifications" && <NotificationsPage />}
|
||||
{activeNavItem === "profile" && <ProfilePage />}
|
||||
{activeNavItem === "how-it-works" && <HowItWorksPage onNavigate={setActiveNavItem} />}
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
@@ -5,6 +5,7 @@ import CalendarView from "./CalendarView";
|
||||
import BookingDetailView from "./BookingDetailView";
|
||||
import { Button } from "./ui/button";
|
||||
import { Input } from "./ui/input";
|
||||
import { Checkbox } from "./ui/checkbox";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
@@ -29,6 +30,7 @@ export default function BookingManagementPage({ activeView, onNavigateToRecurrin
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
const [selectedBooking, setSelectedBooking] = useState<any>(null);
|
||||
const [showDetailView, setShowDetailView] = useState(false);
|
||||
const [selectedBookings, setSelectedBookings] = useState<string[]>([]);
|
||||
|
||||
// Sample booking data
|
||||
const bookings = [
|
||||
@@ -152,6 +154,24 @@ export default function BookingManagementPage({ activeView, onNavigateToRecurrin
|
||||
setSelectedBooking(null);
|
||||
};
|
||||
|
||||
// Handle checkbox selection
|
||||
const handleSelectBooking = (bookingId: string) => {
|
||||
setSelectedBookings(prev =>
|
||||
prev.includes(bookingId)
|
||||
? prev.filter(id => id !== bookingId)
|
||||
: [...prev, bookingId]
|
||||
);
|
||||
};
|
||||
|
||||
// Handle select all
|
||||
const handleSelectAll = () => {
|
||||
if (selectedBookings.length === filteredBookings.length) {
|
||||
setSelectedBookings([]);
|
||||
} else {
|
||||
setSelectedBookings(filteredBookings.map(booking => booking.id));
|
||||
}
|
||||
};
|
||||
|
||||
// Show detail view if a booking is selected
|
||||
if (showDetailView && selectedBooking) {
|
||||
return <BookingDetailView bookingData={selectedBooking} onBack={handleBackFromDetail} />;
|
||||
@@ -225,6 +245,12 @@ export default function BookingManagementPage({ activeView, onNavigateToRecurrin
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow className="bg-gray-50">
|
||||
<TableHead className="text-center font-medium text-gray-900 w-12">
|
||||
<Checkbox
|
||||
checked={selectedBookings.length === filteredBookings.length && filteredBookings.length > 0}
|
||||
onCheckedChange={handleSelectAll}
|
||||
/>
|
||||
</TableHead>
|
||||
<TableHead className="text-center font-medium text-gray-900">Full Name</TableHead>
|
||||
<TableHead className="text-center font-medium text-gray-900">Email</TableHead>
|
||||
<TableHead className="text-center font-medium text-gray-900">Card Type</TableHead>
|
||||
@@ -237,6 +263,12 @@ export default function BookingManagementPage({ activeView, onNavigateToRecurrin
|
||||
<TableBody>
|
||||
{filteredBookings.map((booking, index) => (
|
||||
<TableRow key={booking.id} className="hover:bg-gray-50">
|
||||
<TableCell className="text-center">
|
||||
<Checkbox
|
||||
checked={selectedBookings.includes(booking.id)}
|
||||
onCheckedChange={() => handleSelectBooking(booking.id)}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className="text-center text-gray-900">{booking.fullName}</TableCell>
|
||||
<TableCell className="text-center text-gray-600">{booking.email}</TableCell>
|
||||
<TableCell className="text-center text-gray-900">{booking.cardType}</TableCell>
|
||||
|
||||
@@ -15,24 +15,31 @@ export default function Dashboard() {
|
||||
const [startDate, setStartDate] = useState<Date>();
|
||||
const [endDate, setEndDate] = useState<Date>();
|
||||
const [exportFormat, setExportFormat] = useState<'pdf' | 'excel' | null>(null);
|
||||
const [dateRangeFilter, setDateRangeFilter] = useState<'today' | 'lastWeek' | 'all' | 'custom'>('custom');
|
||||
const [dateRangeFilter, setDateRangeFilter] = useState<'last24Hours' | 'last7Days' | 'last30Days' | 'last3Months' | 'custom'>('custom');
|
||||
|
||||
const handleDateRangeFilterChange = (filter: 'today' | 'lastWeek' | 'all' | 'custom') => {
|
||||
const handleDateRangeFilterChange = (filter: 'last24Hours' | 'last7Days' | 'last30Days' | 'last3Months' | 'custom') => {
|
||||
setDateRangeFilter(filter);
|
||||
const today = new Date();
|
||||
|
||||
if (filter === 'today') {
|
||||
setStartDate(today);
|
||||
if (filter === 'last24Hours') {
|
||||
const yesterday = new Date();
|
||||
yesterday.setDate(today.getDate() - 1);
|
||||
setStartDate(yesterday);
|
||||
setEndDate(today);
|
||||
} else if (filter === 'lastWeek') {
|
||||
const lastWeek = new Date();
|
||||
lastWeek.setDate(today.getDate() - 7);
|
||||
setStartDate(lastWeek);
|
||||
} else if (filter === 'last7Days') {
|
||||
const last7Days = new Date();
|
||||
last7Days.setDate(today.getDate() - 7);
|
||||
setStartDate(last7Days);
|
||||
setEndDate(today);
|
||||
} else if (filter === 'all') {
|
||||
// Set a far past date for "all"
|
||||
const allStart = new Date(2020, 0, 1);
|
||||
setStartDate(allStart);
|
||||
} else if (filter === 'last30Days') {
|
||||
const last30Days = new Date();
|
||||
last30Days.setDate(today.getDate() - 30);
|
||||
setStartDate(last30Days);
|
||||
setEndDate(today);
|
||||
} else if (filter === 'last3Months') {
|
||||
const last3Months = new Date();
|
||||
last3Months.setMonth(today.getMonth() - 3);
|
||||
setStartDate(last3Months);
|
||||
setEndDate(today);
|
||||
} else if (filter === 'custom') {
|
||||
// Clear dates for custom selection
|
||||
@@ -110,16 +117,17 @@ export default function Dashboard() {
|
||||
<label className="text-base font-medium text-gray-900">Date Range</label>
|
||||
<Select
|
||||
value={dateRangeFilter}
|
||||
onValueChange={(value) => handleDateRangeFilterChange(value as 'today' | 'lastWeek' | 'all' | 'custom')}
|
||||
onValueChange={(value) => handleDateRangeFilterChange(value as 'last24Hours' | 'last7Days' | 'last30Days' | 'last3Months' | 'custom')}
|
||||
>
|
||||
<SelectTrigger className="w-48 bg-gray-50 border-gray-200 hover:bg-gray-100">
|
||||
<SelectValue placeholder="Select date range" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="today">Today</SelectItem>
|
||||
<SelectItem value="lastWeek">Last Week</SelectItem>
|
||||
<SelectItem value="all">All</SelectItem>
|
||||
<SelectItem value="custom">Custom</SelectItem>
|
||||
<SelectItem value="last24Hours">Last 24 Hours</SelectItem>
|
||||
<SelectItem value="last7Days">Last 7 Days</SelectItem>
|
||||
<SelectItem value="last30Days">Last 30 Days</SelectItem>
|
||||
<SelectItem value="last3Months">Last 3 Months</SelectItem>
|
||||
<SelectItem value="custom">Custom Date Range</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
89
src/components/HowItWorksPage.tsx
Normal file
89
src/components/HowItWorksPage.tsx
Normal file
@@ -0,0 +1,89 @@
|
||||
import { BookOpen } from "lucide-react";
|
||||
import { motion } from "motion/react";
|
||||
import { ImageWithFallback } from "./figma/ImageWithFallback";
|
||||
|
||||
interface HowItWorksPageProps {
|
||||
onNavigate: (page: string) => void;
|
||||
}
|
||||
|
||||
export default function HowItWorksPage({ onNavigate }: HowItWorksPageProps) {
|
||||
return (
|
||||
<div className="flex-1 overflow-auto bg-gray-50">
|
||||
<div className="max-w-7xl mx-auto p-8">
|
||||
{/* Header */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
className="mb-8"
|
||||
>
|
||||
<div className="flex items-center gap-3 mb-2">
|
||||
<div className="h-12 w-12 rounded-xl bg-gradient-to-br from-blue-500 to-purple-500 flex items-center justify-center">
|
||||
<BookOpen className="h-6 w-6 text-white" />
|
||||
</div>
|
||||
<h1 className="text-gray-900">How It Works</h1>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
{/* Main Content */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.4, delay: 0.1 }}
|
||||
className="bg-white rounded-xl border border-gray-200 shadow-sm overflow-hidden"
|
||||
>
|
||||
{/* Image */}
|
||||
<div className="w-full h-96 overflow-hidden bg-gray-100">
|
||||
<ImageWithFallback
|
||||
src="https://images.unsplash.com/photo-1758983308742-f4ba1f8c8cb4?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w3Nzg4Nzd8MHwxfHNlYXJjaHwxfHxoZWxwJTIwZ3VpZGUlMjB0dXRvcmlhbHxlbnwxfHx8fDE3NjA2MDkzNzZ8MA&ixlib=rb-4.1.0&q=80&w=1080&utm_source=figma&utm_medium=referral"
|
||||
alt="How It Works Guide"
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Text Content */}
|
||||
<div className="p-8">
|
||||
<h2 className="text-gray-900 mb-4">Welcome to CityCards Partner Web</h2>
|
||||
|
||||
<div className="space-y-4 text-gray-700">
|
||||
<p>
|
||||
CityCards Partner Web is your comprehensive dashboard for managing customer bookings,
|
||||
processing redemptions, and overseeing your team operations. This platform streamlines
|
||||
your daily tasks and provides powerful analytics to help grow your business.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong className="text-gray-900">Managing Bookings:</strong> View and manage customer bookings
|
||||
through an intuitive calendar or table view. Check-in customers, handle walk-ins, and set up
|
||||
recurring blocked time periods for holidays or maintenance.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong className="text-gray-900">Processing Redemptions:</strong> Quickly scan and verify
|
||||
CityCard passes for your customers. Process both single and multi-day passes, handle redemption
|
||||
confirmations, and access complete redemption history at your fingertips.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong className="text-gray-900">Staff Management:</strong> Add and remove team members,
|
||||
assign roles and permissions, track staff activity, and manage schedules efficiently.
|
||||
Keep your team organized and ensure smooth operations.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong className="text-gray-900">Reports & Analytics:</strong> Generate comprehensive reports
|
||||
in PDF or Excel format. View redemption analytics, track booking trends, and monitor staff
|
||||
performance to make data-driven decisions for your business.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong className="text-gray-900">Support:</strong> Need help? Our support team is always
|
||||
available to assist you with any questions or issues you may encounter while using the platform.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import { motion } from "motion/react";
|
||||
import { Input } from "./ui/input";
|
||||
import { Button } from "./ui/button";
|
||||
import { Badge } from "./ui/badge";
|
||||
import { Checkbox } from "./ui/checkbox";
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "./ui/table";
|
||||
import { useState } from "react";
|
||||
import CustomerDetailView from "./CustomerDetailView";
|
||||
@@ -12,6 +13,7 @@ export default function RedemptionsPage() {
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
const [selectedCustomer, setSelectedCustomer] = useState(null);
|
||||
const [showDetailView, setShowDetailView] = useState(false);
|
||||
const [selectedRedemptions, setSelectedRedemptions] = useState<string[]>([]);
|
||||
|
||||
// Mock data for redemption logs
|
||||
const redemptionData = [
|
||||
@@ -270,6 +272,24 @@ export default function RedemptionsPage() {
|
||||
setSelectedCustomer(null);
|
||||
};
|
||||
|
||||
// Handle checkbox selection
|
||||
const handleSelectRedemption = (bookingId: string) => {
|
||||
setSelectedRedemptions(prev =>
|
||||
prev.includes(bookingId)
|
||||
? prev.filter(id => id !== bookingId)
|
||||
: [...prev, bookingId]
|
||||
);
|
||||
};
|
||||
|
||||
// Handle select all
|
||||
const handleSelectAll = () => {
|
||||
if (selectedRedemptions.length === currentData.length) {
|
||||
setSelectedRedemptions([]);
|
||||
} else {
|
||||
setSelectedRedemptions(currentData.map(item => item.bookingId));
|
||||
}
|
||||
};
|
||||
|
||||
// If showing detail view, render the CustomerDetailView component
|
||||
if (showDetailView && selectedCustomer) {
|
||||
return (
|
||||
@@ -330,6 +350,12 @@ export default function RedemptionsPage() {
|
||||
<Table>
|
||||
<TableHeader className="sticky top-0 z-10">
|
||||
<TableRow className="border-b border-gray-200 bg-gray-50">
|
||||
<TableHead className="font-medium text-gray-900 py-4 text-center w-[50px]">
|
||||
<Checkbox
|
||||
checked={selectedRedemptions.length === currentData.length && currentData.length > 0}
|
||||
onCheckedChange={handleSelectAll}
|
||||
/>
|
||||
</TableHead>
|
||||
<TableHead className="font-medium text-gray-900 py-4 text-left w-[120px]">Booking ID</TableHead>
|
||||
<TableHead className="font-medium text-gray-900 text-left w-[100px]">Pass ID</TableHead>
|
||||
<TableHead className="font-medium text-gray-900 text-left w-[160px]">Customer Name</TableHead>
|
||||
@@ -348,6 +374,12 @@ export default function RedemptionsPage() {
|
||||
transition={{ delay: index * 0.05 }}
|
||||
className="border-b border-gray-100 hover:bg-gray-50"
|
||||
>
|
||||
<TableCell className="text-center w-[50px]">
|
||||
<Checkbox
|
||||
checked={selectedRedemptions.includes(item.bookingId)}
|
||||
onCheckedChange={() => handleSelectRedemption(item.bookingId)}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className="font-medium text-gray-900 py-4 text-left w-[120px]">{item.bookingId}</TableCell>
|
||||
<TableCell className="text-gray-600 text-left w-[100px]">{item.passId}</TableCell>
|
||||
<TableCell className="text-gray-900 text-left w-[160px]">{item.customerName}</TableCell>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { motion } from "motion/react";
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "./ui/avatar";
|
||||
import { useState } from "react";
|
||||
import { ImageWithFallback } from "./figma/ImageWithFallback";
|
||||
import cityCardsLogo from '../assets/city-card-logo.png';
|
||||
import cityCardsLogo from '../assets/cityLogo.png';
|
||||
|
||||
interface SidebarProps {
|
||||
activeItem: string;
|
||||
@@ -12,7 +12,6 @@ interface SidebarProps {
|
||||
}
|
||||
|
||||
export default function Sidebar({ activeItem, onItemSelect, isNotificationsOpen = false }: SidebarProps) {
|
||||
const [isProfileOpen, setIsProfileOpen] = useState(false);
|
||||
const [isBookingExpanded, setIsBookingExpanded] = useState(activeItem === 'booking-table' || activeItem === 'booking-calendar');
|
||||
|
||||
const navigationItems = [
|
||||
@@ -172,69 +171,34 @@ export default function Sidebar({ activeItem, onItemSelect, isNotificationsOpen
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
{/* Profile Section */}
|
||||
{/* How It Works Section */}
|
||||
<div className="p-4 border-t border-gray-100">
|
||||
<motion.button
|
||||
onClick={() => setIsProfileOpen(!isProfileOpen)}
|
||||
className="w-full flex items-center gap-3 p-3 rounded-lg hover:bg-gray-50 transition-colors"
|
||||
onClick={() => onItemSelect('how-it-works')}
|
||||
className={`w-full flex items-center gap-3 p-3 rounded-lg transition-colors ${
|
||||
activeItem === 'how-it-works'
|
||||
? 'bg-[#F95F62] text-white'
|
||||
: 'hover:bg-gray-50'
|
||||
}`}
|
||||
whileTap={{ scale: 0.98 }}
|
||||
whileHover={{ x: activeItem === 'how-it-works' ? 0 : 4 }}
|
||||
>
|
||||
<div className="h-10 w-10 rounded-lg bg-gradient-to-br from-blue-500 to-purple-500 flex items-center justify-center">
|
||||
<div className={`h-10 w-10 rounded-lg flex items-center justify-center ${
|
||||
activeItem === 'how-it-works'
|
||||
? 'bg-white/20'
|
||||
: 'bg-gradient-to-br from-blue-500 to-purple-500'
|
||||
}`}>
|
||||
<HelpCircle className="h-5 w-5 text-white" />
|
||||
</div>
|
||||
<div className="flex-1 text-left">
|
||||
<p className="font-medium text-gray-900">How it Works</p>
|
||||
<p className="text-sm text-gray-500">Help & Guides</p>
|
||||
<p className={`font-medium ${
|
||||
activeItem === 'how-it-works' ? 'text-white' : 'text-gray-900'
|
||||
}`}>How it Works</p>
|
||||
<p className={`text-sm ${
|
||||
activeItem === 'how-it-works' ? 'text-white/80' : 'text-gray-500'
|
||||
}`}>Help & Guides</p>
|
||||
</div>
|
||||
<motion.div
|
||||
animate={{ rotate: isProfileOpen ? 180 : 0 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
>
|
||||
<ChevronDown className="h-4 w-4 text-gray-400" />
|
||||
</motion.div>
|
||||
</motion.button>
|
||||
|
||||
{/* How it Works Dropdown */}
|
||||
<motion.div
|
||||
initial={{ height: 0, opacity: 0 }}
|
||||
animate={{
|
||||
height: isProfileOpen ? 'auto' : 0,
|
||||
opacity: isProfileOpen ? 1 : 0
|
||||
}}
|
||||
transition={{ duration: 0.2 }}
|
||||
className="overflow-hidden"
|
||||
>
|
||||
<div className="pt-2 space-y-1">
|
||||
<motion.button
|
||||
whileHover={{ x: 4 }}
|
||||
className="w-full flex items-center gap-3 px-3 py-2 text-left text-gray-700 hover:bg-gray-50 rounded-lg transition-colors"
|
||||
>
|
||||
<Calendar className="h-4 w-4 text-gray-500" />
|
||||
<span className="text-sm">Managing Bookings</span>
|
||||
</motion.button>
|
||||
<motion.button
|
||||
whileHover={{ x: 4 }}
|
||||
className="w-full flex items-center gap-3 px-3 py-2 text-left text-gray-700 hover:bg-gray-50 rounded-lg transition-colors"
|
||||
>
|
||||
<CreditCard className="h-4 w-4 text-gray-500" />
|
||||
<span className="text-sm">Redemption Process</span>
|
||||
</motion.button>
|
||||
<motion.button
|
||||
whileHover={{ x: 4 }}
|
||||
className="w-full flex items-center gap-3 px-3 py-2 text-left text-gray-700 hover:bg-gray-50 rounded-lg transition-colors"
|
||||
>
|
||||
<Users className="h-4 w-4 text-gray-500" />
|
||||
<span className="text-sm">Staff Management</span>
|
||||
</motion.button>
|
||||
<motion.button
|
||||
whileHover={{ x: 4 }}
|
||||
className="w-full flex items-center gap-3 px-3 py-2 text-left text-gray-700 hover:bg-gray-50 rounded-lg transition-colors"
|
||||
>
|
||||
<Table2 className="h-4 w-4 text-gray-500" />
|
||||
<span className="text-sm">Reports & Analytics</span>
|
||||
</motion.button>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Input } from "./ui/input";
|
||||
import { Button } from "./ui/button";
|
||||
import { Badge } from "./ui/badge";
|
||||
import { Switch } from "./ui/switch";
|
||||
import { Checkbox } from "./ui/checkbox";
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "./ui/table";
|
||||
import { Label } from "./ui/label";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select";
|
||||
@@ -15,6 +16,7 @@ export default function StaffManagementPage() {
|
||||
const [isEditPanelOpen, setIsEditPanelOpen] = useState(false);
|
||||
const [isAddPanelOpen, setIsAddPanelOpen] = useState(false);
|
||||
const [editingStaff, setEditingStaff] = useState(null);
|
||||
const [selectedStaff, setSelectedStaff] = useState<string[]>([]);
|
||||
const [editForm, setEditForm] = useState({
|
||||
fullName: "",
|
||||
phone: "",
|
||||
@@ -199,6 +201,24 @@ export default function StaffManagementPage() {
|
||||
);
|
||||
};
|
||||
|
||||
// Handle checkbox selection
|
||||
const handleSelectStaff = (idNo: string) => {
|
||||
setSelectedStaff(prev =>
|
||||
prev.includes(idNo)
|
||||
? prev.filter(id => id !== idNo)
|
||||
: [...prev, idNo]
|
||||
);
|
||||
};
|
||||
|
||||
// Handle select all
|
||||
const handleSelectAll = () => {
|
||||
if (selectedStaff.length === currentData.length) {
|
||||
setSelectedStaff([]);
|
||||
} else {
|
||||
setSelectedStaff(currentData.map(staff => staff.idNo));
|
||||
}
|
||||
};
|
||||
|
||||
const handleEditStaff = (idNo: string) => {
|
||||
const staffMember = staffData.find(staff => staff.idNo === idNo);
|
||||
if (staffMember) {
|
||||
@@ -526,6 +546,12 @@ export default function StaffManagementPage() {
|
||||
<Table>
|
||||
<TableHeader className="sticky top-0 z-10">
|
||||
<TableRow className="border-b border-gray-200 bg-gray-50">
|
||||
<TableHead className="font-medium text-gray-900 py-4 text-center w-[50px]">
|
||||
<Checkbox
|
||||
checked={selectedStaff.length === currentData.length && currentData.length > 0}
|
||||
onCheckedChange={handleSelectAll}
|
||||
/>
|
||||
</TableHead>
|
||||
<TableHead className="font-medium text-gray-900 py-4 text-center w-[100px]">ID No.</TableHead>
|
||||
<TableHead className="font-medium text-gray-900 text-center w-[160px]">Full Name</TableHead>
|
||||
<TableHead className="font-medium text-gray-900 text-center w-[140px]">Phone</TableHead>
|
||||
@@ -544,6 +570,12 @@ export default function StaffManagementPage() {
|
||||
transition={{ delay: index * 0.05 }}
|
||||
className="border-b border-gray-100 hover:bg-gray-50"
|
||||
>
|
||||
<TableCell className="text-center w-[50px]">
|
||||
<Checkbox
|
||||
checked={selectedStaff.includes(item.idNo)}
|
||||
onCheckedChange={() => handleSelectStaff(item.idNo)}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className="font-medium text-gray-900 py-4 text-center w-[100px]">{item.idNo}</TableCell>
|
||||
<TableCell className="text-gray-900 text-center w-[160px]">{item.fullName}</TableCell>
|
||||
<TableCell className="text-gray-600 text-center w-[140px]">{item.phone}</TableCell>
|
||||
|
||||
@@ -913,6 +913,10 @@
|
||||
height: calc(var(--spacing) * 64);
|
||||
}
|
||||
|
||||
.h-96 {
|
||||
height: calc(var(--spacing) * 96);
|
||||
}
|
||||
|
||||
.h-\[1\.15rem\] {
|
||||
height: 1.15rem;
|
||||
}
|
||||
@@ -1033,6 +1037,10 @@
|
||||
width: calc(var(--spacing) * 96);
|
||||
}
|
||||
|
||||
.w-\[50px\] {
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.w-\[65px\] {
|
||||
width: 65px;
|
||||
}
|
||||
@@ -1129,6 +1137,10 @@
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.grow {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.caption-bottom {
|
||||
caption-side: bottom;
|
||||
}
|
||||
@@ -1364,6 +1376,10 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.overflow-auto {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.overflow-clip {
|
||||
overflow: clip;
|
||||
}
|
||||
@@ -1712,6 +1728,16 @@
|
||||
background-color: var(--color-white);
|
||||
}
|
||||
|
||||
.bg-white\/20 {
|
||||
background-color: #fff3;
|
||||
}
|
||||
|
||||
@supports (color: color-mix(in lab, red, red)) {
|
||||
.bg-white\/20 {
|
||||
background-color: color-mix(in oklab, var(--color-white) 20%, transparent);
|
||||
}
|
||||
}
|
||||
|
||||
.bg-gradient-to-br {
|
||||
--tw-gradient-position: to bottom right in oklab;
|
||||
background-image: linear-gradient(var(--tw-gradient-stops));
|
||||
@@ -1735,6 +1761,10 @@
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.object-cover {
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.p-0 {
|
||||
padding: calc(var(--spacing) * 0);
|
||||
}
|
||||
@@ -1767,6 +1797,10 @@
|
||||
padding: calc(var(--spacing) * 6);
|
||||
}
|
||||
|
||||
.p-8 {
|
||||
padding: calc(var(--spacing) * 8);
|
||||
}
|
||||
|
||||
.p-12 {
|
||||
padding: calc(var(--spacing) * 12);
|
||||
}
|
||||
@@ -1827,10 +1861,6 @@
|
||||
padding-top: calc(var(--spacing) * 1);
|
||||
}
|
||||
|
||||
.pt-2 {
|
||||
padding-top: calc(var(--spacing) * 2);
|
||||
}
|
||||
|
||||
.pt-4 {
|
||||
padding-top: calc(var(--spacing) * 4);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user