diff --git a/apps/web/src/common/components/ui/badge.tsx b/apps/web/src/common/components/ui/badge.tsx
index fd33e2e7..43ee64f9 100644
--- a/apps/web/src/common/components/ui/badge.tsx
+++ b/apps/web/src/common/components/ui/badge.tsx
@@ -13,6 +13,8 @@ const badgeVariants = cva(
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
destructive:
"border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
+ success:
+ "border-transparent bg-emerald-500 text-white hover:bg-emerald-500/80",
outline: "text-foreground",
},
},
diff --git a/apps/web/src/features/business/clients/AddClient.tsx b/apps/web/src/features/business/clients/AddClient.tsx
new file mode 100644
index 00000000..e277f72c
--- /dev/null
+++ b/apps/web/src/features/business/clients/AddClient.tsx
@@ -0,0 +1,380 @@
+import { Button } from "@/common/components/ui/button";
+import { Input } from "@/common/components/ui/input";
+import { Label } from "@/common/components/ui/label";
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from "@/common/components/ui/select";
+import { Textarea } from "@/common/components/ui/textarea";
+import DashboardLayout from "@/features/layouts/DashboardLayout";
+import { ArrowLeft, Loader2, Save, X, Mail } from "lucide-react";
+import React, { useState } from "react";
+import { useNavigate } from "react-router-dom";
+import { useQueryClient } from "@tanstack/react-query";
+import { useSelector } from "react-redux";
+import type { RootState } from "@/store/store";
+import {
+ useCreateBusiness,
+ useCreateTeamHub
+} from "@/dataconnect-generated/react";
+import {
+ BusinessArea,
+ BusinessSector,
+ BusinessStatus,
+ BusinessRateGroup
+} from "@/dataconnect-generated";
+import { dataConnect } from "@/features/auth/firebase";
+import { motion, AnimatePresence } from "framer-motion";
+
+export default function AddClient() {
+ const navigate = useNavigate();
+ const queryClient = useQueryClient();
+ const { user } = useSelector((state: RootState) => state.auth);
+
+ const [showSnackbar, setShowSnackbar] = useState(false);
+ const [snackbarMessage, setSnackbarMessage] = useState("");
+
+ const [formData, setFormData] = useState({
+ businessName: "",
+ companyLogoUrl: "",
+ contactName: "",
+ phone: "",
+ email: "",
+ hubBuilding: "",
+ address: "",
+ city: "",
+ area: BusinessArea.BAY_AREA,
+ sector: BusinessSector.OTHER,
+ rateGroup: BusinessRateGroup.STANDARD,
+ status: BusinessStatus.ACTIVE,
+ notes: ""
+ });
+
+ const { mutateAsync: createBusiness, isPending: isCreatingBusiness } = useCreateBusiness(dataConnect);
+ const { mutateAsync: createHub, isPending: isCreatingHub } = useCreateTeamHub(dataConnect);
+
+ const handleChange = (field: string, value: any) => {
+ setFormData(prev => ({ ...prev, [field]: value }));
+ };
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+ if (!user?.uid) return;
+
+ try {
+ // 1. Create the business record
+ const businessResult = await createBusiness({
+ businessName: formData.businessName,
+ contactName: formData.contactName,
+ userId: user.uid,
+ companyLogoUrl: formData.companyLogoUrl,
+ phone: formData.phone,
+ email: formData.email,
+ hubBuilding: formData.hubBuilding,
+ address: formData.address,
+ city: formData.city,
+ area: formData.area,
+ sector: formData.sector,
+ rateGroup: formData.rateGroup,
+ status: formData.status,
+ notes: formData.notes
+ });
+
+ const businessId = businessResult.business_insert.id;
+
+ // 2. Automatically create the client's first "hub" or location
+ await createHub({
+ teamId: businessId,
+ hubName: `${formData.businessName} - Main Hub`,
+ address: formData.address || "Main Office",
+ city: formData.city,
+ isActive: true
+ });
+
+ // 3. Show snackbar for welcome email
+ setSnackbarMessage(`Welcome email sent to ${formData.contactName} (${formData.email})`);
+ setShowSnackbar(true);
+
+ // Invalidate queries and navigate after a delay to show snackbar
+ queryClient.invalidateQueries({ queryKey: ['businesses'] });
+
+ setTimeout(() => {
+ navigate("/clients");
+ }, 3000);
+
+ } catch (error) {
+ console.error("Error creating client partnership:", error);
+ setSnackbarMessage("Failed to create client partnership. Please try again.");
+ setShowSnackbar(true);
+ }
+ };
+
+ const isPending = isCreatingBusiness || isCreatingHub;
+
+ return (
+ {snackbarMessage} Only administrators are authorized to view and manage business client records. Total Clients {businesses.length} Active Hubs {hubs.length} Total Orders {orders.length} Loading clients... No business clients found matching your search.Restricted Access
+
+
+
+
+
+
+
+ {isLoading ? (
+ Business Name
+ Logo
+ Industry
+ Status
+ Hubs
+ Last Order
+ Action
+
+
+ ) : filteredClients.length > 0 ? (
+ filteredClients.map((client) => (
+
+
+ navigate(`/clients/${client.id}/edit`)}
+ >
+
+ ))
+ ) : (
+
+
+
+
+
+ ) : (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )}
+
+
+
+