feat: Implement manual assignment for administrators
This commit is contained in:
@@ -1,17 +1,18 @@
|
||||
import React, { useMemo } from "react";
|
||||
import { useMemo, useState } from "react";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { format } from "date-fns";
|
||||
import { useSelector } from "react-redux";
|
||||
import { Calendar, MapPin, Users, DollarSign, Edit3, X, Copy, Clock } from "lucide-react";
|
||||
import { Calendar, MapPin, Users, DollarSign, Edit3, X, Copy, Clock, FileText, UserPlus } from "lucide-react";
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/common/components/ui/card";
|
||||
import { Button } from "@/common/components/ui/button";
|
||||
import { Badge } from "@/common/components/ui/badge";
|
||||
import DashboardLayout from "@/features/layouts/DashboardLayout";
|
||||
import { useGetOrderById, useUpdateOrder } from "@/dataconnect-generated/react";
|
||||
import { useGetOrderById, useUpdateOrder, useListShiftRolesByBusinessAndOrder } from "@/dataconnect-generated/react";
|
||||
import { OrderStatus } from "@/dataconnect-generated";
|
||||
import { dataConnect } from "@/features/auth/firebase";
|
||||
import { useToast } from "@/common/components/ui/use-toast";
|
||||
import AssignStaffModal from "./components/AssignStaffModal";
|
||||
import type { RootState } from "@/store/store";
|
||||
|
||||
const safeFormatDate = (value?: string | null): string => {
|
||||
@@ -85,6 +86,8 @@ export default function OrderDetail() {
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const { toast } = useToast();
|
||||
const { user } = useSelector((state: RootState) => state.auth);
|
||||
const [selectedShift, setSelectedShift] = useState<any>(null);
|
||||
const [isAssignModalOpen, setIsAssignModalOpen] = useState(false);
|
||||
|
||||
const {
|
||||
data,
|
||||
@@ -99,6 +102,22 @@ export default function OrderDetail() {
|
||||
|
||||
const order = data?.order;
|
||||
|
||||
// Fetch real shift roles to get IDs and accurate counts
|
||||
const {
|
||||
data: shiftRolesData,
|
||||
isLoading: isLoadingShifts,
|
||||
refetch: refetchShifts
|
||||
} = useListShiftRolesByBusinessAndOrder(
|
||||
dataConnect,
|
||||
{
|
||||
orderId: id || "",
|
||||
businessId: order?.businessId || ""
|
||||
},
|
||||
{
|
||||
enabled: !!id && !!order?.businessId,
|
||||
}
|
||||
);
|
||||
|
||||
const cancelMutation = useUpdateOrder(dataConnect, {
|
||||
onSuccess: () => {
|
||||
toast({
|
||||
@@ -140,7 +159,12 @@ export default function OrderDetail() {
|
||||
navigate(`/orders/create?duplicate=${id}`);
|
||||
};
|
||||
|
||||
const shifts: any[] = Array.isArray(order?.shifts) ? (order!.shifts as any[]) : [];
|
||||
const shifts: any[] = useMemo(() => {
|
||||
if (shiftRolesData?.shiftRoles && shiftRolesData.shiftRoles.length > 0) {
|
||||
return shiftRolesData.shiftRoles;
|
||||
}
|
||||
return Array.isArray(order?.shifts) ? (order!.shifts as any[]) : [];
|
||||
}, [shiftRolesData, order?.shifts]);
|
||||
|
||||
const totalRequested = order?.requested ?? 0;
|
||||
const totalAssigned = Array.isArray(order?.assignedStaff) ? order!.assignedStaff.length : 0;
|
||||
@@ -238,7 +262,7 @@ export default function OrderDetail() {
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-6">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-12 h-12 bg-primary/10 rounded-xl flex items-center justify-center border border-primary/20">
|
||||
<FileTextIcon />
|
||||
<FileText className="w-6 h-6 text-primary" />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-secondary-text font-medium uppercase tracking-wider">
|
||||
@@ -352,6 +376,21 @@ export default function OrderDetail() {
|
||||
</span>
|
||||
<span className="font-semibold">{vacancies}</span>
|
||||
</div>
|
||||
|
||||
{!isClient && canModify && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="ml-2 text-primary hover:text-primary hover:bg-primary/10 rounded-lg h-8 px-2"
|
||||
onClick={() => {
|
||||
setSelectedShift(shift);
|
||||
setIsAssignModalOpen(true);
|
||||
}}
|
||||
>
|
||||
<UserPlus className="w-4 h-4 mr-1.5" />
|
||||
Assign
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -431,20 +470,20 @@ export default function OrderDetail() {
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{selectedShift && (
|
||||
<AssignStaffModal
|
||||
isOpen={isAssignModalOpen}
|
||||
onClose={() => {
|
||||
setIsAssignModalOpen(false);
|
||||
setSelectedShift(null);
|
||||
}}
|
||||
shift={selectedShift}
|
||||
onSuccess={() => {
|
||||
refetchShifts();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</DashboardLayout>
|
||||
);
|
||||
}
|
||||
|
||||
const FileTextIcon: React.FC = () => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
className="w-6 h-6 text-primary"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M7 2a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8.414a2 2 0 0 0-.586-1.414l-4.414-4.414A2 2 0 0 0 13.586 2H7zm6 2.414L17.586 9H15a2 2 0 0 1-2-2V4.414zM9 11h6v2H9v-2zm0 4h4v2H9v-2z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user