diff --git a/apps/web/src/features/business/clients/AddClient.tsx b/apps/web/src/features/business/clients/AddClient.tsx index 9313b9f6..57144007 100644 --- a/apps/web/src/features/business/clients/AddClient.tsx +++ b/apps/web/src/features/business/clients/AddClient.tsx @@ -56,7 +56,7 @@ export default function AddClient() { const { mutateAsync: createBusiness, isPending: isCreatingBusiness } = useCreateBusiness(dataConnect); const { mutateAsync: createHub, isPending: isCreatingHub } = useCreateTeamHub(dataConnect); - const { mutateAsync: createTeam, isPending: isCreatingTeam } = useCreateTeam(dataConnect); + const { mutateAsync: createTeam } = useCreateTeam(dataConnect); const handleChange = (field: string, value: any) => { setFormData(prev => ({ ...prev, [field]: value })); diff --git a/apps/web/src/features/business/rates/ServiceRates.tsx b/apps/web/src/features/business/rates/ServiceRates.tsx index 3cbc12df..21f597e9 100644 --- a/apps/web/src/features/business/rates/ServiceRates.tsx +++ b/apps/web/src/features/business/rates/ServiceRates.tsx @@ -28,9 +28,7 @@ import { useCreateCustomRateCard, useUpdateCustomRateCard, useDeleteCustomRateCard, - useCreateVendorRate, useUpdateVendorRate, - useDeleteVendorRate, useGetVendorByUserId } from "@/dataconnect-generated/react"; import RateCardModal from "./components/RateCardModal"; @@ -111,9 +109,7 @@ function VendorCompanyPricebookView({ const { mutate: updateCustomRateCard } = useUpdateCustomRateCard(); const { mutate: deleteCustomRateCard } = useDeleteCustomRateCard(); - const { mutate: createVendorRate } = useCreateVendorRate(); const { mutate: updateVendorRate } = useUpdateVendorRate(); - const { mutate: deleteVendorRate } = useDeleteVendorRate(); const handleUpdateVendorRate = (vars: any) => { updateVendorRate(vars, { @@ -146,8 +142,13 @@ function VendorCompanyPricebookView({ }, [vendorRates, vendorName]); const CATEGORIES = useMemo(() => { - const cats = new Set(vendorRates.map(r => r.category).filter(Boolean)); - return Array.from(cats); + const categories = vendorRates.reduce((acc, r) => { + if (r.category) { + acc.push(String(r.category)); + } + return acc; + }, []); + return Array.from(new Set(categories)); }, [vendorRates]); const handleSaveRateCard = (cardData: any) => { @@ -233,7 +234,6 @@ function VendorCompanyPricebookView({ return rates.map((r: any) => { const parsed = parseRoleName(r.roleName || ""); - const position = parsed.position; // Apply discount if it's a custom rate card const proposedRate = r.clientRate * (1 - discount / 100); @@ -470,6 +470,9 @@ function VendorCompanyPricebookView({
{RATE_CARDS.map((tab) => { const cardData = customRateCards.find((c) => c.name === tab); + if (!cardData) { + return null; + } const isRenaming = renamingCard === tab; if (isRenaming) { diff --git a/apps/web/src/features/finance/invoices/InvoiceDetail.tsx b/apps/web/src/features/finance/invoices/InvoiceDetail.tsx index 6c8c5313..b4a19a40 100644 --- a/apps/web/src/features/finance/invoices/InvoiceDetail.tsx +++ b/apps/web/src/features/finance/invoices/InvoiceDetail.tsx @@ -6,10 +6,8 @@ import { InvoiceStatus } from "@/dataconnect-generated"; import { useGetInvoiceById, useUpdateInvoice, useListRecentPaymentsByInvoiceId } from "@/dataconnect-generated/react"; import { dataConnect } from "@/features/auth/firebase"; import DashboardLayout from "@/features/layouts/DashboardLayout"; -import type { RootState } from "@/store/store"; import { format, parseISO } from "date-fns"; import { ArrowLeft, Download, Mail, CheckCircle, FileText, User, Calendar, MapPin, DollarSign } from "lucide-react"; -import { useSelector } from "react-redux"; import { useNavigate, useParams } from "react-router-dom"; const statusConfig: Record = { @@ -25,14 +23,13 @@ const statusConfig: Record = { export default function InvoiceDetail() { const navigate = useNavigate(); const { id: invoiceId } = useParams<{ id: string }>(); - const { user } = useSelector((state: RootState) => state.auth); // Fetch Invoice Data const { data: invoiceData, isLoading: loadingInvoice } = useGetInvoiceById(dataConnect, { id: invoiceId! }); const invoice = invoiceData?.invoice; // Fetch Payment History - const { data: paymentsData, isLoading: loadingPayments } = useListRecentPaymentsByInvoiceId(dataConnect, { invoiceId: invoiceId! }); + const { data: paymentsData } = useListRecentPaymentsByInvoiceId(dataConnect, { invoiceId: invoiceId! }); const payments = paymentsData?.recentPayments || []; // Mutations diff --git a/apps/web/src/features/finance/invoices/InvoiceEditor.tsx b/apps/web/src/features/finance/invoices/InvoiceEditor.tsx index e4d48597..5153cb3d 100644 --- a/apps/web/src/features/finance/invoices/InvoiceEditor.tsx +++ b/apps/web/src/features/finance/invoices/InvoiceEditor.tsx @@ -15,12 +15,9 @@ import { useToast } from "@/common/components/ui/use-toast"; import { InvoiceStatus, InovicePaymentTerms } from "@/dataconnect-generated"; import { useCreateInvoice, - useCreateInvoiceTemplate, - useDeleteInvoiceTemplate, useGetInvoiceById, useListBusinesses, useListInvoices, - useListInvoiceTemplates, useListOrders, useListStaff, useListVendorRates, @@ -71,9 +68,6 @@ export default function InvoiceEditor() { const { data: staffData } = useListStaff(dataConnect); const staffDirectory = staffData?.staffs || []; - const { data: templatesData, refetch: refetchTemplates } = useListInvoiceTemplates(dataConnect); - const templates = templatesData?.invoiceTemplates || []; - const { data: currentInvoiceData } = useGetInvoiceById(dataConnect, { id: effectiveInvoiceId || "" }, { enabled: isEdit && !!effectiveInvoiceId }); const existingInvoice = currentInvoiceData?.invoice; @@ -176,7 +170,7 @@ export default function InvoiceEditor() { phone: existingInvoice.business?.phone || "", email: existingInvoice.business?.email || "", address: existingInvoice.business?.address || "", - manager_name: existingInvoice.business?.contactName || "", + manager_name: existingInvoice.managerName || "", hub_name: existingInvoice.hub || "", vendor_id: existingInvoice.vendorNumber || "" }, @@ -198,21 +192,6 @@ export default function InvoiceEditor() { const selectedBusiness = businesses.find(b => b.id === selectedClientId); if (!selectedBusiness || !position) return 0; - const businessName = selectedBusiness.businessName || ""; - const extractCompanyName = (name: string) => { - if (!name) return ''; - return name.split(/\s*[-–]\s*/)[0].trim(); - }; - const mainCompanyName = extractCompanyName(businessName); - - // Logic similar to MVP - const clientSpecificRate = vendorRates.find(rate => - rate.roleName?.toLowerCase() === position.toLowerCase() && - rate.client_name === businessName // This field might be different in Data Connect, checking listVendorRates output - ); - - if (clientSpecificRate) return clientSpecificRate.clientRate || 0; - const defaultRate = vendorRates.find(rate => rate.roleName?.toLowerCase() === position.toLowerCase() ); @@ -314,157 +293,6 @@ export default function InvoiceEditor() { }); }; - const handleDuplicateInvoice = (invoice: any) => { - const newStaffEntries = (invoice.roles || []).map((entry: any) => ({ - ...entry, - date: format(new Date(), 'MM/dd/yyyy') - })); - - const newInvoiceNumber = generateInvoiceNumber(invoice.business?.businessName || '', invoices); - - setFormData({ - invoice_number: newInvoiceNumber, - event_id: "", - event_name: invoice.order?.eventName || "", - invoice_date: format(new Date(), 'yyyy-MM-dd'), - due_date: format(addDays(new Date(), 45), 'yyyy-MM-dd'), - payment_terms: invoice.paymentTerms || "NET_45", - hub: invoice.hub || "", - manager: invoice.managerName || "", - vendor_id: invoice.vendorNumber || "", - department: invoice.order?.deparment || "", - po_reference: invoice.order?.poReference || "", - from_company: { - name: invoice.vendor?.companyName || formData.from_company.name, - address: invoice.vendor?.address || formData.from_company.address, - phone: invoice.vendor?.phone || formData.from_company.phone, - email: invoice.vendor?.email || formData.from_company.email, - }, - to_company: { - name: invoice.business?.businessName || "", - phone: invoice.business?.phone || "", - email: invoice.business?.email || "", - address: invoice.business?.address || "", - manager_name: invoice.business?.contactName || "", - hub_name: invoice.hub || "", - vendor_id: invoice.vendorNumber || "" - }, - staff_entries: newStaffEntries, - charges: invoice.charges || [], - other_charges: invoice.otherCharges || 0, - notes: invoice.notes || "", - }); - - if (invoice.businessId) { - setSelectedClientId(invoice.businessId); - } - - toast({ - title: "✅ Invoice Duplicated", - description: `Copied from ${invoice.invoiceNumber} - update dates and details as needed`, - }); - }; - - const { mutate: createTemplate } = useCreateInvoiceTemplate(dataConnect); - const { mutate: deleteTemplate } = useDeleteInvoiceTemplate(dataConnect); - - const handleUseTemplate = (template: any) => { - const newStaffEntries = (template.roles || []).map((entry: any) => ({ - ...entry, - name: "", - date: format(new Date(), 'MM/dd/yyyy'), - worked_hours: 0, - regular_hours: 0, - ot_hours: 0, - dt_hours: 0, - regular_value: 0, - ot_value: 0, - dt_value: 0, - total: 0 - })); - - const newInvoiceNumber = generateInvoiceNumber(template.business?.businessName || '', invoices); - - setFormData((prev: any) => ({ - ...prev, - invoice_number: newInvoiceNumber, - invoice_date: format(new Date(), 'yyyy-MM-dd'), - due_date: format(addDays(new Date(), 45), 'yyyy-MM-dd'), - payment_terms: template.paymentTerms || "NET_45", - hub: template.hub || "", - department: "", - po_reference: template.order?.poReference || "", - from_company: { - name: template.vendor?.companyName || prev.from_company.name, - address: template.vendor?.address || prev.from_company.address, - phone: template.vendor?.phone || prev.from_company.phone, - email: template.vendor?.email || prev.from_company.email, - }, - to_company: { - name: template.business?.businessName || "", - phone: template.business?.phone || "", - email: template.business?.email || "", - address: template.business?.address || "", - manager_name: template.business?.contactName || "", - hub_name: template.hub || "", - vendor_id: template.vendorNumber || "" - }, - staff_entries: newStaffEntries, - charges: template.charges || [], - notes: template.notes || "", - })); - - if (template.businessId) { - setSelectedClientId(template.businessId); - } - - toast({ - title: "✅ Template Applied", - description: `Applied "${template.name}" - fill in staff names and times`, - }); - }; - - const handleSaveTemplate = async (templateName: string) => { - const selectedBusiness = businesses.find(b => b.id === selectedClientId); - - await createTemplate({ - name: templateName, - ownerId: "00000000-0000-0000-0000-000000000000", // placeholder, usually from auth - businessId: selectedClientId || undefined, - vendorId: "00000000-0000-0000-0000-000000000000", // placeholder - paymentTerms: formData.payment_terms as InovicePaymentTerms, - invoiceNumber: formData.invoice_number, - issueDate: new Date(formData.invoice_date).toISOString(), - dueDate: new Date(formData.due_date).toISOString(), - hub: formData.hub, - managerName: formData.manager, - roles: formData.staff_entries, - charges: formData.charges, - otherCharges: parseFloat(formData.other_charges) || 0, - subtotal: totals.subtotal, - amount: totals.grandTotal, - notes: formData.notes, - staffCount: formData.staff_entries.length, - chargesCount: formData.charges.length, - }); - - refetchTemplates(); - - toast({ - title: "✅ Template Saved", - description: `"${templateName}" can now be reused for future invoices`, - }); - }; - - const handleDeleteTemplate = async (templateId: string) => { - await deleteTemplate({ id: templateId }); - refetchTemplates(); - toast({ - title: "Template Deleted", - description: "Template has been removed", - }); - }; - const parseTimeToMinutes = (timeStr: string) => { if (!timeStr || timeStr === "hh:mm") return null; const match = timeStr.match(/(\d{1,2}):(\d{2})\s*(AM|PM)/i); @@ -747,11 +575,11 @@ export default function InvoiceEditor() {

Disputed Items Highlighted

{disputedIndices.length} line item(s) have been disputed by the client. - Reason: {existingInvoice.dispute_reason || "Not specified"} + Reason: {existingInvoice.disputeReason || "Not specified"}

- {existingInvoice.dispute_details && ( + {existingInvoice.disputeDetails && (

- "{existingInvoice.dispute_details}" + "{existingInvoice.disputeDetails}"

)}

@@ -775,7 +603,7 @@ export default function InvoiceEditor() {

Quickly fill invoice from a completed event's shifts

- { const event = events.find(e => e.id === val); if (event) handleImportFromEvent(event); }}> @@ -1315,4 +1143,4 @@ export default function InvoiceEditor() { ); -} \ No newline at end of file +} diff --git a/apps/web/src/features/finance/invoices/InvoiceList.tsx b/apps/web/src/features/finance/invoices/InvoiceList.tsx index 723ae2fd..b9df1a67 100644 --- a/apps/web/src/features/finance/invoices/InvoiceList.tsx +++ b/apps/web/src/features/finance/invoices/InvoiceList.tsx @@ -59,7 +59,6 @@ export default function InvoiceList() { // If user is client, they should see their invoices. If admin, they see all. const userRole = user?.userRole?.toUpperCase(); const isClient = userRole === "CLIENT"; - const isVendor = userRole === "VENDOR"; if (isClient && inv.businessId !== user?.uid) return false; // In a real scenario, we'd match vendorId for vendor users diff --git a/apps/web/src/features/operations/orders/EditOrder.tsx b/apps/web/src/features/operations/orders/EditOrder.tsx index 83d62fb2..3ff199af 100644 --- a/apps/web/src/features/operations/orders/EditOrder.tsx +++ b/apps/web/src/features/operations/orders/EditOrder.tsx @@ -113,7 +113,7 @@ export default function EditOrder() { requested: totalRequested, total: eventData.total, poReference: eventData.po_reference, - }); + } as any); } }; @@ -146,7 +146,7 @@ export default function EditOrder() { staffName: s.staffName || s.staff_name, role: s.role })) - }); + } as any); setShowReductionAlert(false); setPendingUpdate(null); diff --git a/apps/web/src/features/operations/orders/OrderDetail.tsx b/apps/web/src/features/operations/orders/OrderDetail.tsx index 2cb4918f..899d2311 100644 --- a/apps/web/src/features/operations/orders/OrderDetail.tsx +++ b/apps/web/src/features/operations/orders/OrderDetail.tsx @@ -105,7 +105,6 @@ export default function OrderDetail() { // Fetch real shift roles to get IDs and accurate counts const { data: shiftRolesData, - isLoading: isLoadingShifts, refetch: refetchShifts } = useListShiftRolesByBusinessAndOrder( dataConnect, @@ -145,7 +144,7 @@ export default function OrderDetail() { cancelMutation.mutate({ id, status: OrderStatus.CANCELLED, - }); + } as any); }; const handleEdit = () => { diff --git a/apps/web/src/features/operations/orders/OrderList.tsx b/apps/web/src/features/operations/orders/OrderList.tsx index 14463846..6cc6e348 100644 --- a/apps/web/src/features/operations/orders/OrderList.tsx +++ b/apps/web/src/features/operations/orders/OrderList.tsx @@ -13,21 +13,19 @@ import DashboardLayout from "@/features/layouts/DashboardLayout"; import { Search, Calendar, - Filter, ArrowRight, Clock, CheckCircle, AlertTriangle, - XCircle, FileText } from "lucide-react"; -import React, { useMemo, useState } from "react"; +import { useMemo, useState } from "react"; import { useNavigate } from "react-router-dom"; import { useSelector } from "react-redux"; import type { RootState } from "@/store/store"; import { useListOrders, useListBusinesses } from "@/dataconnect-generated/react"; import { dataConnect } from "@/features/auth/firebase"; -import { format, isWithinInterval, parseISO, startOfDay, endOfDay } from "date-fns"; +import { format, isWithinInterval, startOfDay, endOfDay } from "date-fns"; import { OrderStatus } from "@/dataconnect-generated"; export default function OrderList() { diff --git a/apps/web/src/features/operations/orders/components/AssignStaffModal.tsx b/apps/web/src/features/operations/orders/components/AssignStaffModal.tsx index f622884d..4c048be6 100644 --- a/apps/web/src/features/operations/orders/components/AssignStaffModal.tsx +++ b/apps/web/src/features/operations/orders/components/AssignStaffModal.tsx @@ -1,6 +1,5 @@ -import React, { useState, useMemo } from "react"; -import { Search, Check, X, UserPlus, Star, Clock, AlertTriangle } from "lucide-react"; -import { format, isSameDay, parseISO } from "date-fns"; +import { useState, useMemo } from "react"; +import { Search, Check, Star, Clock, AlertTriangle } from "lucide-react"; import { Dialog, @@ -20,7 +19,6 @@ import { useCreateAssignment, useUpdateShiftRole, useListAssignments, - useListStaffAvailabilitiesByDay } from "@/dataconnect-generated/react"; import { dataConnect } from "@/features/auth/firebase"; import { AssignmentStatus } from "@/dataconnect-generated"; @@ -38,7 +36,6 @@ export default function AssignStaffModal({ isOpen, onClose, shift, onSuccess }: const [selectedStaff, setSelectedStaff] = useState(null); const vendorId = shift.shift?.order?.vendorId || shift.order?.vendorId; - const shiftDate = shift.shift?.date || shift.date; const shiftStartTime = shift.startTime || shift.start; const shiftEndTime = shift.endTime || shift.end; diff --git a/apps/web/src/features/operations/schedule/Schedule.tsx b/apps/web/src/features/operations/schedule/Schedule.tsx index 0deb571b..8af747d4 100644 --- a/apps/web/src/features/operations/schedule/Schedule.tsx +++ b/apps/web/src/features/operations/schedule/Schedule.tsx @@ -207,7 +207,7 @@ export default function Schedule() { updateOrderMutation.mutate({ id: rescheduleData.order.id, date: rescheduleData.newDate.toISOString() - }); + } as any); } }; diff --git a/apps/web/src/features/operations/tasks/TaskBoard.tsx b/apps/web/src/features/operations/tasks/TaskBoard.tsx index f95e146a..1de29ddf 100644 --- a/apps/web/src/features/operations/tasks/TaskBoard.tsx +++ b/apps/web/src/features/operations/tasks/TaskBoard.tsx @@ -39,7 +39,7 @@ export default function TaskBoard() { const [conditionalColoring, setConditionalColoring] = useState(true); // Queries - const { data: shiftsData, isLoading: shiftsLoading } = useListShifts(dataConnect); + const { data: shiftsData } = useListShifts(dataConnect); const { data: clientsData } = useListBusinesses(dataConnect); const shifts = useMemo(() => shiftsData?.shifts || [], [shiftsData]); diff --git a/apps/web/src/features/operations/tasks/TaskCard.tsx b/apps/web/src/features/operations/tasks/TaskCard.tsx index 47bb7c3f..786500b0 100644 --- a/apps/web/src/features/operations/tasks/TaskCard.tsx +++ b/apps/web/src/features/operations/tasks/TaskCard.tsx @@ -31,7 +31,7 @@ export default function TaskCard({ provided, onClick, itemHeight = "normal", - conditionalColoring = true + conditionalColoring: _conditionalColoring = true }: TaskCardProps) { const heightClasses = { compact: "p-3", diff --git a/apps/web/src/features/workforce/directory/AddStaff.tsx b/apps/web/src/features/workforce/directory/AddStaff.tsx index c108389f..343f5c1d 100644 --- a/apps/web/src/features/workforce/directory/AddStaff.tsx +++ b/apps/web/src/features/workforce/directory/AddStaff.tsx @@ -164,7 +164,8 @@ export default function AddStaff() { { + onChange={(e) => { + const checked = e.target.checked; const updatedSkills = checked ? [...(field.value || []), skill] : field.value?.filter((s: string) => s !== skill); diff --git a/apps/web/src/features/workforce/directory/StaffList.tsx b/apps/web/src/features/workforce/directory/StaffList.tsx index 32b4d788..a3efe9d3 100644 --- a/apps/web/src/features/workforce/directory/StaffList.tsx +++ b/apps/web/src/features/workforce/directory/StaffList.tsx @@ -18,7 +18,7 @@ const ITEMS_PER_PAGE = 10; function StaffActiveStatus({ staffId }: { staffId: string }) { const { data: staffDetail, isLoading } = useGetStaffById(dataConnect, { id: staffId }); - const getLastActiveText = (lastActive?: string) => { + const getLastActiveText = (lastActive?: string | null) => { if (!lastActive) return 'Never'; try { const date = new Date(lastActive); diff --git a/apps/web/src/features/workforce/directory/components/EmployeeCard.tsx b/apps/web/src/features/workforce/directory/components/EmployeeCard.tsx index 020ac0f0..ccf313c7 100644 --- a/apps/web/src/features/workforce/directory/components/EmployeeCard.tsx +++ b/apps/web/src/features/workforce/directory/components/EmployeeCard.tsx @@ -74,7 +74,7 @@ export default function EmployeeCard({ staff }: EmployeeCardProps) { const coveragePercentage = staff.shift_coverage_percentage || 0; const cancellationCount = staff.cancellation_count || 0; const noShowCount = staff.no_show_count || 0; - const rating = staff.rating || 0; + const rating = staff.averageRating || 0; const reliabilityScore = staff.reliability_score || 0; const reliability = getReliabilityColor(reliabilityScore); diff --git a/apps/web/src/features/workforce/documents/DocumentVault.tsx b/apps/web/src/features/workforce/documents/DocumentVault.tsx index fc147dbf..02404377 100644 --- a/apps/web/src/features/workforce/documents/DocumentVault.tsx +++ b/apps/web/src/features/workforce/documents/DocumentVault.tsx @@ -107,7 +107,7 @@ export default function DocumentVault() { const filteredStaff = useMemo(() => { let result = [...staff]; if (isVendor && user?.uid) { - result = result.filter(s => s.ownerId === user.uid || s.createdBy === user.email); + result = result.filter(s => s.ownerId === user.uid); } if (searchTerm) { result = result.filter(s => @@ -472,7 +472,7 @@ export default function DocumentVault() { Employees - {availableDocTypes.map((type, idx) => ( + {availableDocTypes.map((type) => (
{type.name}