diff --git a/apps/web/package.json b/apps/web/package.json index f984fcd0..385c8b38 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -14,6 +14,7 @@ "@firebase/data-connect": "^0.3.12", "@radix-ui/react-label": "^2.1.7", "@radix-ui/react-slot": "^1.2.4", + "@radix-ui/react-tabs": "^1.1.13", "@radix-ui/themes": "^3.2.1", "@reduxjs/toolkit": "^2.11.2", "@tailwindcss/vite": "^4.1.18", diff --git a/apps/web/pnpm-lock.yaml b/apps/web/pnpm-lock.yaml index 3bfa8f7e..9c831927 100644 --- a/apps/web/pnpm-lock.yaml +++ b/apps/web/pnpm-lock.yaml @@ -23,6 +23,9 @@ importers: '@radix-ui/react-slot': specifier: ^1.2.4 version: 1.2.4(@types/react@19.2.10)(react@19.2.4) + '@radix-ui/react-tabs': + specifier: ^1.1.13 + version: 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@radix-ui/themes': specifier: ^3.2.1 version: 3.2.1(@types/react-dom@19.2.3(@types/react@19.2.10))(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) diff --git a/apps/web/src/common/components/ui/tabs.tsx b/apps/web/src/common/components/ui/tabs.tsx new file mode 100644 index 00000000..abadf3d8 --- /dev/null +++ b/apps/web/src/common/components/ui/tabs.tsx @@ -0,0 +1,52 @@ +import React from 'react'; +import * as TabsPrimitive from '@radix-ui/react-tabs'; +import { cn } from '@/lib/utils'; + +const Tabs = TabsPrimitive.Root; + +const TabsList = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +TabsList.displayName = TabsPrimitive.List.displayName; + +const TabsTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +TabsTrigger.displayName = TabsPrimitive.Trigger.displayName; + +const TabsContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +TabsContent.displayName = TabsPrimitive.Content.displayName; + +export { Tabs, TabsList, TabsTrigger, TabsContent }; diff --git a/apps/web/src/features/business/clients/EditClient.tsx b/apps/web/src/features/business/clients/EditClient.tsx index c324a9bf..90a44f8c 100644 --- a/apps/web/src/features/business/clients/EditClient.tsx +++ b/apps/web/src/features/business/clients/EditClient.tsx @@ -1,8 +1,371 @@ +import React, { useState, useEffect } from "react"; +import { useNavigate, useParams } from "react-router-dom"; +import { useQueryClient } from "@tanstack/react-query"; +import { Button } from "@/common/components/ui/button"; +import { Card, CardContent, CardHeader, CardTitle } from "@/common/components/ui/card"; +import { Input } from "@/common/components/ui/input"; +import { Label } from "@/common/components/ui/label"; +import { Textarea } from "@/common/components/ui/textarea"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue +} from "@/common/components/ui/select"; +import { ArrowLeft, Save, Loader2, Building2, User, MapPin, CreditCard, Activity } from "lucide-react"; +import DashboardLayout from "@/features/layouts/DashboardLayout"; +import { + useGetBusinessById, + useUpdateBusiness +} from "@/dataconnect-generated/react"; +import { + BusinessArea, + BusinessSector, + BusinessStatus, + BusinessRateGroup +} from "@/dataconnect-generated"; +import { dataConnect } from "@/features/auth/firebase"; + +export default function EditClient() { + const navigate = useNavigate(); + const queryClient = useQueryClient(); + const { id: businessId } = useParams<{ id: string }>(); + + const { data: businessData, isLoading: isLoadingBusiness } = useGetBusinessById(dataConnect, { id: businessId || "" }); + const { mutateAsync: updateBusiness, isPending: isUpdating } = useUpdateBusiness(dataConnect); + + const [formData, setFormData] = useState({ + businessName: "", + sector: BusinessSector.OTHER, + address: "", + city: "", + area: BusinessArea.OTHER, + contactName: "", + phone: "", + email: "", + rateGroup: BusinessRateGroup.STANDARD, + status: BusinessStatus.ACTIVE, + notes: "" + }); + + useEffect(() => { + if (businessData?.business) { + const b = businessData.business; + setFormData({ + businessName: b.businessName || "", + sector: b.sector || BusinessSector.OTHER, + address: b.address || "", + city: b.city || "", + area: b.area || BusinessArea.OTHER, + contactName: b.contactName || "", + phone: b.phone || "", + email: b.email || "", + rateGroup: b.rateGroup || BusinessRateGroup.STANDARD, + status: b.status || BusinessStatus.ACTIVE, + notes: b.notes || "" + }); + } + }, [businessData]); + + const handleChange = (field: string, value: any) => { + setFormData(prev => ({ ...prev, [field]: value })); + }; + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + if (!businessId) return; + + try { + await updateBusiness({ + id: businessId, + businessName: formData.businessName, + contactName: formData.contactName, + phone: formData.phone, + email: formData.email, + address: formData.address, + city: formData.city, + area: formData.area, + sector: formData.sector, + rateGroup: formData.rateGroup, + status: formData.status, + notes: formData.notes + }); + + queryClient.invalidateQueries({ queryKey: ['businesses'] }); + queryClient.invalidateQueries({ queryKey: ['business', businessId] }); + navigate("/clients"); + } catch (error) { + console.error("Error updating client:", error); + } + }; + + if (isLoadingBusiness) { + return ( +
+ +
+ ); + } + + if (!businessData?.business) { + return ( + +
+

Business record not found.

+ +
+
+ ); + } -const EditClient = () => { return ( -
EditClient
- ) -} + navigate("/clients")} + leadingIcon={} + > + Back to Directory + + } + > +
+
+ {/* General Information */} + + + + + General Information + + + +
+
+ + handleChange('businessName', e.target.value)} + required + /> +
+
+ + +
+
+
+
-export default EditClient \ No newline at end of file + {/* Billing Information */} + + + + + Billing Information + + + +
+ + handleChange('address', e.target.value)} + required + /> +
+
+
+ + handleChange('city', e.target.value)} + required + /> +
+
+ + +
+
+
+
+ + {/* Primary Contact */} + + + + + Primary Contact + + + +
+ + handleChange('contactName', e.target.value)} + required + /> +
+
+
+ + handleChange('phone', e.target.value)} + /> +
+
+ + handleChange('email', e.target.value)} + required + /> +
+
+
+
+ + {/* Rate Configuration & Status */} +
+ + + + + Rate Configuration + + + +
+ + +
+
+
+ + + + + + Partnership Status + + + +
+ + +
+
+
+
+ + {/* Notes */} + + + Notes + + +
+ +