- );
-}
\ No newline at end of file
diff --git a/frontend-web/src/pages/Schedule.jsx b/frontend-web/src/pages/Schedule.jsx
deleted file mode 100644
index a1f65bf9..00000000
--- a/frontend-web/src/pages/Schedule.jsx
+++ /dev/null
@@ -1,252 +0,0 @@
-import React, { useState } from "react";
-import { base44 } from "@/api/base44Client";
-import { useQuery } from "@tanstack/react-query";
-import { useNavigate } from "react-router-dom";
-import { createPageUrl } from "@/utils";
-import { Button } from "@/components/ui/button";
-import { Card, CardContent } from "@/components/ui/card";
-import { ChevronLeft, ChevronRight, Plus, Clock, DollarSign, Calendar as CalendarIcon } from "lucide-react";
-import { format, startOfWeek, addDays, isSameDay, addWeeks, subWeeks, isToday, parseISO } from "date-fns";
-
-const safeParseDate = (dateString) => {
- if (!dateString) return null;
- try {
- if (typeof dateString === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(dateString)) {
- const [year, month, day] = dateString.split('-').map(Number);
- return new Date(year, month - 1, day);
- }
- return parseISO(dateString);
- } catch {
- return null;
- }
-};
-
-export default function Schedule() {
- const navigate = useNavigate();
- const [currentWeek, setCurrentWeek] = useState(startOfWeek(new Date(), { weekStartsOn: 0 }));
-
- const { data: events = [] } = useQuery({
- queryKey: ['events'],
- queryFn: () => base44.entities.Event.list('-date'),
- initialData: [],
- });
-
- const weekDays = Array.from({ length: 7 }, (_, i) => addDays(currentWeek, i));
-
- const getEventsForDay = (date) => {
- return events.filter(event => {
- const eventDate = safeParseDate(event.date);
- return eventDate && isSameDay(eventDate, date);
- });
- };
-
- const calculateWeekMetrics = () => {
- const weekEvents = events.filter(event => {
- const eventDate = safeParseDate(event.date);
- if (!eventDate) return false;
- return weekDays.some(day => isSameDay(eventDate, day));
- });
-
- const totalHours = weekEvents.reduce((sum, event) => {
- const hours = event.shifts?.reduce((shiftSum, shift) => {
- return shiftSum + (shift.roles?.reduce((roleSum, role) => roleSum + (role.hours || 0), 0) || 0);
- }, 0) || 0;
- return sum + hours;
- }, 0);
-
- const totalCost = weekEvents.reduce((sum, event) => sum + (event.total || 0), 0);
- const totalShifts = weekEvents.reduce((sum, event) => sum + (event.shifts?.length || 0), 0);
-
- return { totalHours, totalCost, totalShifts };
- };
-
- const metrics = calculateWeekMetrics();
-
- const goToPreviousWeek = () => setCurrentWeek(subWeeks(currentWeek, 1));
- const goToNextWeek = () => setCurrentWeek(addWeeks(currentWeek, 1));
- const goToToday = () => setCurrentWeek(startOfWeek(new Date(), { weekStartsOn: 0 }));
-
- return (
-
- );
-}
\ No newline at end of file
diff --git a/frontend-web/src/pages/SectorManagement.jsx b/frontend-web/src/pages/SectorManagement.jsx
deleted file mode 100644
index 78c6e98f..00000000
--- a/frontend-web/src/pages/SectorManagement.jsx
+++ /dev/null
@@ -1,141 +0,0 @@
-import React, { useState } from "react";
-import { base44 } from "@/api/base44Client";
-import { useQuery } from "@tanstack/react-query";
-import { Link } from "react-router-dom";
-import { createPageUrl } from "@/utils";
-import { Button } from "@/components/ui/button";
-import { Card, CardContent } from "@/components/ui/card";
-import { Input } from "@/components/ui/input";
-import { Badge } from "@/components/ui/badge";
-import { MapPin, Plus, Search, Building2, Edit } from "lucide-react";
-import PageHeader from "@/components/common/PageHeader";
-
-export default function SectorManagement() {
- const [searchTerm, setSearchTerm] = useState("");
-
- const { data: sectors = [], isLoading } = useQuery({
- queryKey: ['sectors'],
- queryFn: () => base44.entities.Sector.list('-created_date'),
- initialData: [],
- });
-
- const filteredSectors = sectors.filter(s =>
- !searchTerm ||
- s.sector_name?.toLowerCase().includes(searchTerm.toLowerCase()) ||
- s.sector_code?.toLowerCase().includes(searchTerm.toLowerCase())
- );
-
- const getSectorColor = (index) => {
- const colors = [
- "from-blue-500 to-blue-700",
- "from-green-500 to-green-700",
- "from-purple-500 to-purple-700",
- "from-orange-500 to-orange-700",
- ];
- return colors[index % colors.length];
- };
-
- return (
-
- );
-}
\ No newline at end of file
diff --git a/frontend-web/src/pages/Settings.jsx b/frontend-web/src/pages/Settings.jsx
deleted file mode 100644
index feb17026..00000000
--- a/frontend-web/src/pages/Settings.jsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import React from "react";
-import { Settings as SettingsIcon } from "lucide-react";
-
-export default function Settings() {
- return (
-
- );
-}
\ No newline at end of file
diff --git a/frontend-web/src/pages/SmartScheduler.jsx b/frontend-web/src/pages/SmartScheduler.jsx
deleted file mode 100644
index 6e1ab356..00000000
--- a/frontend-web/src/pages/SmartScheduler.jsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import React from "react";
-import { useNavigate } from "react-router-dom";
-import { createPageUrl } from "@/utils";
-import { Card, CardContent } from "@/components/ui/card";
-import { Button } from "@/components/ui/button";
-import { ArrowRight, Sparkles } from "lucide-react";
-
-export default function SmartScheduler() {
- const navigate = useNavigate();
-
- return (
-
- );
-}
\ No newline at end of file
diff --git a/frontend-web/src/pages/SmartVendorOnboarding.jsx b/frontend-web/src/pages/SmartVendorOnboarding.jsx
deleted file mode 100644
index 21c29106..00000000
--- a/frontend-web/src/pages/SmartVendorOnboarding.jsx
+++ /dev/null
@@ -1,2888 +0,0 @@
-
-import React, { useState, useEffect } from "react";
-import { base44 } from "@/api/base44Client";
-import { useMutation, useQuery } from "@tanstack/react-query";
-import { useNavigate } from "react-router-dom";
-import { createPageUrl } from "@/utils";
-import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
-import { Button } from "@/components/ui/button";
-import { Input } from "@/components/ui/input";
-import { Label } from "@/components/ui/label";
-import { Textarea } from "@/components/ui/textarea";
-import { Badge } from "@/components/ui/badge";
-import { Progress } from "@/components/ui/progress";
-import {
- Building2, FileText, MapPin, DollarSign, Sparkles, Upload,
- CheckCircle2, Loader2, AlertCircle, ArrowRight, ArrowLeft,
- Shield, TrendingUp, Users, Briefcase, Mail, Phone, Hash,
- Search, Calendar, Plus, Trash2, Check, Target
-} from "lucide-react";
-import { useToast } from "@/components/ui/use-toast";
-import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
-import { Checkbox } from "@/components/ui/checkbox";
-import {
- Dialog,
- DialogContent,
- DialogHeader,
- DialogTitle,
- DialogDescription,
-} from "@/components/ui/dialog";
-import DragDropFileUpload from "@/components/common/DragDropFileUpload";
-import DocumentViewer from "@/components/vendor/DocumentViewer";
-
-// Google Places Autocomplete Component
-const GoogleAddressInput = ({ value, onChange, placeholder, label, required }) => {
- const [inputValue, setInputValue] = useState(value || "");
- const [suggestions, setSuggestions] = useState([]);
- const [showSuggestions, setShowSuggestions] = useState(false);
- const inputRef = React.useRef(null);
-
- useEffect(() => {
- setInputValue(value || "");
- }, [value]);
-
- const handleAddressSearch = async (searchText) => {
- setInputValue(searchText);
-
- if (searchText.length < 3) {
- setSuggestions([]);
- return;
- }
-
- try {
- // Use Google Places API via integration
- const response = await base44.integrations.Core.InvokeLLM({
- prompt: `Extract and return ONLY a valid JSON array of 5 US address suggestions for: "${searchText}". Format each as: {"address": "full formatted address", "city": "city", "state": "state", "zip": "zip"}. Return ONLY the JSON array, no other text.`,
- response_json_schema: {
- type: "object",
- properties: {
- suggestions: {
- type: "array",
- items: {
- type: "object",
- properties: {
- address: { type: "string" },
- city: { type: "string" },
- state: { type: "string" },
- zip: { type: "string" }
- }
- }
- }
- }
- }
- });
-
- if (response?.suggestions) {
- setSuggestions(response.suggestions);
- setShowSuggestions(true);
- }
- } catch (error) {
- console.error("Address search error:", error);
- }
- };
-
- const handleSelectAddress = (suggestion) => {
- const fullAddress = `${suggestion.address}, ${suggestion.city}, ${suggestion.state} ${suggestion.zip}`;
- setInputValue(fullAddress);
- onChange(fullAddress);
- setSuggestions([]);
- setShowSuggestions(false);
- };
-
- return (
-
- );
-};
-
-export default function SmartVendorOnboarding() {
- const { toast } = useToast();
- const navigate = useNavigate();
-
- const [currentStep, setCurrentStep] = useState(0); // Changed from 1 to 0 for welcome screen
- const [generatingRates, setGeneratingRates] = useState(false);
-
- // Function to detect minimum wage based on business address
- const getMinimumWageFromAddress = (address) => {
- if (!address) return 18; // Default fallback
-
- const addr = address.toLowerCase();
-
- // State-specific minimum wages (as of 2024)
- if (addr.includes('california') || addr.includes(' ca ') || addr.includes('ca,')) return 16.00;
- if (addr.includes('washington') || addr.includes(' wa ')) return 16.28;
- if (addr.includes('massachusetts') || addr.includes(' ma ')) return 15.00;
- if (addr.includes('new york') || addr.includes(' ny ')) return 15.00;
- if (addr.includes('connecticut') || addr.includes(' ct ')) return 15.00;
- if (addr.includes('arizona') || addr.includes(' az ')) return 14.35;
- if (addr.includes('colorado') || addr.includes(' co ')) return 14.42;
- if (addr.includes('maine') || addr.includes(' me ')) return 14.15;
- if (addr.includes('oregon') || addr.includes(' or ')) return 14.20;
- if (addr.includes('vermont') || addr.includes(' vt ')) return 13.67;
- if (addr.includes('illinois') || addr.includes(' il ')) return 14.00;
- if (addr.includes('rhode island') || addr.includes(' ri ')) return 14.00;
- if (addr.includes('new jersey') || addr.includes(' nj ')) return 15.13;
- if (addr.includes('florida') || addr.includes(' fl ')) return 12.00;
- if (addr.includes('nevada') || addr.includes(' nv ')) return 12.00;
- if (addr.includes('hawaii') || addr.includes(' hi ')) return 14.00;
- if (addr.includes('texas') || addr.includes(' tx ')) return 7.25;
- if (addr.includes('georgia') || addr.includes(' ga ')) return 7.25;
- if (addr.includes('pennsylvania') || addr.includes(' pa ')) return 7.25;
- if (addr.includes('ohio') || addr.includes(' oh ')) return 10.45;
- if (addr.includes('michigan') || addr.includes(' mi ')) return 10.33;
- if (addr.includes('virginia') || addr.includes(' va ')) return 12.00;
- if (addr.includes('north carolina') || addr.includes(' nc ')) return 7.25;
- if (addr.includes('tennessee') || addr.includes(' tn ')) return 7.25;
-
- return 15.00; // Default minimum wage for unspecified states
- };
-
- const [formData, setFormData] = useState({
- // NEW: NDA Step (Step 1)
- nda_acknowledged: false,
- nda_signed_by: "",
- nda_signature_date: "",
- nda_signature_time: "",
- nda_signature_image: "", // NEW: Store the signature image data
-
- // Contract Data (now Step 2)
- contract_review_notes: "",
- contract_acknowledged: false,
- contract_va_fee_acknowledged: false,
- contract_review_time: 0,
-
- // Business Identity (now Step 3)
- legal_name: "",
- dba: "",
- tax_id: "",
- business_type: "",
- primary_contact_name: "",
- primary_contact_email: "",
- primary_contact_phone: "",
- billing_address: "",
- service_address: "",
- same_as_billing: false, // This now means "billing address is same as service address"
- total_employees: "",
- has_software: "",
- software_name: "",
- software_type: "",
-
- // Documents (now Step 4)
- w9_file: null,
- coi_file: null,
- sos_file: null,
- w9_url: "",
- coi_url: "",
- sos_url: "",
- background_check_attestation: false,
- i9_compliance_attestation: false,
- legal_compliance_attestation: false,
-
- // Service Coverage (now Step 5)
- coverage_regions: [],
- selected_states: [],
- selected_cities: {},
-
- // Rate Proposals (now Step 6)
- rate_proposals: [],
- default_location: ""
- });
-
- const [uploadingDoc, setUploadingDoc] = useState(null);
- const [validatingDoc, setValidatingDoc] = useState(null);
- const [docValidation, setDocValidation] = useState({
- w9: null,
- coi: null,
- sos: null,
- // contract: null, // Removed for contract upload status
- });
- const [showAIInsights, setShowAIInsights] = useState(false);
- const [aiInsights, setAiInsights] = useState(null);
-
- // Get invite data from URL
- const urlParams = new URLSearchParams(window.location.search);
- const inviteCode = urlParams.get('invite');
-
- const { data: invite } = useQuery({
- queryKey: ['vendor-invite', inviteCode],
- queryFn: async () => {
- if (!inviteCode) return null;
- const invites = await base44.entities.VendorInvite.filter({ invite_code: inviteCode });
- return invites[0];
- },
- enabled: !!inviteCode
- });
-
- // Pre-fill data from invite
- useEffect(() => {
- if (invite) {
- setFormData(prev => ({
- ...prev,
- legal_name: invite.company_name || "",
- primary_contact_name: invite.primary_contact_name || "",
- primary_contact_email: invite.primary_contact_email || ""
- }));
- }
- }, [invite]);
-
-
- const steps = [
- { number: 0, title: "Welcome", icon: Sparkles, subtitle: "Let's get started" },
- { number: 1, title: "NDA & Trust", icon: Shield, subtitle: "Sign and accept agreement" },
- { number: 2, title: "Foodbuy Contract", icon: FileText, subtitle: "Review & acknowledge terms" },
- { number: 3, title: "Business Identity", icon: Building2, subtitle: "Let's set your stage" },
- { number: 4, title: "Documents & Validation", icon: Shield, subtitle: "Compliance essentials" },
- { number: 5, title: "Service Coverage", icon: MapPin, subtitle: "Where you operate" },
- { number: 6, title: "Rate Proposals", icon: DollarSign, subtitle: "Competitive pricing" },
- { number: 7, title: "AI Intelligence", icon: Sparkles, subtitle: "Market insights" }
- ];
-
- const progressPercentage = currentStep === 0 ? 0 : ((currentStep - 1) / (steps.length - 2)) * 100;
-
- // Upload document
- const handleFileUpload = async (file, docType) => {
- if (!file) return;
-
- setUploadingDoc(docType);
- try {
- // Upload file
- const { file_url } = await base44.integrations.Core.UploadFile({ file });
-
- setFormData(prev => ({
- ...prev,
- [`${docType}_url`]: file_url,
- [`${docType}_file`]: file
- }));
-
- // For contract, the logic has been removed as it's handled by DocumentViewer
- // and AI analysis of an uploaded contract is no longer directly here.
-
- // Validate document with AI
- setValidatingDoc(docType);
- const validation = await validateDocument(file_url, docType);
-
- setDocValidation(prev => ({
- ...prev,
- [docType]: validation
- }));
-
- toast({
- title: "Document Uploaded",
- description: validation.isValid ? "✅ Document validated successfully" : "âš ï¸ Please review validation notes",
- });
- } catch (error) {
- toast({
- title: "Upload Failed",
- description: error.message,
- variant: "destructive"
- });
- } finally {
- setUploadingDoc(null);
- setValidatingDoc(null);
- }
- };
-
- // Validate document with AI
- const validateDocument = async (fileUrl, docType) => {
- const prompts = {
- w9: "Analyze this W-9 tax form and verify: 1) Business name is filled 2) Tax ID is present 3) Business entity type is checked 4) Signature is present. Return validation results.",
- coi: "Analyze this Certificate of Insurance and verify: 1) General liability coverage is present 2) Coverage amount meets $1M minimum 3) Policy is not expired 4) KROW or client is listed as additional insured. Return validation results.",
- sos: "Analyze this Secretary of State certificate and verify: 1) Business is actively registered 2) Registration is current/not expired 3) Business name matches application 4) State of registration. Return validation results."
- };
-
- try {
- const analysis = await base44.integrations.Core.InvokeLLM({
- prompt: prompts[docType],
- file_urls: [fileUrl],
- response_json_schema: {
- type: "object",
- properties: {
- isValid: { type: "boolean" },
- businessName: { type: "string" },
- expiryDate: { type: "string" },
- registrationState: { type: "string" },
- issues: { type: "array", items: { type: "string" } },
- notes: { type: "string" }
- }
- }
- });
-
- return analysis;
- } catch (error) {
- return {
- isValid: false,
- issues: ["Unable to validate document automatically"],
- notes: "Manual review required"
- };
- }
- };
-
- // Generate AI rate suggestions - This function remains but its direct UI trigger in Step 4 is removed
- const generateAIRates = async () => {
- setGeneratingRates(true);
- try {
- const response = await base44.integrations.Core.InvokeLLM({
- prompt: `
- Generate competitive rate proposals for ${formData.legal_name}.
- Business Type: ${formData.business_type}
- Service Regions: ${Object.values(formData.selected_cities).flat().map(city => city).join(", ")}
- Total Employees: ${formData.total_employees}
- Software Type: ${formData.software_type}
-
- Provide 10-15 common staffing roles with competitive rates for the hospitality/event industry.
- Consider regional market rates and vendor's operational efficiency.
-
- For each role, provide:
- - Role name
- - Category (Kitchen and Culinary, Concessions, Facilities, Bartending, Security, Event Staff, Management)
- - Employee wage (competitive market rate)
- - Suggested markup percentage (18-25% based on role complexity)
- - Calculated client rate
- `,
- add_context_from_internet: true,
- response_json_schema: {
- type: "object",
- properties: {
- roles: {
- type: "array",
- items: {
- type: "object",
- properties: {
- role_name: { type: "string" },
- category: { type: "string" },
- employee_wage: { type: "number" },
- markup_percentage: { type: "number" },
- client_rate: { type: "number" },
- market_comparison: { type: "string" }
- }
- }
- }
- }
- }
- });
-
- if (response?.roles) {
- setFormData(prev => ({
- ...prev,
- rate_proposals: response.roles
- }));
-
- toast({
- title: "Rates Generated",
- description: `${response.roles.length} competitive rates suggested`,
- });
- }
- } catch (error) {
- toast({
- title: "Generation Failed",
- description: error.message,
- variant: "destructive"
- });
- } finally {
- setGeneratingRates(null);
- }
- };
-
- // Generate AI insights
- const generateAIInsights = async () => {
- try {
- const insights = await base44.integrations.Core.InvokeLLM({
- prompt: `
- Analyze this vendor application and provide strategic insights:
-
- Vendor: ${formData.legal_name}
- Business Type: ${formData.business_type}
- Total Employees: ${formData.total_employees}
- Software: ${formData.software_name || formData.software_type}
- Service Areas: ${Object.values(formData.selected_cities).flat().map(city => city).join(", ")}
- Rate Proposals: ${formData.rate_proposals.length} roles
-
- Provide:
- 1. Competitive positioning (1-5 stars)
- 2. Market alignment assessment
- 3. Pricing competitiveness
- 4. Operational readiness score
- 5. Recommended focus areas
- 6. Potential challenges
- `,
- add_context_from_internet: true,
- response_json_schema: {
- type: "object",
- properties: {
- overall_score: { type: "number" },
- competitive_position: { type: "string" },
- market_alignment: { type: "string" },
- pricing_analysis: { type: "string" },
- operational_readiness: { type: "string" },
- strengths: { type: "array", items: { type: "string" } },
- recommendations: { type: "array", items: { type: "string" } },
- potential_challenges: { type: "array", items: { type: "string" } }
- }
- }
- });
-
- setAiInsights(insights);
- setShowAIInsights(true);
- } catch (error) {
- toast({
- title: "Analysis Failed",
- description: error.message,
- variant: "destructive"
- });
- }
- };
-
- // US States and Major Cities Data
- const usLocationData = {
- "Alabama": ["Birmingham", "Montgomery", "Mobile", "Huntsville"],
- "Alaska": ["Anchorage", "Fairbanks", "Juneau"],
- "Arizona": ["Phoenix", "Tucson", "Mesa", "Scottsdale", "Chandler"],
- "Arkansas": ["Little Rock", "Fort Smith", "Fayetteville"],
- "California": ["Los Angeles", "San Francisco", "San Diego", "San Jose", "Sacramento", "Oakland", "Fresno", "Long Beach", "Anaheim", "Bakersfield"],
- "Colorado": ["Denver", "Colorado Springs", "Aurora", "Boulder", "Fort Collins"],
- "Connecticut": ["Hartford", "New Haven", "Stamford", "Bridgeport"],
- "Delaware": ["Wilmington", "Dover", "Newark"],
- "Florida": ["Miami", "Orlando", "Tampa", "Jacksonville", "Fort Lauderdale", "West Palm Beach"],
- "Georgia": ["Atlanta", "Savannah", "Augusta", "Columbus", "Macon"],
- "Hawaii": ["Honolulu", "Hilo", "Kailua"],
- "Idaho": ["Boise", "Meridian", "Nampa"],
- "Illinois": ["Chicago", "Aurora", "Naperville", "Rockford", "Joliet"],
- "Indiana": ["Indianapolis", "Fort Wayne", "Evansville", "South Bend"],
- "Iowa": ["Des Moines", "Cedar Rapids", "Davenport"],
- "Kansas": ["Wichita", "Overland Park", "Kansas City", "Topeka"],
- "Kentucky": ["Louisville", "Lexington", "Bowling Green"],
- "Louisiana": ["New Orleans", "Baton Rouge", "Shreveport", "Lafayette"],
- "Maine": ["Portland", "Lewiston", "Bangor"],
- "Maryland": ["Baltimore", "Columbia", "Germantown", "Silver Spring"],
- "Massachusetts": ["Boston", "Worcester", "Springfield", "Cambridge", "Lowell"],
- "Michigan": ["Detroit", "Grand Rapids", "Warren", "Sterling Heights", "Ann Arbor"],
- "Minnesota": ["Minneapolis", "St. Paul", "Rochester", "Duluth"],
- "Mississippi": ["Jackson", "Gulfport", "Southaven"],
- "Missouri": ["Kansas City", "St. Louis", "Springfield", "Columbia"],
- "Montana": ["Billings", "Missoula", "Great Falls"],
- "Nebraska": ["Omaha", "Lincoln", "Bellevue"],
- "Nevada": ["Las Vegas", "Henderson", "Reno", "North Las Vegas"],
- "New Hampshire": ["Manchester", "Nashua", "Concord"],
- "New Jersey": ["Newark", "Jersey City", "Paterson", "Elizabeth", "Edison"],
- "New Mexico": ["Albuquerque", "Las Cruces", "Rio Rancho", "Santa Fe"],
- "New York": ["New York City", "Buffalo", "Rochester", "Yonkers", "Syracuse", "Albany"],
- "North Carolina": ["Charlotte", "Raleigh", "Greensboro", "Durham", "Winston-Salem"],
- "North Dakota": ["Fargo", "Bismarck", "Grand Forks"],
- "Ohio": ["Columbus", "Cleveland", "Cincinnati", "Toledo", "Akron"],
- "Oklahoma": ["Oklahoma City", "Tulsa", "Norman"],
- "Oregon": ["Portland", "Salem", "Eugene", "Gresham"],
- "Pennsylvania": ["Philadelphia", "Pittsburgh", "Allentown", "Erie", "Reading"],
- "Rhode Island": ["Providence", "Warwick", "Cranston"],
- "South Carolina": ["Charleston", "Columbia", "North Charleston", "Mount Pleasant"],
- "South Dakota": ["Sioux Falls", "Rapid City", "Aberdeen"],
- "Tennessee": ["Nashville", "Memphis", "Knoxville", "Chattanooga"],
- "Texas": ["Houston", "San Antonio", "Dallas", "Austin", "Fort Worth", "El Paso", "Arlington", "Corpus Christi"],
- "Utah": ["Salt Lake City", "West Valley City", "Provo", "West Jordan"],
- "Vermont": ["Burlington", "South Burlington", "Rutland"],
- "Virginia": ["Virginia Beach", "Norfolk", "Chesapeake", "Richmond", "Newport News"],
- "Washington": ["Seattle", "Spokane", "Tacoma", "Vancouver", "Bellevue"],
- "West Virginia": ["Charleston", "Huntington", "Morgantown"],
- "Wisconsin": ["Milwaukee", "Madison", "Green Bay", "Kenosha"],
- "Wyoming": ["Cheyenne", "Casper", "Laramie"]
- };
-
- // Submit vendor application - UPDATED
- const submitApplicationMutation = useMutation({
- mutationFn: async () => {
- // Generate vendor number
- const vendorNumber = `VN-${Math.floor(1000 + Math.random() * 9000)}`;
-
- // Build coverage regions from selected cities
- const coverageRegionsList = [];
- Object.keys(formData.selected_cities).forEach(state => {
- formData.selected_cities[state].forEach(city => {
- coverageRegionsList.push(`${city}, ${state}`);
- });
- });
-
- // Create vendor record
- const vendor = await base44.entities.Vendor.create({
- vendor_number: vendorNumber,
- legal_name: formData.legal_name,
- doing_business_as: formData.dba,
- tax_id: formData.tax_id,
- business_type: formData.business_type,
- primary_contact_name: formData.primary_contact_name,
- primary_contact_email: formData.primary_contact_email,
- primary_contact_phone: formData.primary_contact_phone,
- // Updated logic for billing_address and service_address based on new flow
- service_address: formData.service_address,
- billing_address: formData.same_as_billing ? formData.service_address : formData.billing_address,
- coverage_regions: coverageRegionsList,
- w9_document: formData.w9_url,
- coi_document: formData.coi_url,
- insurance_certificate: formData.coi_url,
- approval_status: "pending",
- is_active: false,
- // Updated contract note to reflect review not upload
- notes: `Total Employees: ${formData.total_employees}, Software: ${formData.software_name || formData.software_type}, SOS: ${formData.sos_url ? 'Verified' : 'Pending'}, Contract: ${formData.contract_acknowledged ? 'Acknowledged' : 'Not Acknowledged'}. Contract Review Notes: ${formData.contract_review_notes}. NDA Signed: ${formData.nda_acknowledged ? 'Yes' : 'No'}`
- });
-
- // Create rate proposals with location-specific rates
- const vendorFee = invite?.vendor_admin_fee || 12;
-
- await Promise.all(
- formData.rate_proposals
- .filter(rate => rate.is_active)
- .map(rate =>
- base44.entities.VendorRate.create({
- vendor_id: vendor.id,
- vendor_name: formData.legal_name,
- category: rate.category,
- role_name: rate.role_name,
- employee_wage: rate.employee_wage,
- markup_percentage: rate.markup_percentage,
- vendor_fee_percentage: vendorFee,
- client_rate: rate.client_rate,
- is_active: true,
- ai_analysis: rate.ai_analysis,
- is_custom: rate.is_custom,
- notes: rate.location_rates ? JSON.stringify(rate.location_rates) : null
- })
- )
- );
-
- // Update invite status if exists
- if (invite) {
- await base44.entities.VendorInvite.update(invite.id, {
- invite_status: "completed",
- vendor_id: vendor.id,
- invite_accepted_date: new Date().toISOString()
- });
- }
-
- // Send confirmation email
- await base44.integrations.Core.SendEmail({
- from_name: "KROW Platform",
- to: formData.primary_contact_email,
- subject: "Vendor Application Received - Under Review",
- body: `
-
- `
- });
-
- return vendor;
- },
- onSuccess: (vendor) => {
- toast({
- title: "Application Submitted!",
- description: "You'll hear from us within 2-3 business days",
- });
- navigate(createPageUrl("VendorManagement"));
- },
- onError: (error) => {
- toast({
- title: "Submission Failed",
- description: error.message,
- variant: "destructive"
- });
- }
- });
-
- const handleNext = () => {
- // Step 0: Welcome (no validation, just go to next step)
- if (currentStep === 0) {
- setCurrentStep(1);
- return;
- }
-
- // Step 1: NDA
- if (currentStep === 1) {
- if (!formData.nda_acknowledged) {
- toast({
- title: "NDA Required",
- description: "You must sign and accept the NDA before proceeding",
- variant: "destructive"
- });
- return;
- }
- }
-
- // Step 2: Foodbuy Contract
- if (currentStep === 2) {
- if (!formData.contract_acknowledged || !formData.contract_va_fee_acknowledged) {
- toast({
- title: "Contract Review Required",
- description: "Please acknowledge all terms to proceed",
- variant: "destructive"
- });
- return;
- }
- }
-
- // Step 3: Business Identity
- if (currentStep === 3) {
- if (!formData.legal_name || !formData.tax_id || !formData.business_type ||
- !formData.primary_contact_name || !formData.primary_contact_email ||
- !formData.service_address || !formData.total_employees ||
- (formData.has_software === "yes" && (!formData.software_type || !formData.software_name))) {
- toast({
- title: "Missing Information",
- description: "Please fill in all required fields",
- variant: "destructive"
- });
- return;
- }
- }
-
- // Step 4: Documents
- if (currentStep === 4) {
- const isSosValidated = (docValidation.sos?.autoVerified && docValidation.sos.isRegistered && (docValidation.sos.registrationStatus === 'Active' || docValidation.sos.registrationStatus === 'Good Standing')) || (docValidation.sos && docValidation.sos.isValid);
-
- if (!formData.w9_url || !formData.coi_url || !isSosValidated) {
- toast({
- title: "Missing Documents",
- description: "Please upload W-9, COI, and verify/upload Secretary of State certificate",
- variant: "destructive"
- });
- return;
- }
-
- // NEW: Validate compliance attestations
- if (!formData.background_check_attestation || !formData.i9_compliance_attestation || !formData.legal_compliance_attestation) {
- toast({
- title: "Compliance Attestation Required",
- description: "Please confirm all compliance attestations to proceed",
- variant: "destructive"
- });
- return;
- }
- }
-
- // Step 5: Service Coverage
- if (currentStep === 5) {
- const totalCities = Object.values(formData.selected_cities).reduce((sum, cities) => sum + cities.length, 0);
- if (totalCities === 0) {
- toast({
- title: "No Coverage Selected",
- description: "Please select at least one city/location you can service",
- variant: "destructive"
- });
- return;
- }
- }
-
- // Step 6: Rate Proposals
- if (currentStep === 6) {
- const activeRates = formData.rate_proposals.filter(rate => rate.is_active);
- if (activeRates.length === 0) {
- toast({
- title: "No Active Rate Proposals",
- description: "Please activate at least one rate proposal.",
- variant: "destructive"
- });
- return;
- }
-
- const hasInvalidRates = activeRates.some(rate =>
- !rate.role_name || !rate.category || rate.employee_wage <= 0 || rate.markup_percentage <= 0 || rate.client_rate <= 0
- );
- if (hasInvalidRates) {
- toast({
- title: "Incomplete Rate Proposals",
- description: "Please ensure all active rate proposals have valid employee wages and markups.",
- variant: "destructive"
- });
- return;
- }
- }
-
-
- if (currentStep < steps.length - 1) {
- setCurrentStep(prev => prev + 1);
- }
- };
-
- const handleBack = () => {
- if (currentStep > 0) {
- setCurrentStep(prev => prev - 1);
- }
- };
-
- const handleSubmit = () => {
- submitApplicationMutation.mutate();
- };
-
- // Update handleSignNDA to handle signature data from DocumentViewer
- const handleSignNDA = (acknowledgmentData) => {
- const now = new Date();
- setFormData(prev => ({
- ...prev,
- nda_acknowledged: true,
- nda_signed_by: acknowledgmentData.signerName || invite?.primary_contact_name || prev.primary_contact_name || "Vendor",
- nda_signature_date: now.toLocaleDateString(),
- nda_signature_time: now.toLocaleTimeString(),
- nda_signature_image: acknowledgmentData.signature || "" // Store the signature image
- }));
- toast({
- title: "✅ NDA Signed",
- description: `Signed on ${now.toLocaleString()}`,
- });
- };
-
- return (
-
- );
-}
diff --git a/frontend-web/src/pages/StaffAvailability.jsx b/frontend-web/src/pages/StaffAvailability.jsx
deleted file mode 100644
index d4e7da39..00000000
--- a/frontend-web/src/pages/StaffAvailability.jsx
+++ /dev/null
@@ -1,469 +0,0 @@
-import React, { useState, useMemo } from "react";
-import { base44 } from "@/api/base44Client";
-import { useQuery } from "@tanstack/react-query";
-import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
-import { Button } from "@/components/ui/button";
-import { Input } from "@/components/ui/input";
-import { Badge } from "@/components/ui/badge";
-import { Avatar, AvatarFallback } from "@/components/ui/avatar";
-import { Users, Calendar, Clock, TrendingUp, TrendingDown, AlertCircle, CheckCircle, XCircle, Search, Filter, List, LayoutGrid, ChevronLeft, ChevronRight } from "lucide-react";
-import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
-import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
-import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
-import { format } from "date-fns";
-
-export default function StaffAvailability() {
- const [searchTerm, setSearchTerm] = useState("");
- const [filterStatus, setFilterStatus] = useState("all");
- const [filterUtilization, setFilterUtilization] = useState("all");
- const [viewMode, setViewMode] = useState("cards");
- const [currentPage, setCurrentPage] = useState(1);
- const [itemsPerPage, setItemsPerPage] = useState(50);
- const [sortBy, setSortBy] = useState("need_work_index");
-
- const { data: allStaff = [] } = useQuery({
- queryKey: ['staff-availability-all'],
- queryFn: () => base44.entities.Staff.list(),
- initialData: [],
- });
-
- const { data: availabilityData = [] } = useQuery({
- queryKey: ['worker-availability'],
- queryFn: () => base44.entities.WorkerAvailability.list(),
- initialData: [],
- });
-
- const { data: events = [] } = useQuery({
- queryKey: ['events-for-availability'],
- queryFn: () => base44.entities.Event.list(),
- initialData: [],
- });
-
- // Calculate metrics
- const metrics = useMemo(() => {
- const needsWork = availabilityData.filter(w => w.need_work_index >= 60).length;
- const fullyBooked = availabilityData.filter(w => w.utilization_percentage >= 90).length;
- const hasUtilization = availabilityData.filter(w => w.utilization_percentage > 0 && w.utilization_percentage < 90).length;
- const onTimeOff = availabilityData.filter(w => w.availability_status === 'BLOCKED').length;
-
- return { needsWork, fullyBooked, hasUtilization, onTimeOff };
- }, [availabilityData]);
-
- // Filter and search logic
- const filteredAvailability = useMemo(() => {
- let filtered = availabilityData;
-
- // Search
- if (searchTerm) {
- filtered = filtered.filter(a =>
- a.staff_name?.toLowerCase().includes(searchTerm.toLowerCase())
- );
- }
-
- // Status filter
- if (filterStatus !== "all") {
- filtered = filtered.filter(a => a.availability_status === filterStatus);
- }
-
- // Utilization filter
- if (filterUtilization === "underutilized") {
- filtered = filtered.filter(a => a.utilization_percentage < 50);
- } else if (filterUtilization === "optimal") {
- filtered = filtered.filter(a => a.utilization_percentage >= 50 && a.utilization_percentage < 100);
- } else if (filterUtilization === "full") {
- filtered = filtered.filter(a => a.utilization_percentage >= 100);
- }
-
- // Sort
- if (sortBy === "need_work_index") {
- filtered.sort((a, b) => (b.need_work_index || 0) - (a.need_work_index || 0));
- } else if (sortBy === "utilization") {
- filtered.sort((a, b) => (a.utilization_percentage || 0) - (b.utilization_percentage || 0));
- } else if (sortBy === "name") {
- filtered.sort((a, b) => (a.staff_name || "").localeCompare(b.staff_name || ""));
- } else if (sortBy === "availability_score") {
- filtered.sort((a, b) => (b.predicted_availability_score || 0) - (a.predicted_availability_score || 0));
- }
-
- return filtered;
- }, [availabilityData, searchTerm, filterStatus, filterUtilization, sortBy]);
-
- // Pagination
- const totalPages = Math.ceil(filteredAvailability.length / itemsPerPage);
- const paginatedData = filteredAvailability.slice(
- (currentPage - 1) * itemsPerPage,
- currentPage * itemsPerPage
- );
-
- React.useEffect(() => {
- setCurrentPage(1);
- }, [searchTerm, filterStatus, filterUtilization, sortBy]);
-
- const getUtilizationColor = (percentage) => {
- if (percentage === 0) return "text-slate-400";
- if (percentage < 50) return "text-red-600";
- if (percentage < 80) return "text-amber-600";
- return "text-green-600";
- };
-
- const getStatusBadge = (worker) => {
- const statusConfig = {
- 'CONFIRMED_AVAILABLE': { bg: 'bg-green-100', text: 'text-green-800', label: 'Available' },
- 'UNKNOWN': { bg: 'bg-gray-100', text: 'text-gray-800', label: 'Unknown' },
- 'BLOCKED': { bg: 'bg-red-100', text: 'text-red-800', label: 'Unavailable' },
- };
- const config = statusConfig[worker.availability_status] || statusConfig['UNKNOWN'];
- return
- );
-}
\ No newline at end of file
diff --git a/frontend-web/src/pages/StaffDirectory.jsx b/frontend-web/src/pages/StaffDirectory.jsx
deleted file mode 100644
index 29fda88f..00000000
--- a/frontend-web/src/pages/StaffDirectory.jsx
+++ /dev/null
@@ -1,307 +0,0 @@
-import React, { useState } from "react";
-import { base44 } from "@/api/base44Client";
-import { useQuery } from "@tanstack/react-query";
-import { Link } from "react-router-dom";
-import { createPageUrl } from "@/utils";
-import { Button } from "@/components/ui/button";
-import { Card, CardContent } from "@/components/ui/card";
-import { Badge } from "@/components/ui/badge";
-import { UserPlus, Users, LayoutGrid, List as ListIcon, Phone, MapPin, Calendar, Star } from "lucide-react";
-import FilterBar from "@/components/staff/FilterBar";
-import StaffCard from "@/components/staff/StaffCard";
-import EmployeeCard from "@/components/staff/EmployeeCard";
-import PageHeader from "@/components/common/PageHeader";
-
-export default function StaffDirectory() {
- const [searchTerm, setSearchTerm] = useState("");
- const [departmentFilter, setDepartmentFilter] = useState("all");
- const [locationFilter, setLocationFilter] = useState("all");
- const [viewMode, setViewMode] = useState("grid"); // "grid" or "list"
-
- const { data: user } = useQuery({
- queryKey: ['current-user'],
- queryFn: () => base44.auth.me(),
- });
-
- const { data: staff, isLoading } = useQuery({
- queryKey: ['staff'],
- queryFn: () => base44.entities.Staff.list('-created_date'),
- initialData: [],
- });
-
- const { data: events } = useQuery({
- queryKey: ['events-for-staff-filter'],
- queryFn: () => base44.entities.Event.list(),
- initialData: [],
- enabled: !!user
- });
-
- const visibleStaff = React.useMemo(() => {
- const userRole = user?.user_role || user?.role;
-
- if (['admin', 'procurement'].includes(userRole)) {
- return staff;
- }
-
- if (['operator', 'sector'].includes(userRole)) {
- return staff;
- }
-
- if (userRole === 'vendor') {
- return staff.filter(s =>
- s.vendor_id === user?.id ||
- s.vendor_name === user?.company_name ||
- s.created_by === user?.email
- );
- }
-
- if (userRole === 'client') {
- const clientEvents = events.filter(e =>
- e.client_email === user?.email ||
- e.business_name === user?.company_name ||
- e.created_by === user?.email
- );
-
- const assignedStaffIds = new Set();
- clientEvents.forEach(event => {
- if (event.assigned_staff) {
- event.assigned_staff.forEach(assignment => {
- if (assignment.staff_id) {
- assignedStaffIds.add(assignment.staff_id);
- }
- });
- }
- });
-
- return staff.filter(s => assignedStaffIds.has(s.id));
- }
-
- if (userRole === 'workforce') {
- return staff;
- }
-
- return staff;
- }, [staff, user, events]);
-
- const uniqueDepartments = [...new Set(visibleStaff.map(s => s.department).filter(Boolean))];
- const uniqueLocations = [...new Set(visibleStaff.map(s => s.hub_location).filter(Boolean))];
-
- const filteredStaff = visibleStaff.filter(member => {
- const matchesSearch = !searchTerm ||
- member.employee_name?.toLowerCase().includes(searchTerm.toLowerCase()) ||
- member.position?.toLowerCase().includes(searchTerm.toLowerCase()) ||
- member.manager?.toLowerCase().includes(searchTerm.toLowerCase());
-
- const matchesDepartment = departmentFilter === "all" || member.department === departmentFilter;
- const matchesLocation = locationFilter === "all" || member.hub_location === locationFilter;
-
- return matchesSearch && matchesDepartment && matchesLocation;
- });
-
- const canAddStaff = ['admin', 'procurement', 'operator', 'sector', 'vendor'].includes(user?.user_role || user?.role);
-
- const getPageTitle = () => {
- const userRole = user?.user_role || user?.role;
- if (userRole === 'vendor') return "My Staff Directory";
- if (userRole === 'client') return "Event Staff Directory";
- if (userRole === 'workforce') return "Team Directory";
- return "Staff Directory";
- };
-
- const getPageSubtitle = () => {
- const userRole = user?.user_role || user?.role;
- if (userRole === 'vendor') return `${filteredStaff.length} of your staff members`;
- if (userRole === 'client') return `${filteredStaff.length} staff assigned to your events`;
- if (userRole === 'workforce') return `${filteredStaff.length} team members`;
- return `${filteredStaff.length} ${filteredStaff.length === 1 ? 'member' : 'members'} found`;
- };
-
- const getCoverageColor = (percentage) => {
- if (!percentage) return "bg-red-100 text-red-700";
- if (percentage >= 90) return "bg-green-100 text-green-700";
- if (percentage >= 50) return "bg-yellow-100 text-yellow-700";
- return "bg-red-100 text-red-700";
- };
-
- return (
-
- );
-}
\ No newline at end of file
diff --git a/frontend-web/src/pages/StaffOnboarding.jsx b/frontend-web/src/pages/StaffOnboarding.jsx
deleted file mode 100644
index 15909b6b..00000000
--- a/frontend-web/src/pages/StaffOnboarding.jsx
+++ /dev/null
@@ -1,197 +0,0 @@
-import React, { useState } from "react";
-import { base44 } from "@/api/base44Client";
-import { useMutation, useQueryClient, useQuery } from "@tanstack/react-query";
-import { useNavigate } from "react-router-dom";
-import { createPageUrl } from "@/utils";
-import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
-import { Button } from "@/components/ui/button";
-import { CheckCircle, Circle } from "lucide-react";
-import { useToast } from "@/components/ui/use-toast";
-import ProfileSetupStep from "@/components/onboarding/ProfileSetupStep";
-import DocumentUploadStep from "@/components/onboarding/DocumentUploadStep";
-import TrainingStep from "@/components/onboarding/TrainingStep";
-import CompletionStep from "@/components/onboarding/CompletionStep";
-
-const steps = [
- { id: 1, name: "Profile Setup", description: "Basic information" },
- { id: 2, name: "Documents", description: "Upload required documents" },
- { id: 3, name: "Training", description: "Complete compliance training" },
- { id: 4, name: "Complete", description: "Finish onboarding" },
-];
-
-export default function StaffOnboarding() {
- const navigate = useNavigate();
- const queryClient = useQueryClient();
- const { toast } = useToast();
- const [currentStep, setCurrentStep] = useState(1);
- const [onboardingData, setOnboardingData] = useState({
- profile: {},
- documents: [],
- training: { completed: [] },
- });
-
- const { data: currentUser } = useQuery({
- queryKey: ['current-user-onboarding'],
- queryFn: () => base44.auth.me(),
- });
-
- const createStaffMutation = useMutation({
- mutationFn: (staffData) => base44.entities.Staff.create(staffData),
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ['staff'] });
- toast({
- title: "✅ Onboarding Complete",
- description: "Welcome to KROW! Your profile is now active.",
- });
- navigate(createPageUrl("WorkforceDashboard"));
- },
- onError: (error) => {
- toast({
- title: "⌠Onboarding Failed",
- description: error.message,
- variant: "destructive",
- });
- },
- });
-
- const handleNext = (stepData) => {
- setOnboardingData(prev => ({
- ...prev,
- [stepData.type]: stepData.data,
- }));
-
- if (currentStep < steps.length) {
- setCurrentStep(currentStep + 1);
- }
- };
-
- const handleBack = () => {
- if (currentStep > 1) {
- setCurrentStep(currentStep - 1);
- }
- };
-
- const handleComplete = () => {
- const staffData = {
- employee_name: onboardingData.profile.full_name,
- email: onboardingData.profile.email || currentUser?.email,
- phone: onboardingData.profile.phone,
- address: onboardingData.profile.address,
- city: onboardingData.profile.city,
- position: onboardingData.profile.position,
- department: onboardingData.profile.department,
- hub_location: onboardingData.profile.hub_location,
- employment_type: onboardingData.profile.employment_type,
- english: onboardingData.profile.english_level,
- certifications: onboardingData.documents.filter(d => d.type === 'certification').map(d => ({
- name: d.name,
- issued_date: d.issued_date,
- expiry_date: d.expiry_date,
- document_url: d.url,
- })),
- background_check_status: onboardingData.documents.some(d => d.type === 'background_check') ? 'pending' : 'not_required',
- notes: `Onboarding completed: ${new Date().toISOString()}. Training modules completed: ${onboardingData.training.completed.length}`,
- };
-
- createStaffMutation.mutate(staffData);
- };
-
- const renderStep = () => {
- switch (currentStep) {
- case 1:
- return (
-
- );
- default:
- return null;
- }
- };
-
- return (
-
-
- {/* Header */}
-
-
- Welcome to KROW! 👋
-
-
- Let's get you set up in just a few steps
-
-
-
- {/* Progress Steps */}
-
-
- {steps.map((step, idx) => (
-
-
-
step.id
- ? "bg-green-500 text-white"
- : currentStep === step.id
- ? "bg-[#0A39DF] text-white"
- : "bg-slate-200 text-slate-400"
- }`}>
- {currentStep > step.id ? (
-
- ) : (
- {step.id}
- )}
-
-
= step.id ? "text-slate-900" : "text-slate-400"
- }`}>
- {step.name}
-
-
{step.description}
-
- {idx < steps.length - 1 && (
- step.id ? "bg-green-500" : "bg-slate-200"
- }`} />
- )}
-
- ))}
-
-
-
- {/* Step Content */}
-
-
- {renderStep()}
-
-
-
-
- );
-}
\ No newline at end of file
diff --git a/frontend-web/src/pages/Support.jsx b/frontend-web/src/pages/Support.jsx
deleted file mode 100644
index e42918e2..00000000
--- a/frontend-web/src/pages/Support.jsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import React from "react";
-import { HelpCircle } from "lucide-react";
-
-export default function Support() {
- return (
-
-
-
-
-
Support
-
-
-
-
Support center coming soon
-
-
-
- );
-}
\ No newline at end of file
diff --git a/frontend-web/src/pages/TaskBoard.jsx b/frontend-web/src/pages/TaskBoard.jsx
deleted file mode 100644
index 1ddfeeb4..00000000
--- a/frontend-web/src/pages/TaskBoard.jsx
+++ /dev/null
@@ -1,650 +0,0 @@
-import React, { useState, useMemo } from "react";
-import { base44 } from "@/api/base44Client";
-import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
-import { Card, CardContent } from "@/components/ui/card";
-import { Button } from "@/components/ui/button";
-import { Badge } from "@/components/ui/badge";
-import { Avatar, AvatarFallback } from "@/components/ui/avatar";
-import { Input } from "@/components/ui/input";
-import { Label } from "@/components/ui/label";
-import { Textarea } from "@/components/ui/textarea";
-import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
-import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog";
-import { DragDropContext, Draggable } from "@hello-pangea/dnd";
-import { Link2, Plus, Users, Search, UserCircle, Filter, ArrowUpDown, EyeOff, Grid3x3, MoreVertical, Pin, Ruler, Palette } from "lucide-react";
-import {
- DropdownMenu,
- DropdownMenuContent,
- DropdownMenuItem,
- DropdownMenuTrigger,
- DropdownMenuSeparator,
- DropdownMenuLabel,
-} from "@/components/ui/dropdown-menu";
-import TaskCard from "@/components/tasks/TaskCard";
-import TaskColumn from "@/components/tasks/TaskColumn";
-import TaskDetailModal from "@/components/tasks/TaskDetailModal";
-import { useToast } from "@/components/ui/use-toast";
-
-export default function TaskBoard() {
- const { toast } = useToast();
- const queryClient = useQueryClient();
- const [createDialog, setCreateDialog] = useState(false);
- const [selectedTask, setSelectedTask] = useState(null);
- const [selectedStatus, setSelectedStatus] = useState("pending");
- const [newTask, setNewTask] = useState({
- task_name: "",
- description: "",
- priority: "normal",
- due_date: "",
- progress: 0,
- assigned_members: []
- });
- const [selectedMembers, setSelectedMembers] = useState([]);
- const [searchQuery, setSearchQuery] = useState("");
- const [filterPerson, setFilterPerson] = useState("all");
- const [filterPriority, setFilterPriority] = useState("all");
- const [sortBy, setSortBy] = useState("due_date");
- const [showCompleted, setShowCompleted] = useState(true);
- const [groupBy, setGroupBy] = useState("status");
- const [pinnedColumns, setPinnedColumns] = useState([]);
- const [itemHeight, setItemHeight] = useState("normal");
- const [conditionalColoring, setConditionalColoring] = useState(true);
-
- const { data: user } = useQuery({
- queryKey: ['current-user-taskboard'],
- queryFn: () => base44.auth.me(),
- });
-
- const { data: teams = [] } = useQuery({
- queryKey: ['teams'],
- queryFn: () => base44.entities.Team.list(),
- initialData: [],
- });
-
- const { data: teamMembers = [] } = useQuery({
- queryKey: ['team-members'],
- queryFn: () => base44.entities.TeamMember.list(),
- initialData: [],
- });
-
- const { data: tasks = [] } = useQuery({
- queryKey: ['tasks'],
- queryFn: () => base44.entities.Task.list(),
- initialData: [],
- });
-
- const userTeam = teams.find(t => t.owner_id === user?.id) || teams[0];
- let teamTasks = tasks.filter(t => t.team_id === userTeam?.id);
-
- // Apply filters
- if (searchQuery) {
- teamTasks = teamTasks.filter(t =>
- t.task_name?.toLowerCase().includes(searchQuery.toLowerCase()) ||
- t.description?.toLowerCase().includes(searchQuery.toLowerCase())
- );
- }
-
- if (filterPerson !== "all") {
- teamTasks = teamTasks.filter(t =>
- t.assigned_members?.some(m => m.member_id === filterPerson)
- );
- }
-
- if (filterPriority !== "all") {
- teamTasks = teamTasks.filter(t => t.priority === filterPriority);
- }
-
- if (!showCompleted) {
- teamTasks = teamTasks.filter(t => t.status !== "completed");
- }
-
- const currentTeamMembers = teamMembers.filter(m => m.team_id === userTeam?.id);
-
- const leadMembers = currentTeamMembers.filter(m => m.role === 'admin' || m.role === 'manager');
- const regularMembers = currentTeamMembers.filter(m => m.role === 'member');
-
- // Get unique departments from team members
- const departments = [...new Set(currentTeamMembers.map(m => m.department).filter(Boolean))];
-
- const sortTasks = (tasks) => {
- return [...tasks].sort((a, b) => {
- switch (sortBy) {
- case "due_date":
- return new Date(a.due_date || '9999-12-31') - new Date(b.due_date || '9999-12-31');
- case "priority":
- const priorityOrder = { high: 0, normal: 1, low: 2 };
- return (priorityOrder[a.priority] || 1) - (priorityOrder[b.priority] || 1);
- case "created_date":
- return new Date(b.created_date || 0) - new Date(a.created_date || 0);
- case "task_name":
- return (a.task_name || '').localeCompare(b.task_name || '');
- default:
- return (a.order_index || 0) - (b.order_index || 0);
- }
- });
- };
-
- const tasksByStatus = useMemo(() => ({
- pending: sortTasks(teamTasks.filter(t => t.status === 'pending')),
- in_progress: sortTasks(teamTasks.filter(t => t.status === 'in_progress')),
- on_hold: sortTasks(teamTasks.filter(t => t.status === 'on_hold')),
- completed: sortTasks(teamTasks.filter(t => t.status === 'completed')),
- }), [teamTasks, sortBy]);
-
- const overallProgress = useMemo(() => {
- if (teamTasks.length === 0) return 0;
- const totalProgress = teamTasks.reduce((sum, t) => sum + (t.progress || 0), 0);
- return Math.round(totalProgress / teamTasks.length);
- }, [teamTasks]);
-
- const createTaskMutation = useMutation({
- mutationFn: (taskData) => base44.entities.Task.create(taskData),
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ['tasks'] });
- setCreateDialog(false);
- setNewTask({
- task_name: "",
- description: "",
- priority: "normal",
- due_date: "",
- progress: 0,
- assigned_members: []
- });
- setSelectedMembers([]);
- toast({
- title: "✅ Task Created",
- description: "New task added to the board",
- });
- },
- });
-
- const updateTaskMutation = useMutation({
- mutationFn: ({ id, data }) => base44.entities.Task.update(id, data),
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ['tasks'] });
- },
- });
-
- const handleDragEnd = (result) => {
- if (!result.destination) return;
-
- const { source, destination, draggableId } = result;
-
- if (source.droppableId === destination.droppableId && source.index === destination.index) {
- return;
- }
-
- const task = teamTasks.find(t => t.id === draggableId);
- if (!task) return;
-
- const newStatus = destination.droppableId;
- updateTaskMutation.mutate({
- id: task.id,
- data: {
- ...task,
- status: newStatus,
- order_index: destination.index
- }
- });
- };
-
- const handleCreateTask = () => {
- if (!newTask.task_name.trim()) {
- toast({
- title: "Task name required",
- variant: "destructive",
- });
- return;
- }
-
- createTaskMutation.mutate({
- ...newTask,
- team_id: userTeam?.id,
- status: selectedStatus,
- order_index: tasksByStatus[selectedStatus]?.length || 0,
- assigned_members: selectedMembers.map(m => ({
- member_id: m.id,
- member_name: m.member_name,
- avatar_url: m.avatar_url
- })),
- assigned_department: selectedMembers.length > 0 && selectedMembers[0].department ? selectedMembers[0].department : null
- });
- };
-
- return (
-
-
- {/* Header */}
-
- {/* Toolbar */}
-
-
-
- setSearchQuery(e.target.value)}
- className="pl-9 h-9"
- />
-
-
-
-
-
-
-
- setFilterPerson("all")}>
- All People
-
-
- {currentTeamMembers.map((member) => (
- setFilterPerson(member.id)}
- >
- {member.member_name}
-
- ))}
-
-
-
-
-
-
-
-
- Priority
- setFilterPriority("all")}>All
- setFilterPriority("high")}>High
- setFilterPriority("normal")}>Normal
- setFilterPriority("low")}>Low
-
-
-
-
-
-
-
-
- setSortBy("due_date")}>Due Date
- setSortBy("priority")}>Priority
- setSortBy("created_date")}>Created Date
- setSortBy("task_name")}>Name
-
-
-
-
-
-
-
-
-
-
- setGroupBy("status")}>Status
- setGroupBy("priority")}>Priority
- setGroupBy("assigned")}>Assigned To
-
-
-
-
-
-
-
-
- setPinnedColumns(pinnedColumns.length > 0 ? [] : ['pending'])}>
-
- Pin columns
-
-
- Item height
- setItemHeight("compact")}>
-
- Compact
-
- setItemHeight("normal")}>
-
- Normal
-
- setItemHeight("comfortable")}>
-
- Comfortable
-
-
- setConditionalColoring(!conditionalColoring)}>
-
- Conditional coloring
-
-
-
-
-
-
-
-
Task Board
-
-
-
Lead
-
- {leadMembers.slice(0, 3).map((member, idx) => (
-
-
-
- ))}
- {leadMembers.length > 3 && (
-
- +{leadMembers.length - 3}
-
- )}
-
-
-
-
-
Team
-
- {regularMembers.slice(0, 3).map((member, idx) => (
-
-
-
- ))}
- {regularMembers.length > 3 && (
-
- +{regularMembers.length - 3}
-
- )}
-
-
-
-
-
-
-
-
-
-
-
- {/* Overall Progress */}
-
-
-
- {/* Kanban Board */}
-
-
- {['pending', 'in_progress', 'on_hold', 'completed'].map((status) => (
- {
- setSelectedStatus(status);
- setCreateDialog(true);
- }}
- >
- {tasksByStatus[status].map((task, index) => (
-
- {(provided) => (
- setSelectedTask(task)}
- itemHeight={itemHeight}
- conditionalColoring={conditionalColoring}
- />
- )}
-
- ))}
-
- ))}
-
-
-
- {teamTasks.length === 0 && (
-
-
-
No tasks yet
-
Create your first task to get started
-
-
- )}
-
-
- {/* Create Task Dialog */}
-
-
- {/* Task Detail Modal with Comments */}
-
setSelectedTask(null)}
- />
-
- );
-}
\ No newline at end of file
diff --git a/frontend-web/src/pages/TeamDetails.jsx b/frontend-web/src/pages/TeamDetails.jsx
deleted file mode 100644
index ae77337a..00000000
--- a/frontend-web/src/pages/TeamDetails.jsx
+++ /dev/null
@@ -1,1249 +0,0 @@
-import React, { useState } from "react";
-import { base44 } from "@/api/base44Client";
-import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
-import { useNavigate } from "react-router-dom";
-import { createPageUrl } from "@/utils";
-import { Button } from "@/components/ui/button";
-import { Card, CardContent } from "@/components/ui/card";
-import { Input } from "@/components/ui/input";
-import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
-import { Badge } from "@/components/ui/badge";
-import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
-import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
-import { ArrowLeft, Edit, UserPlus, MapPin, Star, UserX, Search, Mail, Loader2 } from "lucide-react";
-import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog";
-import { Label } from "@/components/ui/label";
-import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
-import { useToast } from "@/components/ui/use-toast";
-
-export default function TeamDetails() {
- const navigate = useNavigate();
- const queryClient = useQueryClient();
- const { toast } = useToast();
- const urlParams = new URLSearchParams(window.location.search);
- const teamId = urlParams.get('id');
-
- const [activeTab, setActiveTab] = useState("details");
- const [memberTab, setMemberTab] = useState("active");
- const [searchTerm, setSearchTerm] = useState("");
- const [showInviteMemberDialog, setShowInviteMemberDialog] = useState(false);
- const [showEditMemberDialog, setShowEditMemberDialog] = useState(false);
- const [showAddHubDialog, setShowAddHubDialog] = useState(false);
- const [editingMember, setEditingMember] = useState(null);
-
- const [inviteData, setInviteData] = useState({
- email: "",
- full_name: "",
- role: "member",
- title: "",
- department: "",
- hub: ""
- });
-
- const [newHub, setNewHub] = useState({
- hub_name: "",
- address: "",
- city: "",
- state: "",
- zip_code: "",
- manager_name: "",
- manager_email: "",
- departments: []
- });
-
- const [showAddDepartmentDialog, setShowAddDepartmentDialog] = useState(false);
- const [selectedHub, setSelectedHub] = useState(null);
- const [newDepartment, setNewDepartment] = useState({
- department_name: "",
- cost_center: "",
- manager_name: ""
- });
-
- const [favoriteSearch, setFavoriteSearch] = useState("");
- const [blockedSearch, setBlockedSearch] = useState("");
- const [showAddFavoriteDialog, setShowAddFavoriteDialog] = useState(false);
- const [showAddBlockedDialog, setShowAddBlockedDialog] = useState(false);
- const [blockReason, setBlockReason] = useState("");
-
- const { data: user } = useQuery({
- queryKey: ['current-user-team-details'],
- queryFn: () => base44.auth.me(),
- });
-
- const { data: team, isLoading } = useQuery({
- queryKey: ['team', teamId],
- queryFn: async () => {
- const allTeams = await base44.entities.Team.list();
- return allTeams.find(t => t.id === teamId);
- },
- enabled: !!teamId,
- });
-
- const { data: members = [] } = useQuery({
- queryKey: ['team-members', teamId],
- queryFn: async () => {
- const allMembers = await base44.entities.TeamMember.list('-created_date');
- return allMembers.filter(m => m.team_id === teamId);
- },
- enabled: !!teamId,
- initialData: [],
- });
-
- const { data: hubs = [] } = useQuery({
- queryKey: ['team-hubs', teamId],
- queryFn: async () => {
- const allHubs = await base44.entities.TeamHub.list('-created_date');
- return allHubs.filter(h => h.team_id === teamId);
- },
- enabled: !!teamId,
- initialData: [],
- });
-
- const { data: allStaff = [] } = useQuery({
- queryKey: ['staff-for-favorites'],
- queryFn: () => base44.entities.Staff.list(),
- enabled: !!teamId,
- initialData: [],
- });
-
- const updateMemberMutation = useMutation({
- mutationFn: ({ id, data }) => base44.entities.TeamMember.update(id, data),
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ['team-members', teamId] });
- setShowEditMemberDialog(false);
- setEditingMember(null);
- toast({
- title: "Member Updated",
- description: "Team member updated successfully",
- });
- },
- });
-
- const inviteMemberMutation = useMutation({
- mutationFn: async (data) => {
- // Generate unique invite code
- const inviteCode = `TEAM-${Math.floor(10000 + Math.random() * 90000)}`;
-
- // Create invite record
- const invite = await base44.entities.TeamMemberInvite.create({
- team_id: teamId,
- team_name: team?.team_name,
- invite_code: inviteCode,
- email: data.email,
- full_name: data.full_name,
- role: data.role,
- invited_by: user?.email || user?.full_name,
- invite_status: "pending",
- invited_date: new Date().toISOString(),
- expires_at: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString() // 7 days
- });
-
- // Send email invitation
- const acceptUrl = `${window.location.origin}${createPageUrl('TeamDetails')}?id=${teamId}&invite=${inviteCode}`;
-
- await base44.integrations.Core.SendEmail({
- from_name: team?.team_name || "Team",
- to: data.email,
- subject: `You're invited to join ${team?.team_name}!`,
- body: `
-
-
-
Team Invitation
-
Join ${team?.team_name}
-
-
-
-
- Hi ${data.full_name || 'there'},
-
-
-
- ${user?.full_name || user?.email} has invited you to join ${team?.team_name} as a ${data.role}.
-
-
- ${data.title ? `
Position: ${data.title}
` : ''}
- ${data.department ? `
Department: ${data.department}
` : ''}
- ${data.hub ? `
Hub: ${data.hub}
` : ''}
-
-
-
-
-
- 📋 Note: This invitation will expire in 7 days.
-
-
-
-
- Your invite code: ${inviteCode}
- Questions? Contact ${user?.email || 'the team admin'}
-
-
-
- `
- });
-
- return invite;
- },
- onSuccess: () => {
- setShowInviteMemberDialog(false);
- setInviteData({
- email: "",
- full_name: "",
- role: "member",
- title: "",
- department: "",
- hub: ""
- });
- toast({
- title: "Invitation Sent",
- description: `Invitation sent to ${inviteData.email}`,
- });
- },
- });
-
- const addHubMutation = useMutation({
- mutationFn: (hubData) => base44.entities.TeamHub.create(hubData),
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ['team-hubs', teamId] });
- queryClient.invalidateQueries({ queryKey: ['team', teamId] });
- setShowAddHubDialog(false);
- setNewHub({
- hub_name: "",
- address: "",
- city: "",
- state: "",
- zip_code: "",
- manager_name: "",
- manager_email: "",
- departments: []
- });
- toast({
- title: "Hub Created",
- description: "Hub created successfully",
- });
- },
- });
-
- const updateTeamMutation = useMutation({
- mutationFn: ({ id, data }) => base44.entities.Team.update(id, data),
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ['team', teamId] });
- toast({
- title: "Updated",
- description: "Team updated successfully",
- });
- },
- });
-
- const addToFavorites = (staff) => {
- const favoriteStaff = team.favorite_staff || [];
- const newFavorite = {
- staff_id: staff.id,
- staff_name: staff.employee_name,
- position: staff.position,
- added_date: new Date().toISOString()
- };
-
- updateTeamMutation.mutate({
- id: teamId,
- data: {
- favorite_staff: [...favoriteStaff, newFavorite],
- favorite_staff_count: favoriteStaff.length + 1
- }
- });
- setShowAddFavoriteDialog(false);
- };
-
- const removeFromFavorites = (staffId) => {
- const favoriteStaff = (team.favorite_staff || []).filter(f => f.staff_id !== staffId);
- updateTeamMutation.mutate({
- id: teamId,
- data: {
- favorite_staff: favoriteStaff,
- favorite_staff_count: favoriteStaff.length
- }
- });
- };
-
- const addToBlocked = (staff) => {
- const blockedStaff = team.blocked_staff || [];
- const newBlocked = {
- staff_id: staff.id,
- staff_name: staff.employee_name,
- reason: blockReason,
- blocked_date: new Date().toISOString()
- };
-
- updateTeamMutation.mutate({
- id: teamId,
- data: {
- blocked_staff: [...blockedStaff, newBlocked],
- blocked_staff_count: blockedStaff.length + 1
- }
- });
- setShowAddBlockedDialog(false);
- setBlockReason("");
- };
-
- const removeFromBlocked = (staffId) => {
- const blockedStaff = (team.blocked_staff || []).filter(b => b.staff_id !== staffId);
- updateTeamMutation.mutate({
- id: teamId,
- data: {
- blocked_staff: blockedStaff,
- blocked_staff_count: blockedStaff.length
- }
- });
- };
-
- const handleEditMember = (member) => {
- setEditingMember(member);
- setShowEditMemberDialog(true);
- };
-
- const handleUpdateMember = () => {
- updateMemberMutation.mutate({
- id: editingMember.id,
- data: editingMember
- });
- };
-
- const handleInviteMember = () => {
- inviteMemberMutation.mutate(inviteData);
- };
-
- const handleAddHub = () => {
- addHubMutation.mutate({
- ...newHub,
- team_id: teamId,
- is_active: true
- });
- };
-
- const activeMembers = members.filter(m => m.is_active);
- const deactivatedMembers = members.filter(m => !m.is_active);
-
- const filteredMembers = (memberTab === "active" ? activeMembers : deactivatedMembers).filter(m =>
- !searchTerm ||
- m.member_name?.toLowerCase().includes(searchTerm.toLowerCase()) ||
- m.email?.toLowerCase().includes(searchTerm.toLowerCase()) ||
- m.title?.toLowerCase().includes(searchTerm.toLowerCase())
- );
-
- if (isLoading) {
- return (
-
-
-
-
Loading team details...
-
-
- );
- }
-
- if (!team) {
- return (
-
-
Team Not Found
-
-
- );
- }
-
- return (
-
-
-
-
-
-
-
-
-
- {team.team_name?.charAt(0) || 'T'}
-
-
-
-
Teams
-
{team.team_name}
-
-
-
-
-
-
-
-
-
-
-
- Details
-
-
- Team members
- {members.length}
-
-
- Hubs
- {hubs.length}
-
-
- Favorite staff
- {team.favorite_staff_count || 0}
-
-
- Blocked staff
- {team.blocked_staff_count || 0}
-
-
-
- {/* Details Tab */}
-
-
- {/* Company Logo */}
-
-
- Company Logo
-
-
-
-
- {team.team_name?.charAt(0) || 'T'}
-
-
-
-
-
-
- {/* Personal Info */}
-
-
- Personal Info
-
-
-
-
{team.full_name || '-'}
-
-
-
-
{team.email || '-'}
-
-
-
-
{team.phone || '-'}
-
-
-
-
-
- {/* Contact Info */}
-
-
- Contact Info
-
-
-
-
{team.address || '-'}
-
-
-
-
{team.city || '-'}
-
-
-
-
{team.zip_code || '-'}
-
- {team.vendor_id && (
-
-
-
{team.vendor_id}
-
- )}
-
-
-
-
-
-
-
-
-
-
- {/* Team Members Tab */}
-
-
-
- {/* Search */}
-
-
-
- setSearchTerm(e.target.value)}
- className="pl-10"
- />
-
-
-
- {/* Active / Deactivated Tabs */}
-
-
-
- Active
- {activeMembers.length}
-
-
- Deactivated
- {deactivatedMembers.length}
-
-
-
-
-
-
-
- #
- Name
- Title
- Role
- Department
- Hub
- Actions
-
-
-
- {filteredMembers.length > 0 ? (
- filteredMembers.map((member, index) => (
-
- {index + 1}
-
-
-
-
-
- {member.member_name?.charAt(0) || '?'}
-
-
-
-
{member.member_name}
-
{member.email}
-
-
-
- {member.title || '-'}
-
-
- {member.role}
-
-
- {member.department || 'No Department'}
- {member.hub || 'No Hub'}
-
-
-
-
- ))
- ) : (
-
-
- No members found
-
-
- )}
-
-
-
- {filteredMembers.length > 0 && (
-
-
1-{filteredMembers.length} of {filteredMembers.length}
-
-
-
-
-
-
-
- )}
-
-
-
-
- {/* Hubs Tab */}
-
-
- {hubs.length > 0 ? (
- hubs.map((hub) => (
-
-
-
-
-
-
-
-
-
{hub.hub_name}
-
- {members.filter(m => m.hub === hub.hub_name).length} members
-
-
- {hub.manager_name && (
-
Manager: {hub.manager_name}
- )}
-
-
-
- {hub.address &&
{hub.address}
}
- {hub.city && (
-
- {hub.city}{hub.state ? `, ${hub.state}` : ''} {hub.zip_code}
-
- )}
- {hub.manager_email && (
-
{hub.manager_email}
- )}
-
-
- {hub.departments && hub.departments.length > 0 && (
-
-
DEPARTMENTS
-
- {hub.departments.map((dept, idx) => (
-
-
{dept.department_name}
- {dept.cost_center && (
-
Cost Center: {dept.cost_center}
- )}
- {dept.manager_name && (
-
Manager: {dept.manager_name}
- )}
-
- ))}
-
-
- )}
-
-
-
-
- ))
- ) : (
-
-
-
- No Hubs Yet
- Create your first hub location
-
-
-
- )}
-
-
-
- {/* Favorite Staff Tab */}
-
-
-
-
-
-
- setFavoriteSearch(e.target.value)}
- className="pl-10"
- />
-
-
-
-
- {team.favorite_staff && team.favorite_staff.length > 0 ? (
-
- {team.favorite_staff.filter(f =>
- !favoriteSearch ||
- f.staff_name?.toLowerCase().includes(favoriteSearch.toLowerCase()) ||
- f.position?.toLowerCase().includes(favoriteSearch.toLowerCase())
- ).map((fav) => (
-
-
-
-
-
-
- {fav.staff_name?.charAt(0)}
-
-
-
-
{fav.staff_name}
-
{fav.position}
-
-
-
-
-
-
-
- ))}
-
- ) : (
-
-
-
No Favorite Staff
-
Mark staff as favorites to see them here
-
-
- )}
-
-
-
-
- {/* Blocked Staff Tab */}
-
-
-
-
-
-
- setBlockedSearch(e.target.value)}
- className="pl-10"
- />
-
-
-
-
- {team.blocked_staff && team.blocked_staff.length > 0 ? (
-
- {team.blocked_staff.filter(b =>
- !blockedSearch ||
- b.staff_name?.toLowerCase().includes(blockedSearch.toLowerCase())
- ).map((blocked) => (
-
-
-
-
-
-
- {blocked.staff_name?.charAt(0)}
-
-
-
-
{blocked.staff_name}
-
Reason: {blocked.reason || 'No reason provided'}
-
Blocked {new Date(blocked.blocked_date).toLocaleDateString()}
-
-
-
-
-
-
- ))}
-
- ) : (
-
-
-
No Blocked Staff
-
Blocked staff will appear here
-
- )}
-
-
-
-
-
- {/* Invite Member Dialog */}
-
-
- {/* Edit Member Dialog */}
-
-
- {/* Add Hub Dialog */}
-
-
- {/* Add Department Dialog */}
-
-
- {/* Add Favorite Staff Dialog */}
-
-
- {/* Add Blocked Staff Dialog */}
-
-
-
- );
-}
\ No newline at end of file
diff --git a/frontend-web/src/pages/Teams.jsx b/frontend-web/src/pages/Teams.jsx
deleted file mode 100644
index 5113f6a0..00000000
--- a/frontend-web/src/pages/Teams.jsx
+++ /dev/null
@@ -1,2575 +0,0 @@
-import React, { useState, useEffect } from "react";
-import { base44 } from "@/api/base44Client";
-import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
-import { Link, useNavigate } from "react-router-dom";
-import { createPageUrl } from "@/utils";
-import { Button } from "@/components/ui/button";
-import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
-import { Input } from "@/components/ui/input";
-import { Badge } from "@/components/ui/badge";
-import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
-import { Users, Plus, Search, Building2, MapPin, UserCheck, Mail, Edit, Loader2, Trash2, UserX, LayoutGrid, List as ListIcon, RefreshCw, Send, Filter, Star, UserPlus } from "lucide-react";
-import PageHeader from "@/components/common/PageHeader";
-import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
-import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DialogDescription } from "@/components/ui/dialog";
-import { Label } from "@/components/ui/label";
-import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
-import { useToast } from "@/components/ui/use-toast";
-import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
-import {
- AlertDialog,
- AlertDialogAction,
- AlertDialogCancel,
- AlertDialogContent,
- AlertDialogDescription,
- AlertDialogFooter,
- AlertDialogHeader,
- AlertDialogTitle,
-} from "@/components/ui/alert-dialog";
-
-export default function Teams() {
- const navigate = useNavigate();
- const queryClient = useQueryClient();
- const { toast } = useToast();
- const [searchTerm, setSearchTerm] = useState("");
- const [departmentFilter, setDepartmentFilter] = useState("all");
- const [viewMode, setViewMode] = useState("grid");
- const [activeTab, setActiveTab] = useState("active");
- const [showInviteMemberDialog, setShowInviteMemberDialog] = useState(false);
- const [showEditMemberDialog, setShowEditMemberDialog] = useState(false);
- const [showDepartmentDialog, setShowDepartmentDialog] = useState(false);
- const [showDeleteTeamDialog, setShowDeleteTeamDialog] = useState(false);
- const [editingMember, setEditingMember] = useState(null);
- const [editingDepartment, setEditingDepartment] = useState(null);
- const [teamToDelete, setTeamToDelete] = useState(null);
- const [newDepartment, setNewDepartment] = useState("");
- const [favoriteSearch, setFavoriteSearch] = useState("");
- const [blockedSearch, setBlockedSearch] = useState("");
- const [showAddFavoriteDialog, setShowAddFavoriteDialog] = useState(false);
- const [showAddBlockedDialog, setShowAddBlockedDialog] = useState(false);
- const [blockReason, setBlockReason] = useState("");
- const [showAddHubDialog, setShowAddHubDialog] = useState(false);
- const [showAddHubDepartmentDialog, setShowAddHubDepartmentDialog] = useState(false);
- const [selectedHubForDept, setSelectedHubForDept] = useState(null);
- const [preSelectedHub, setPreSelectedHub] = useState(null);
- const [newHubDepartment, setNewHubDepartment] = useState({
- department_name: "",
- cost_center: ""
- });
-
- const [inviteData, setInviteData] = useState({
- email: "",
- full_name: "",
- role: "member",
- hub: "",
- department: "",
- });
-
- const [newHub, setNewHub] = useState({
- hub_name: "",
- address: "",
- manager_name: "",
- manager_position: "",
- manager_email: ""
- });
-
- const [isGoogleMapsLoaded, setIsGoogleMapsLoaded] = useState(false);
- const addressInputRef = React.useRef(null);
- const autocompleteRef = React.useRef(null);
-
- const { data: user } = useQuery({
- queryKey: ['current-user-teams'],
- queryFn: () => base44.auth.me(),
- });
-
- const userRole = user?.user_role || user?.role;
-
- /**
- * CRITICAL ISOLATION LAYER:
- * Each role (Admin, Procurement, Operator, Sector, Client, Vendor, Workforce)
- * gets their OWN isolated team that ONLY they can see and manage.
- *
- * Security Rules:
- * - Teams are filtered by owner_id === current user's ID
- * - Vendors CANNOT see Procurement teams
- * - Procurement CANNOT see Vendor teams
- * - Operators CANNOT see Client teams
- * - NO cross-layer visibility is allowed
- *
- * This ensures complete data isolation across all organizational layers.
- */
- const { data: userTeam } = useQuery({
- queryKey: ['user-team', user?.id, userRole],
- queryFn: async () => {
- if (!user?.id) {
- console.warn("âš ï¸ No user ID found - cannot fetch team");
- return null;
- }
-
- // SECURITY: Fetch ALL teams and filter by owner_id
- // This ensures only THIS user's team is returned
- const allTeams = await base44.entities.Team.list('-created_date');
-
- // Find ONLY teams owned by this specific user
- let team = allTeams.find(t => t.owner_id === user.id);
-
- // ISOLATION VERIFICATION
- if (team && team.owner_id !== user.id) {
- console.error("🚨 SECURITY VIOLATION: Team owner mismatch!");
- return null;
- }
-
- // Auto-create team if doesn't exist (first time user accesses Teams)
- if (!team && user.id) {
- console.log(`✅ Creating new isolated team for ${userRole} user: ${user.email}`);
- const teamName = user.company_name || `${user.full_name}'s Team` || "My Team";
-
- team = await base44.entities.Team.create({
- team_name: teamName,
- owner_id: user.id, // CRITICAL: Links team to THIS user only
- owner_name: user.full_name || user.email,
- owner_role: userRole, // Tracks which layer this team belongs to
- email: user.email,
- phone: user.phone || "",
- total_members: 0,
- active_members: 0,
- total_hubs: 0,
- favorite_staff_count: 0,
- blocked_staff_count: 0,
- departments: [], // Initialize with an empty array for departments
- });
-
- console.log(`✅ Team created successfully for ${userRole}: ${team.id}`);
- }
-
- // FINAL VERIFICATION: Ensure team belongs to current user
- if (team) {
- console.log(`🔒 Team loaded for ${userRole}: ${team.team_name} (Owner: ${team.owner_id})`);
-
- // Double-check ownership
- if (team.owner_id !== user.id) {
- console.error("🚨 CRITICAL: Attempted to load team not owned by current user!");
- toast({
- title: "â›” Access Denied",
- description: "You don't have permission to view this team.",
- variant: "destructive",
- });
- return null;
- }
- }
-
- return team;
- },
- enabled: !!user?.id,
- });
-
- /**
- * CRITICAL ISOLATION LAYER FOR TEAM MEMBERS:
- * Only fetch members that belong to THIS user's team.
- * Members from other teams/layers are NEVER visible.
- */
- const { data: teamMembers = [] } = useQuery({
- queryKey: ['team-members', userTeam?.id, user?.id],
- queryFn: async () => {
- if (!userTeam?.id) {
- console.log("âš ï¸ No team ID - returning empty members list");
- return [];
- }
-
- // Fetch all members and filter by team_id
- const allMembers = await base44.entities.TeamMember.list('-created_date');
-
- // SECURITY: Only return members that belong to THIS user's team
- const filteredMembers = allMembers.filter(m => m.team_id === userTeam.id);
-
- console.log(`🔒 Loaded ${filteredMembers.length} members for team ${userTeam.id}`);
-
- // VERIFICATION: Ensure all returned members belong to the correct team
- const invalidMembers = filteredMembers.filter(m => m.team_id !== userTeam.id);
- if (invalidMembers.length > 0) {
- console.error("🚨 SECURITY VIOLATION: Found members from other teams!");
- return [];
- }
-
- return filteredMembers;
- },
- enabled: !!userTeam?.id && !!user?.id,
- initialData: [],
- });
-
- // Fetch pending invitations
- const { data: pendingInvites = [] } = useQuery({
- queryKey: ['team-invites', userTeam?.id],
- queryFn: async () => {
- if (!userTeam?.id) return [];
- const allInvites = await base44.entities.TeamMemberInvite.list('-invited_date');
- return allInvites.filter(inv => inv.team_id === userTeam.id && inv.invite_status === 'pending');
- },
- enabled: !!userTeam?.id,
- initialData: [],
- });
-
- const { data: allStaff = [] } = useQuery({
- queryKey: ['staff-for-favorites'],
- queryFn: () => base44.entities.Staff.list(),
- enabled: !!userTeam?.id,
- initialData: [],
- });
-
- const { data: teamHubs = [] } = useQuery({
- queryKey: ['team-hubs-main', userTeam?.id],
- queryFn: async () => {
- if (!userTeam?.id) return [];
- const allHubs = await base44.entities.TeamHub.list('-created_date');
- return allHubs.filter(h => h.team_id === userTeam.id);
- },
- enabled: !!userTeam?.id,
- initialData: [],
- });
-
- // Get unique departments from both team settings and existing team members
- const teamDepartments = userTeam?.departments || [];
- const memberDepartments = [...new Set(teamMembers.map(m => m.department).filter(Boolean))];
- const uniqueDepartments = [...new Set([...teamDepartments, ...memberDepartments])];
-
- // Separate active and deactivated members
- const activeMembers = teamMembers.filter(m => m.is_active !== false);
- const deactivatedMembers = teamMembers.filter(m => m.is_active === false);
-
- const createTestInviteMutation = useMutation({
- mutationFn: async () => {
- if (!userTeam?.id) {
- throw new Error("Team not found. Cannot create test invite.");
- }
- if (!user?.email && !user?.full_name) {
- throw new Error("User identity not found. Cannot create test invite.");
- }
-
- const inviteCode = `TEAM-${Math.floor(10000 + Math.random() * 90000)}`;
-
- // Use the first hub if available, or empty string
- const firstHub = teamHubs.length > 0 ? teamHubs[0].hub_name : "";
- const firstDept = uniqueDepartments.length > 0 ? uniqueDepartments[0] : "Operations";
-
- const invite = await base44.entities.TeamMemberInvite.create({
- team_id: userTeam.id,
- team_name: userTeam.team_name || "Team",
- invite_code: inviteCode,
- email: "demo@example.com",
- full_name: "Demo User",
- role: "member",
- hub: firstHub,
- department: firstDept,
- invited_by: user?.email || user?.full_name,
- invite_status: "pending",
- invited_date: new Date().toISOString(),
- expires_at: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString()
- });
-
- return invite;
- },
- onSuccess: (invite) => {
- navigate(createPageUrl("Onboarding") + `?invite=${invite.invite_code}`);
- },
- onError: (error) => {
- toast({
- title: "⌠Failed to Create Test Invite",
- description: error.message,
- variant: "destructive",
- });
- },
- });
-
- const inviteMemberMutation = useMutation({
- mutationFn: async (data) => {
- if (!userTeam?.id) {
- throw new Error("No team found. Please try refreshing the page.");
- }
-
- if (!user?.email && !user?.full_name) {
- throw new Error("Unable to identify who is sending the invite. Please try logging out and back in.");
- }
-
- // Create hub if it doesn't exist, or update hub with new department
- const existingHub = teamHubs.find(h => h.hub_name === data.hub);
-
- if (data.hub && !existingHub) {
- // Create new hub with department
- await base44.entities.TeamHub.create({
- team_id: userTeam.id,
- hub_name: data.hub,
- address: "",
- is_active: true,
- departments: data.department ? [{ department_name: data.department, cost_center: "" }] : []
- });
- queryClient.invalidateQueries({ queryKey: ['team-hubs-main', userTeam?.id] });
- } else if (existingHub && data.department) {
- // Add department to existing hub if it doesn't exist
- const hubDepartments = existingHub.departments || [];
- const departmentExists = hubDepartments.some(d => d.department_name === data.department);
-
- if (!departmentExists) {
- await base44.entities.TeamHub.update(existingHub.id, {
- departments: [...hubDepartments, { department_name: data.department, cost_center: "" }]
- });
- queryClient.invalidateQueries({ queryKey: ['team-hubs-main', userTeam?.id] });
- }
- }
-
- const inviteCode = `TEAM-${Math.floor(10000 + Math.random() * 90000)}`;
-
- const invite = await base44.entities.TeamMemberInvite.create({
- team_id: userTeam.id,
- team_name: userTeam.team_name || "Team",
- invite_code: inviteCode,
- email: data.email,
- full_name: data.full_name,
- role: data.role,
- hub: data.hub || "",
- department: data.department || "",
- invited_by: user?.email || user?.full_name,
- invite_status: "pending",
- invited_date: new Date().toISOString(),
- expires_at: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString()
- });
-
- const registerUrl = `${window.location.origin}${createPageUrl('Onboarding')}?invite=${inviteCode}`;
-
- await base44.integrations.Core.SendEmail({
- from_name: userTeam.team_name || "KROW",
- to: data.email,
- subject: `🚀 Welcome to KROW! You've been invited to ${data.hub || userTeam.team_name}`,
- body: `
-
-
-
🎉
-
You're Invited!
-
Join ${data.hub ? `the ${data.hub} hub` : userTeam.team_name || 'our team'}
-
-
-
-
- Hi ${data.full_name || 'there'} 👋
-
-
-
- Great news! ${user?.full_name || user?.email} has invited you to join ${data.hub || userTeam.team_name || 'the team'} as a ${data.role}.
-
-
-
-
🚀 Why KROW?
-
- - Seamless Operations: Manage your workforce effortlessly
- - Smart Scheduling: AI-powered shift assignments
- - Real-Time Updates: Stay connected with your team
- - Simplified Workflow: Everything you need in one place
-
-
-
-
-
-
-
✅ Quick Setup (3 Steps):
-
- - Click the button above to register
- - Create your account with ${data.email}
- - Start managing your operations smoothly!
-
-
-
-
-
- â° Time-Sensitive: This invitation expires in 7 days. Don't miss out!
-
-
-
-
-
-
-
-
Powered by KROW - Workforce Control Tower
-
-
- `
- });
-
- return { invite };
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ['team-members', userTeam?.id] });
- queryClient.invalidateQueries({ queryKey: ['team-invites', userTeam?.id] });
- setShowInviteMemberDialog(false);
- setPreSelectedHub(null);
- setInviteData({
- email: "",
- full_name: "",
- role: "member",
- hub: "",
- department: "",
- });
- toast({
- title: "✅ Invitation Sent!",
- description: `Email invitation sent to ${inviteData.email}`,
- });
- },
- onError: (error) => {
- toast({
- title: "⌠Failed to Send Invitation",
- description: error.message,
- variant: "destructive",
- });
- },
- });
-
- const resendInviteMutation = useMutation({
- mutationFn: async (invite) => {
- const registerUrl = `${window.location.origin}${createPageUrl('Onboarding')}?invite=${invite.invite_code}`;
-
- await base44.integrations.Core.SendEmail({
- from_name: userTeam.team_name || "Team",
- to: invite.email,
- subject: `Reminder: You're invited to join ${userTeam.team_name || 'our team'}!`,
- body: `
-
-
-
📬 Reminder: Team Invitation
-
Join ${userTeam.team_name || 'our team'}
-
-
-
-
- Hi ${invite.full_name || 'there'},
-
-
-
- This is a reminder that ${invite.invited_by} has invited you to join ${userTeam.team_name || 'our team'} as a ${invite.role}.
-
-
-
-
-
-
- â° Important: This invitation will expire soon. Please register at your earliest convenience.
-
-
-
-
- Your invite code: ${invite.invite_code}
- Questions? Contact ${user?.email || 'the team admin'}
-
-
-
- `
- });
-
- return invite;
- },
- onSuccess: () => {
- toast({
- title: "✅ Invitation Resent!",
- description: "The invitation has been sent again",
- });
- },
- onError: (error) => {
- toast({
- title: "⌠Failed to Resend",
- description: error.message,
- variant: "destructive",
- });
- },
- });
-
- const updateMemberMutation = useMutation({
- mutationFn: ({ id, data }) => base44.entities.TeamMember.update(id, data),
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ['team-members', userTeam?.id] });
- setShowEditMemberDialog(false);
- setEditingMember(null);
- toast({
- title: "✅ Member Updated",
- description: "Team member updated successfully",
- });
- },
- });
-
- const deactivateMemberMutation = useMutation({
- mutationFn: ({ id }) => base44.entities.TeamMember.update(id, { is_active: false }),
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ['team-members', userTeam?.id] });
- toast({
- title: "✅ Member Deactivated",
- description: "Team member has been deactivated",
- });
- },
- });
-
- const activateMemberMutation = useMutation({
- mutationFn: ({ id }) => base44.entities.TeamMember.update(id, { is_active: true }),
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ['team-members', userTeam?.id] });
- toast({
- title: "✅ Member Activated",
- description: "Team member has been activated",
- });
- },
- });
-
- const handleInviteMember = () => {
- inviteMemberMutation.mutate(inviteData);
- };
-
- const handleEditMember = (member) => {
- setEditingMember(member);
- setShowEditMemberDialog(true);
- };
-
- const handleUpdateMember = () => {
- updateMemberMutation.mutate({
- id: editingMember.id,
- data: editingMember
- });
- };
-
- const handleDeactivateMember = (member) => {
- deactivateMemberMutation.mutate({ id: member.id });
- };
-
- const handleActivateMember = (member) => {
- activateMemberMutation.mutate({ id: member.id });
- };
-
- const handleAddDepartment = () => {
- setEditingDepartment(null);
- setNewDepartment("");
- setShowDepartmentDialog(true);
- };
-
- const handleSaveDepartment = async () => {
- if (!newDepartment.trim()) {
- toast({
- title: "âš ï¸ Invalid Department",
- description: "Department name cannot be empty",
- variant: "destructive",
- });
- return;
- }
-
- if (!userTeam?.id) {
- toast({
- title: "âš ï¸ Error",
- description: "Team not found. Please refresh the page.",
- variant: "destructive",
- });
- return;
- }
-
- try {
- const currentDepartments = userTeam.departments || [];
- let updatedDepartments;
-
- if (editingDepartment) {
- // Update existing department
- updatedDepartments = currentDepartments.map(dept =>
- dept === editingDepartment ? newDepartment.trim() : dept
- );
- } else {
- // Add new department
- if (currentDepartments.includes(newDepartment.trim())) {
- toast({
- title: "âš ï¸ Duplicate Department",
- description: "This department already exists",
- variant: "destructive",
- });
- return;
- }
- updatedDepartments = [...currentDepartments, newDepartment.trim()];
- }
-
- // Update the team with new departments list
- await base44.entities.Team.update(userTeam.id, {
- departments: updatedDepartments
- });
-
- // Refresh team data
- queryClient.invalidateQueries({ queryKey: ['user-team', user?.id, userRole] });
-
- toast({
- title: "✅ Department Saved",
- description: `Department "${newDepartment}" has been ${editingDepartment ? 'updated' : 'added'}`,
- });
-
- setShowDepartmentDialog(false);
- setEditingDepartment(null);
- setNewDepartment("");
- } catch (error) {
- toast({
- title: "⌠Error",
- description: "Failed to save department. Please try again.",
- variant: "destructive",
- });
- }
- };
-
- const handleDeleteDepartment = async (deptToDelete) => {
- if (!userTeam?.id) return;
-
- try {
- const currentDepartments = userTeam.departments || [];
- const updatedDepartments = currentDepartments.filter(dept => dept !== deptToDelete);
-
- await base44.entities.Team.update(userTeam.id, {
- departments: updatedDepartments
- });
-
- queryClient.invalidateQueries({ queryKey: ['user-team', user?.id, userRole] });
-
- toast({
- title: "✅ Department Deleted",
- description: `Department "${deptToDelete}" has been removed`,
- });
- } catch (error) {
- toast({
- title: "⌠Error",
- description: "Failed to delete department. Please try again.",
- variant: "destructive",
- });
- }
- };
-
- const updateTeamMutation = useMutation({
- mutationFn: ({ id, data }) => base44.entities.Team.update(id, data),
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ['user-team', user?.id, userRole] });
- toast({
- title: "✅ Team Updated",
- description: "Team updated successfully",
- });
- },
- });
-
- const addToFavorites = (staff) => {
- const favoriteStaff = userTeam.favorite_staff || [];
- const newFavorite = {
- staff_id: staff.id,
- staff_name: staff.employee_name,
- position: staff.position,
- added_date: new Date().toISOString()
- };
-
- updateTeamMutation.mutate({
- id: userTeam.id,
- data: {
- favorite_staff: [...favoriteStaff, newFavorite],
- favorite_staff_count: favoriteStaff.length + 1
- }
- });
- setShowAddFavoriteDialog(false);
- };
-
- const removeFromFavorites = (staffId) => {
- const favoriteStaff = (userTeam.favorite_staff || []).filter(f => f.staff_id !== staffId);
- updateTeamMutation.mutate({
- id: userTeam.id,
- data: {
- favorite_staff: favoriteStaff,
- favorite_staff_count: favoriteStaff.length
- }
- });
- };
-
- const addToBlocked = (staff) => {
- const blockedStaff = userTeam.blocked_staff || [];
- const newBlocked = {
- staff_id: staff.id,
- staff_name: staff.employee_name,
- reason: blockReason,
- blocked_date: new Date().toISOString()
- };
-
- updateTeamMutation.mutate({
- id: userTeam.id,
- data: {
- blocked_staff: [...blockedStaff, newBlocked],
- blocked_staff_count: blockedStaff.length + 1
- }
- });
- setShowAddBlockedDialog(false);
- setBlockReason("");
- };
-
- const removeFromBlocked = (staffId) => {
- const blockedStaff = (userTeam.blocked_staff || []).filter(b => b.staff_id !== staffId);
- updateTeamMutation.mutate({
- id: userTeam.id,
- data: {
- blocked_staff: blockedStaff,
- blocked_staff_count: blockedStaff.length
- }
- });
- };
-
- // Load Google Maps script
- useEffect(() => {
- if (window.google?.maps?.places) {
- setIsGoogleMapsLoaded(true);
- return;
- }
-
- const script = document.createElement('script');
- script.src = `https://maps.googleapis.com/maps/api/js?key=AIzaSyBkP7xH4NvR6C6vZ8Y3J7qX2QW8Z9vN3Zc&libraries=places`;
- script.async = true;
- script.onload = () => setIsGoogleMapsLoaded(true);
- document.head.appendChild(script);
- }, []);
-
- // Initialize autocomplete
- useEffect(() => {
- if (isGoogleMapsLoaded && addressInputRef.current && showAddHubDialog && !autocompleteRef.current) {
- autocompleteRef.current = new window.google.maps.places.Autocomplete(addressInputRef.current, {
- types: ['address'],
- componentRestrictions: { country: 'us' }
- });
-
- autocompleteRef.current.addListener('place_changed', () => {
- const place = autocompleteRef.current.getPlace();
- if (place.formatted_address) {
- setNewHub({ ...newHub, address: place.formatted_address });
- }
- });
- }
- }, [isGoogleMapsLoaded, showAddHubDialog]);
-
- const createHubMutation = useMutation({
- mutationFn: (hubData) => base44.entities.TeamHub.create({
- ...hubData,
- team_id: userTeam.id,
- is_active: true
- }),
- onSuccess: (createdHub) => {
- queryClient.invalidateQueries({ queryKey: ['team-hubs-main', userTeam?.id] });
- setShowAddHubDialog(false);
- const hubName = newHub.hub_name;
- setNewHub({
- hub_name: "",
- address: "",
- manager_name: "",
- manager_position: "",
- manager_email: ""
- });
- autocompleteRef.current = null;
-
- // Show success with invite action
- toast({
- title: "✅ Hub Created Successfully!",
- description: (
-
- Ready to invite members to {hubName}?
-
-
- ),
- });
- },
- });
-
- const filteredMembers = (members) => members.filter(member => {
- const matchesSearch = !searchTerm ||
- member.member_name?.toLowerCase().includes(searchTerm.toLowerCase()) ||
- member.email?.toLowerCase().includes(searchTerm.toLowerCase()) ||
- member.title?.toLowerCase().includes(searchTerm.toLowerCase());
-
- const matchesDepartment = departmentFilter === "all" || member.department === departmentFilter;
-
- return matchesSearch && matchesDepartment;
- });
-
- const getRoleTitle = () => {
- const titles = {
- admin: "Admin Team",
- procurement: "Procurement Team",
- operator: "Operator Team",
- sector: "Sector Team",
- client: "Client Team",
- vendor: "Vendor Team",
- workforce: "Workforce Team"
- };
- return titles[userRole] || "Team";
- };
-
- const getIsolatedSubtitle = () => {
- return `${activeMembers.length} active • ${deactivatedMembers.length} deactivated • ${pendingInvites.length} pending invites`;
- };
-
- const renderMemberCard = (member) => (
-
-
-
-
- {member.member_name?.split(' ').map(n => n[0]).join('') || '?'}
- {!member.is_active && (
-
-
-
- )}
-
-
-
- {member.member_name}
-
-
{member.role}
- {member.title && (
-
{member.title}
- )}
-
-
-
-
- {member.email && (
-
-
- {member.email}
-
- )}
-
- {member.department && (
-
- {member.department}
-
- )}
- {userRole !== 'vendor' && member.hub && (
-
-
- {member.hub}
-
- )}
-
-
-
-
-
- {member.is_active ? (
-
- ) : (
-
- )}
-
-
-
- );
-
- return (
-
-
-
- {/* Security Notice Banner */}
-
-
-
- Isolated Team: You can only see and manage YOUR team members.
- {userRole === 'vendor' && " Procurement teams are NOT visible to you."}
- {userRole === 'procurement' && " Vendor teams are NOT visible to you."}
- {userRole === 'operator' && " Other layer teams are NOT visible to you."}
-
-
-
-
-
- {/* Team Members Section */}
-
-
-
-
-
-
-
-
-
Team Management
-
Manage roles, permissions, and team organization
-
-
-
-
-
-
-
-
-
-
- {/* Filters and View Toggle */}
-
-
-
- setSearchTerm(e.target.value)}
- className="pl-10 border-slate-300 focus:border-[#0A39DF] transition-all"
- />
-
-
-
-
-
-
-
-
-
-
-
-
-
- {/* Tabs for Active, Deactivated, Invitations, Hubs, Favorites, Blocked */}
-
-
-
-
- Active ({activeMembers.length})
-
-
-
- Deactivated ({deactivatedMembers.length})
-
-
-
- Invitations ({pendingInvites.length})
-
- {userRole === 'vendor' ? (
-
-
- Departments ({uniqueDepartments.length})
-
- ) : (
-
-
- Hubs ({teamHubs.length})
-
- )}
-
-
- Favorites ({userTeam?.favorite_staff_count || 0})
-
-
-
- Blocked ({userTeam?.blocked_staff_count || 0})
-
-
-
- {/* Active Members Tab */}
-
- {viewMode === "grid" && filteredMembers(activeMembers).length > 0 && (
-
- {filteredMembers(activeMembers).map(renderMemberCard)}
-
- )}
-
- {viewMode === "list" && filteredMembers(activeMembers).length > 0 && (
-
-
-
-
- | # |
- Name |
- Title |
- Role |
- Department |
- {userRole !== 'vendor' && (
- <>
- Hub |
- Hub Address |
- >
- )}
- Actions |
-
-
-
- {filteredMembers(activeMembers).map((member, index) => {
- const memberHub = teamHubs.find(h => h.hub_name === member.hub);
- return (
-
- | {index + 1} |
-
-
-
- {member.member_name?.split(' ').map(n => n[0]).join('') || '?'}
-
-
- {member.member_name}
- {member.email}
-
-
- |
- {member.title || '-'} |
-
-
- {member.role}
-
- |
- {member.department || 'No Department'} |
- {userRole !== 'vendor' && (
- <>
- {member.hub || 'No Hub'} |
- {memberHub?.address || 'No Address'} |
- >
- )}
-
-
-
-
-
- |
-
- );
- })}
-
-
-
- )}
-
- {filteredMembers(activeMembers).length === 0 && (
-
-
-
-
-
No Active Members
-
- {activeMembers.length === 0
- ? 'Invite your first team member to get started'
- : 'No active members match your filters'}
-
- {activeMembers.length === 0 && (
-
- )}
-
- )}
-
-
- {/* Deactivated Members Tab */}
-
- {viewMode === "grid" && filteredMembers(deactivatedMembers).length > 0 && (
-
- {filteredMembers(deactivatedMembers).map(renderMemberCard)}
-
- )}
-
- {viewMode === "list" && filteredMembers(deactivatedMembers).length > 0 && (
-
-
-
-
- | # |
- Name |
- Title |
- Role |
- Department |
- {userRole !== 'vendor' && (
- <>
- Hub |
- Hub Address |
- >
- )}
- Actions |
-
-
-
- {filteredMembers(deactivatedMembers).map((member, index) => {
- const memberHub = teamHubs.find(h => h.hub_name === member.hub);
- return (
-
- | {index + 1} |
-
-
-
- {member.member_name?.split(' ').map(n => n[0]).join('') || '?'}
-
-
-
-
-
- {member.member_name}
- {member.email}
-
-
- |
- {member.title || '-'} |
-
-
- {member.role}
-
- |
- {member.department || 'No Department'} |
- {userRole !== 'vendor' && (
- <>
- {member.hub || 'No Hub'} |
- {memberHub?.address || 'No Address'} |
- >
- )}
-
-
-
-
-
- |
-
- );
- })}
-
-
-
- )}
-
- {filteredMembers(deactivatedMembers).length === 0 && (
-
-
-
-
-
No Deactivated Members
-
All your team members are currently active
-
- )}
-
-
- {/* Pending Invitations Tab */}
-
- {pendingInvites.length > 0 ? (
-
- {pendingInvites.map((invite) => (
-
-
-
-
-
-
-
{invite.full_name}
-
{invite.email}
-
-
- {invite.role}
-
-
- Invited {new Date(invite.invited_date).toLocaleDateString()}
-
-
-
-
-
-
- ))}
-
- ) : (
-
-
-
-
-
No Pending Invitations
-
All invitations have been accepted or expired
-
- )}
-
-
- {/* Departments Tab (for Vendors) */}
-
-
-
-
-
- Departments
-
-
-
-
- {uniqueDepartments.length > 0 ? (
-
- {uniqueDepartments.map((dept) => (
-
-
-
-
-
-
-
-
-
-
- {activeMembers.filter(m => m.department === dept).length} members
-
-
-
- ))}
-
- ) : (
-
-
-
No Departments Yet
-
Create departments to organize your team
-
-
- )}
-
-
-
- {/* Hubs Tab */}
-
-
- {teamHubs.length > 0 ? (
- viewMode === "grid" ? (
-
- {teamHubs.map((hub) => (
-
- {/* Hub Header */}
-
-
-
-
-
-
-
-
{hub.hub_name}
- {hub.address && (
-
- )}
- {hub.manager_name && (
-
- )}
-
-
-
-
-
-
-
- {/* Quick Stats */}
-
-
-
-
-
-
-
Team Members
-
{activeMembers.filter(m => m.hub === hub.hub_name).length}
-
-
-
-
-
-
-
-
Departments
-
{hub.departments?.length || 0}
-
-
-
-
-
- {/* Departments Section */}
-
-
-
-
- Departments
-
-
-
-
- {hub.departments && hub.departments.length > 0 ? (
-
- {hub.departments.map((dept, idx) => (
-
-
-
-
-
-
-
-
-
{dept.department_name}
- {dept.cost_center && (
-
Cost Center: {dept.cost_center}
- )}
-
-
- {dept.manager_name && (
-
- {dept.manager_name}
-
- )}
-
-
- {/* Team members in this department */}
- {activeMembers.filter(m => m.hub === hub.hub_name && m.department === dept.department_name).length > 0 && (
-
-
- Team ({activeMembers.filter(m => m.hub === hub.hub_name && m.department === dept.department_name).length})
-
-
- {activeMembers.filter(m => m.hub === hub.hub_name && m.department === dept.department_name).map((member) => (
-
handleEditMember(member)}>
-
- {member.member_name?.split(' ').map(n => n[0]).join('') || '?'}
-
-
-
{member.member_name}
-
{member.title || member.role}
-
-
- ))}
-
-
- )}
-
-
- ))}
-
- ) : (
-
-
-
No departments yet
-
-
- )}
-
-
- ))}
-
- {/* Add New Hub Button */}
-
-
- ) : (
-
-
-
-
- Hub Name
- Address
- Manager
- Departments
- Members
- Actions
-
-
-
- {teamHubs.map((hub) => (
-
-
-
-
-
-
-
- {hub.address || '—'}
-
-
-
-
-
{hub.manager_name || '—'}
- {hub.manager_email && (
-
{hub.manager_email}
- )}
-
-
-
-
- {hub.departments?.length || 0} depts
-
-
-
-
- {activeMembers.filter(m => m.hub === hub.hub_name).length} members
-
-
-
-
-
-
-
-
-
- ))}
-
-
-
-
- )
- ) : (
-
-
-
-
-
No Hubs Yet
-
- Create your first hub location to organize your team by physical locations and departments
-
-
-
- )}
-
-
-
- {/* Favorites Tab */}
-
-
- {/* Header Section */}
-
-
-
-
-
-
-
- Preferred Staff
-
-
Your go-to professionals for high-priority assignments
-
-
-
-
{userTeam?.favorite_staff_count || 0}
-
Favorites
-
-
-
-
-
- {/* Search */}
-
-
- setFavoriteSearch(e.target.value)}
- className="pl-12 h-12 bg-white border-2 border-amber-200 focus:border-amber-400 text-base"
- />
-
-
-
- {userTeam?.favorite_staff && userTeam.favorite_staff.length > 0 ? (
- viewMode === "grid" ? (
-
- {userTeam.favorite_staff.filter(f =>
- !favoriteSearch ||
- f.staff_name?.toLowerCase().includes(favoriteSearch.toLowerCase()) ||
- f.position?.toLowerCase().includes(favoriteSearch.toLowerCase())
- ).map((fav) => (
-
-
-
-
-
-
- {fav.staff_name?.charAt(0)}
-
-
-
-
-
-
-
{fav.staff_name}
-
{fav.position}
-
- Added {new Date(fav.added_date).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })}
-
-
-
-
-
-
-
-
-
-
- ))}
-
- ) : (
-
-
-
- Staff Member
- Position
- Added Date
- Actions
-
-
-
- {userTeam.favorite_staff.filter(f =>
- !favoriteSearch ||
- f.staff_name?.toLowerCase().includes(favoriteSearch.toLowerCase()) ||
- f.position?.toLowerCase().includes(favoriteSearch.toLowerCase())
- ).map((fav) => (
-
-
-
-
- {fav.staff_name?.charAt(0)}
-
-
{fav.staff_name}
-
-
-
- {fav.position}
-
-
- {new Date(fav.added_date).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })}
-
-
-
-
-
-
- ))}
-
-
- )
- ) : (
-
-
-
-
-
No Favorites Yet
-
- Build your dream team by marking your most reliable and skilled staff members as favorites
-
-
-
- )}
-
-
-
- {/* Blocked Staff Tab */}
-
-
- {/* Header Section */}
-
-
-
-
-
-
-
- Blocked Staff
-
-
Staff members excluded from future assignments
-
-
-
-
{userTeam?.blocked_staff_count || 0}
-
Blocked
-
-
-
-
-
- {/* Search */}
-
-
- setBlockedSearch(e.target.value)}
- className="pl-12 h-12 bg-white border-2 border-red-200 focus:border-red-400 text-base"
- />
-
-
-
- {userTeam?.blocked_staff && userTeam.blocked_staff.length > 0 ? (
- viewMode === "grid" ? (
-
- {userTeam.blocked_staff.filter(b =>
- !blockedSearch ||
- b.staff_name?.toLowerCase().includes(blockedSearch.toLowerCase())
- ).map((blocked) => (
-
-
-
-
-
-
- {blocked.staff_name?.charAt(0)}
-
-
-
-
-
-
-
{blocked.staff_name}
-
-
Block Reason
-
{blocked.reason || 'No reason provided'}
-
-
-
-
- Blocked on {new Date(blocked.blocked_date).toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' })}
-
-
-
-
-
-
-
-
- ))}
-
- ) : (
-
-
-
- Staff Member
- Reason
- Blocked Date
- Actions
-
-
-
- {userTeam.blocked_staff.filter(b =>
- !blockedSearch ||
- b.staff_name?.toLowerCase().includes(blockedSearch.toLowerCase())
- ).map((blocked) => (
-
-
-
-
- {blocked.staff_name?.charAt(0)}
-
-
{blocked.staff_name}
-
-
-
-
- {blocked.reason || 'No reason provided'}
-
-
-
- {new Date(blocked.blocked_date).toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' })}
-
-
-
-
-
-
- ))}
-
-
- )
- ) : (
-
-
-
-
-
No Blocked Staff
-
- All staff members are currently eligible for assignments
-
-
- Block staff members who should not be assigned to your events
-
-
- )}
-
-
-
-
-
-
- {/* Invite Member Dialog */}
-
-
- {/* Department Dialog */}
-
-
- {/* Edit Member Dialog */}
-
-
- {/* Add Hub Dialog */}
-
-
- {/* Add Hub Department Dialog */}
-
-
- {/* Add Favorite Staff Dialog */}
-
-
- {/* Add Blocked Staff Dialog */}
-
-
-
-
- );
-}
\ No newline at end of file
diff --git a/frontend-web/src/pages/Tutorials.jsx b/frontend-web/src/pages/Tutorials.jsx
deleted file mode 100644
index 3eb76e5b..00000000
--- a/frontend-web/src/pages/Tutorials.jsx
+++ /dev/null
@@ -1,469 +0,0 @@
-import React, { useState } from "react";
-import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
-import { Input } from "@/components/ui/input";
-import { Badge } from "@/components/ui/badge";
-import { Button } from "@/components/ui/button";
-import {
- Play, Search, Calendar, Users, FileText, UserPlus, Building2,
- DollarSign, MessageSquare, Award, TrendingUp, MapPin,
- Briefcase, Package, CheckSquare, Headphones, Mail
-} from "lucide-react";
-import PageHeader from "@/components/common/PageHeader";
-
-export default function Tutorials() {
- const [searchTerm, setSearchTerm] = useState("");
- const [selectedCategory, setSelectedCategory] = useState("all");
- const [playingVideo, setPlayingVideo] = useState(null);
-
- const tutorials = [
- {
- id: 1,
- title: "How to Create an Event Order",
- description: "Learn how to create a new event booking with staff requirements, shifts, and scheduling",
- category: "Events",
- duration: "3:45",
- icon: Calendar,
- videoUrl: "https://www.youtube.com/embed/dQw4w9WgXcQ",
- steps: [
- "Navigate to Events page",
- "Click 'Create Event' button",
- "Fill in event details (name, date, location)",
- "Add shift requirements and roles",
- "Set headcount for each position",
- "Review and submit"
- ]
- },
- {
- id: 2,
- title: "Inviting Team Members",
- description: "Step-by-step guide to invite new members to your team and assign them to hubs",
- category: "Team Management",
- duration: "2:30",
- icon: UserPlus,
- videoUrl: "https://www.youtube.com/embed/dQw4w9WgXcQ",
- steps: [
- "Go to Teams page",
- "Click 'Invite Member' button",
- "Enter member's name and email",
- "Select role and department",
- "Choose hub location",
- "Send invitation email"
- ]
- },
- {
- id: 3,
- title: "Creating and Managing Hubs",
- description: "How to create location hubs and organize departments within them",
- category: "Team Management",
- duration: "4:15",
- icon: MapPin,
- videoUrl: "https://www.youtube.com/embed/dQw4w9WgXcQ",
- steps: [
- "Navigate to Teams → Hubs tab",
- "Click 'Create Hub' button",
- "Enter hub name (e.g., BVG300)",
- "Add location address",
- "Assign hub manager",
- "Add departments with cost centers"
- ]
- },
- {
- id: 4,
- title: "Staff Assignment & Scheduling",
- description: "Assign staff to events, manage schedules, and handle conflicts",
- category: "Staff Management",
- duration: "5:20",
- icon: Users,
- videoUrl: "https://www.youtube.com/embed/dQw4w9WgXcQ",
- steps: [
- "Open event details",
- "Click 'Assign Staff' button",
- "Filter staff by role and rating",
- "Select staff members",
- "Review conflict warnings",
- "Confirm assignments"
- ]
- },
- {
- id: 5,
- title: "Creating and Sending Invoices",
- description: "Generate invoices from events and send them to clients",
- category: "Invoicing",
- duration: "3:50",
- icon: FileText,
- videoUrl: "https://www.youtube.com/embed/dQw4w9WgXcQ",
- steps: [
- "Go to Invoices page",
- "Click 'Create Invoice'",
- "Select event or create manually",
- "Review line items and totals",
- "Set payment terms",
- "Send to client via email"
- ]
- },
- {
- id: 6,
- title: "Vendor Onboarding Process",
- description: "Complete guide to onboarding new vendors with compliance documents",
- category: "Vendor Management",
- duration: "6:10",
- icon: Package,
- videoUrl: "https://www.youtube.com/embed/dQw4w9WgXcQ",
- steps: [
- "Navigate to Vendors",
- "Click 'Add Vendor'",
- "Enter vendor details and contacts",
- "Upload W9 and COI documents",
- "Set coverage regions and roles",
- "Submit for approval"
- ]
- },
- {
- id: 7,
- title: "Managing Vendor Rates",
- description: "Set up and manage vendor pricing, markups, and client rates",
- category: "Vendor Management",
- duration: "4:30",
- icon: DollarSign,
- videoUrl: "https://www.youtube.com/embed/dQw4w9WgXcQ",
- steps: [
- "Go to Vendor Rates page",
- "Click 'Add New Rate'",
- "Select category and role",
- "Enter employee wage",
- "Set markup and vendor fee %",
- "Review client rate and save"
- ]
- },
- {
- id: 8,
- title: "Staff Onboarding Tutorial",
- description: "Onboard new staff members with all required information and documents",
- category: "Staff Management",
- duration: "5:00",
- icon: Users,
- videoUrl: "https://www.youtube.com/embed/dQw4w9WgXcQ",
- steps: [
- "Navigate to Onboarding page",
- "Enter staff personal details",
- "Add employment information",
- "Upload certifications",
- "Set availability and skills",
- "Complete profile setup"
- ]
- },
- {
- id: 9,
- title: "Using the Messaging System",
- description: "Communicate with team members, vendors, and clients through built-in messaging",
- category: "Communication",
- duration: "2:45",
- icon: MessageSquare,
- videoUrl: "https://www.youtube.com/embed/dQw4w9WgXcQ",
- steps: [
- "Go to Messages page",
- "Start new conversation",
- "Select participants",
- "Type and send messages",
- "Attach files if needed",
- "Archive old conversations"
- ]
- },
- {
- id: 10,
- title: "Managing Certifications",
- description: "Track and manage employee certifications and compliance documents",
- category: "Compliance",
- duration: "3:20",
- icon: Award,
- videoUrl: "https://www.youtube.com/embed/dQw4w9WgXcQ",
- steps: [
- "Navigate to Certifications",
- "Click 'Add Certification'",
- "Select employee and cert type",
- "Enter issue and expiry dates",
- "Upload certificate document",
- "Submit for validation"
- ]
- },
- {
- id: 11,
- title: "Enterprise & Sector Setup",
- description: "Set up enterprise organizations and manage multiple sectors",
- category: "Enterprise",
- duration: "5:40",
- icon: Building2,
- videoUrl: "https://www.youtube.com/embed/dQw4w9WgXcQ",
- steps: [
- "Go to Enterprise Management",
- "Click 'Add Enterprise'",
- "Enter enterprise details",
- "Add brand family members",
- "Create sectors under enterprise",
- "Link partners to sectors"
- ]
- },
- {
- id: 12,
- title: "Partner & Client Management",
- description: "Add partners, manage sites, and configure client relationships",
- category: "Partners",
- duration: "4:00",
- icon: Briefcase,
- videoUrl: "https://www.youtube.com/embed/dQw4w9WgXcQ",
- steps: [
- "Navigate to Partners",
- "Click 'Add Partner'",
- "Enter partner information",
- "Add multiple sites",
- "Configure allowed vendors",
- "Set payment terms"
- ]
- },
- {
- id: 13,
- title: "Generating Reports & Analytics",
- description: "Create custom reports and analyze workforce performance data",
- category: "Reports",
- duration: "4:25",
- icon: TrendingUp,
- videoUrl: "https://www.youtube.com/embed/dQw4w9WgXcQ",
- steps: [
- "Go to Reports page",
- "Select report type",
- "Choose date range",
- "Apply filters (vendor, client, etc.)",
- "Generate report",
- "Export to PDF or Excel"
- ]
- },
- {
- id: 14,
- title: "Task Board & Project Management",
- description: "Use the task board to track work items and collaborate with your team",
- category: "Productivity",
- duration: "3:10",
- icon: CheckSquare,
- videoUrl: "https://www.youtube.com/embed/dQw4w9WgXcQ",
- steps: [
- "Navigate to Task Board",
- "Create new task",
- "Assign to team members",
- "Set due dates and priority",
- "Move tasks between columns",
- "Mark tasks as complete"
- ]
- },
- {
- id: 15,
- title: "Role-Based Permissions",
- description: "Configure user roles and permissions across the platform",
- category: "Administration",
- duration: "3:55",
- icon: Users,
- videoUrl: "https://www.youtube.com/embed/dQw4w9WgXcQ",
- steps: [
- "Go to Permissions page",
- "Select user role",
- "Configure access levels",
- "Set entity permissions",
- "Enable/disable features",
- "Save permission settings"
- ]
- }
- ];
-
- const categories = ["all", ...new Set(tutorials.map(t => t.category))];
-
- const filteredTutorials = tutorials.filter(tutorial => {
- const matchesSearch = !searchTerm ||
- tutorial.title.toLowerCase().includes(searchTerm.toLowerCase()) ||
- tutorial.description.toLowerCase().includes(searchTerm.toLowerCase());
-
- const matchesCategory = selectedCategory === "all" || tutorial.category === selectedCategory;
-
- return matchesSearch && matchesCategory;
- });
-
- return (
-
-
-
-
- {/* Search and Filters */}
-
-
-
- setSearchTerm(e.target.value)}
- className="pl-10 h-12 border-slate-300 focus:border-[#0A39DF]"
- />
-
-
-
- {categories.map(category => (
-
- ))}
-
-
-
- {/* Tutorials Grid */}
-
- {filteredTutorials.map((tutorial) => (
-
-
-
-
-
-
-
-
-
- {tutorial.title}
-
-
{tutorial.description}
-
-
-
- {tutorial.duration}
-
-
-
-
-
- {/* Video Player */}
- {playingVideo === tutorial.id ? (
-
-
-
- ) : (
- setPlayingVideo(tutorial.id)}
- className="relative bg-gradient-to-br from-slate-200 to-slate-300 aspect-video flex items-center justify-center group-hover:from-blue-100 group-hover:to-indigo-200 transition-all cursor-pointer"
- >
-
-
- Watch Tutorial
-
-
- )}
-
- {/* Steps */}
-
-
What You'll Learn:
-
- {tutorial.steps.map((step, idx) => (
- -
-
- {idx + 1}
-
- {step}
-
- ))}
-
-
-
-
- ))}
-
-
- {/* No Results */}
- {filteredTutorials.length === 0 && (
-
-
-
No Tutorials Found
-
Try adjusting your search or filters
-
- )}
-
- {/* Support Section */}
-
-
-
-
-
-
- Questions about KROW Workforce?
-
-
- Contact KROW support team for personalized help
-
-
-
-
-
-
-
-
- {/* Quick Links */}
-
-
-
-
-
-
- Documentation
- Read the complete API docs
-
-
-
-
-
-
-
-
-
- Community Forum
- Connect with other users
-
-
-
-
-
-
-
- Best Practices
- Learn from experts
-
-
-
-
-
-
- );
-}
\ No newline at end of file
diff --git a/frontend-web/src/pages/UserManagement.jsx b/frontend-web/src/pages/UserManagement.jsx
deleted file mode 100644
index 518c5673..00000000
--- a/frontend-web/src/pages/UserManagement.jsx
+++ /dev/null
@@ -1,596 +0,0 @@
-import React, { useState, useMemo } from "react";
-import { base44 } from "@/api/base44Client";
-import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
-import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
-import { Button } from "@/components/ui/button";
-import { Input } from "@/components/ui/input";
-import { Label } from "@/components/ui/label";
-import { Badge } from "@/components/ui/badge";
-import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
-import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
-import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog";
-import {
- Users, UserPlus, Mail, Shield, Building2, Edit, Trash2, Search,
- Filter, MoreVertical, Eye, Key, UserCheck, UserX, Layers,
- Phone, Calendar, Clock, CheckCircle2, XCircle, AlertCircle
-} from "lucide-react";
-import { useToast } from "@/components/ui/use-toast";
-import UserPermissionsModal from "@/components/permissions/UserPermissionsModal";
-import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
-import {
- DropdownMenu,
- DropdownMenuContent,
- DropdownMenuItem,
- DropdownMenuSeparator,
- DropdownMenuTrigger,
-} from "@/components/ui/dropdown-menu";
-
-// Layer configuration
-const LAYERS = [
- { id: "all", name: "All Users", icon: Users, color: "bg-slate-600" },
- { id: "admin", name: "Admins", icon: Shield, color: "bg-red-600" },
- { id: "procurement", name: "Procurement", icon: Building2, color: "bg-blue-600" },
- { id: "operator", name: "Operators", icon: Building2, color: "bg-emerald-600" },
- { id: "sector", name: "Sectors", icon: Layers, color: "bg-purple-600" },
- { id: "client", name: "Clients", icon: Users, color: "bg-green-600" },
- { id: "vendor", name: "Vendors", icon: Building2, color: "bg-amber-600" },
- { id: "workforce", name: "Workforce", icon: Users, color: "bg-slate-500" },
-];
-
-const ROLE_CONFIG = {
- admin: { name: "Administrator", color: "bg-red-100 text-red-700 border-red-200", bgGradient: "from-red-500 to-red-700" },
- procurement: { name: "Procurement", color: "bg-blue-100 text-blue-700 border-blue-200", bgGradient: "from-blue-500 to-blue-700" },
- operator: { name: "Operator", color: "bg-emerald-100 text-emerald-700 border-emerald-200", bgGradient: "from-emerald-500 to-emerald-700" },
- sector: { name: "Sector Manager", color: "bg-purple-100 text-purple-700 border-purple-200", bgGradient: "from-purple-500 to-purple-700" },
- client: { name: "Client", color: "bg-green-100 text-green-700 border-green-200", bgGradient: "from-green-500 to-green-700" },
- vendor: { name: "Vendor", color: "bg-amber-100 text-amber-700 border-amber-200", bgGradient: "from-amber-500 to-amber-700" },
- workforce: { name: "Workforce", color: "bg-slate-100 text-slate-700 border-slate-200", bgGradient: "from-slate-500 to-slate-700" },
-};
-
-export default function UserManagement() {
- const [showInviteDialog, setShowInviteDialog] = useState(false);
- const [activeLayer, setActiveLayer] = useState("all");
- const [searchTerm, setSearchTerm] = useState("");
- const [inviteData, setInviteData] = useState({
- email: "",
- full_name: "",
- user_role: "workforce",
- company_name: "",
- phone: "",
- department: ""
- });
-
- const [selectedUser, setSelectedUser] = useState(null);
- const [showPermissionsModal, setShowPermissionsModal] = useState(false);
- const [showUserDetailModal, setShowUserDetailModal] = useState(false);
-
- const queryClient = useQueryClient();
- const { toast } = useToast();
-
- const { data: users = [] } = useQuery({
- queryKey: ['all-users'],
- queryFn: async () => {
- const allUsers = await base44.entities.User.list('-created_date');
- return allUsers;
- },
- initialData: [],
- });
-
- const { data: currentUser } = useQuery({
- queryKey: ['current-user'],
- queryFn: () => base44.auth.me(),
- });
-
- const updateUserMutation = useMutation({
- mutationFn: ({ userId, data }) => base44.entities.User.update(userId, data),
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ['all-users'] });
- toast({
- title: "User Updated",
- description: "User information updated successfully",
- });
- setShowPermissionsModal(false);
- setSelectedUser(null);
- },
- onError: (error) => {
- toast({
- title: "Error updating user",
- description: error.message || "Failed to update user information.",
- variant: "destructive",
- });
- }
- });
-
- // Calculate stats per layer
- const layerStats = useMemo(() => {
- const stats = {};
- LAYERS.forEach(layer => {
- if (layer.id === "all") {
- stats[layer.id] = users.length;
- } else {
- stats[layer.id] = users.filter(u => (u.user_role || u.role) === layer.id).length;
- }
- });
- return stats;
- }, [users]);
-
- // Filter users
- const filteredUsers = useMemo(() => {
- let filtered = users;
-
- if (activeLayer !== "all") {
- filtered = filtered.filter(u => (u.user_role || u.role) === activeLayer);
- }
-
- if (searchTerm) {
- const term = searchTerm.toLowerCase();
- filtered = filtered.filter(u =>
- u.full_name?.toLowerCase().includes(term) ||
- u.email?.toLowerCase().includes(term) ||
- u.company_name?.toLowerCase().includes(term)
- );
- }
-
- return filtered;
- }, [users, activeLayer, searchTerm]);
-
- const handleInviteUser = async () => {
- if (!inviteData.email || !inviteData.full_name) {
- toast({
- title: "Missing Information",
- description: "Please fill in email and full name",
- variant: "destructive"
- });
- return;
- }
-
- toast({
- title: "User Invited",
- description: `Invitation sent to ${inviteData.email}. They will receive setup instructions via email.`,
- });
-
- setShowInviteDialog(false);
- setInviteData({
- email: "",
- full_name: "",
- user_role: "workforce",
- company_name: "",
- phone: "",
- department: ""
- });
- };
-
- const handleEditPermissions = (user) => {
- setSelectedUser(user);
- setShowPermissionsModal(true);
- };
-
- const handleViewUser = (user) => {
- setSelectedUser(user);
- setShowUserDetailModal(true);
- };
-
- const handleSavePermissions = async (updatedUser) => {
- await updateUserMutation.mutateAsync({ userId: updatedUser.id, data: updatedUser });
- };
-
- const getRoleConfig = (role) => ROLE_CONFIG[role] || ROLE_CONFIG.workforce;
-
- if (currentUser?.user_role !== "admin" && currentUser?.role !== "admin") {
- return (
-
-
-
Access Denied
-
Only administrators can access user management.
-
- );
- }
-
- const sampleAvatar = "https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=400&h=400&fit=crop";
-
- return (
-
-
- {/* Header */}
-
-
-
User Management
-
Manage users across all ecosystem layers
-
-
-
-
- {/* Layer Stats Cards */}
-
- {LAYERS.map((layer) => {
- const Icon = layer.icon;
- const isActive = activeLayer === layer.id;
-
- return (
-
- );
- })}
-
-
- {/* Search and Filter */}
-
-
-
-
-
- setSearchTerm(e.target.value)}
- className="pl-10 border-slate-300"
- />
-
-
-
-
-
-
-
-
- {/* Users Grid */}
-
- {filteredUsers.map((user) => {
- const role = user.user_role || user.role || "workforce";
- const config = getRoleConfig(role);
-
- return (
-
- {/* Role Header */}
-
-
-
-
-
-
-
- {user.full_name?.charAt(0) || user.email?.charAt(0) || '?'}
-
-
-
-
-
-
-
{user.full_name || 'Unnamed User'}
-
- {config.name}
-
-
-
-
-
-
-
- handleViewUser(user)}>
-
- View Details
-
- handleEditPermissions(user)}>
-
- Edit Permissions
-
-
-
-
- Deactivate User
-
-
-
-
-
-
-
-
- {user.email}
-
- {user.company_name && (
-
-
- {user.company_name}
-
- )}
- {user.phone && (
-
-
- {user.phone}
-
- )}
-
-
-
-
- {/* Quick Actions */}
-
-
-
-
-
-
-
- );
- })}
-
-
- {filteredUsers.length === 0 && (
-
-
-
No users found
-
- {searchTerm ? "Try adjusting your search" : "No users in this layer yet"}
-
-
- )}
-
- {/* Invite User Dialog */}
-
-
- {/* User Detail Modal */}
-
-
- {/* Permissions Modal */}
-
{
- setShowPermissionsModal(false);
- setSelectedUser(null);
- }}
- onSave={handleSavePermissions}
- isSaving={updateUserMutation.isPending}
- />
-
-
- );
-}
\ No newline at end of file
diff --git a/frontend-web/src/pages/VendorCompliance.jsx b/frontend-web/src/pages/VendorCompliance.jsx
deleted file mode 100644
index d688b2aa..00000000
--- a/frontend-web/src/pages/VendorCompliance.jsx
+++ /dev/null
@@ -1,941 +0,0 @@
-import React, { useState, useMemo } from "react";
-import { base44 } from "@/api/base44Client";
-import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
-import { Card, CardContent } from "@/components/ui/card";
-import { Button } from "@/components/ui/button";
-import { Input } from "@/components/ui/input";
-import { Badge } from "@/components/ui/badge";
-import { Avatar, AvatarFallback } from "@/components/ui/avatar";
-import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/dialog";
-import { Label } from "@/components/ui/label";
-import { Progress } from "@/components/ui/progress";
-import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
-import {
- ShieldCheck, Search, Plus, Clock, CheckCircle2, XCircle, AlertTriangle,
- Upload, Eye, Activity, Filter, Users, Award, FileText, Bell, Send, Sparkles, AlertOctagon
-} from "lucide-react";
-import { format, differenceInDays, parseISO } from "date-fns";
-import { useToast } from "@/components/ui/use-toast";
-
-const COMPLIANCE_TYPES = ["Background Check", "Food Handler", "RBS"];
-
-const COMPLIANCE_CONFIG = {
- "Background Check": {
- color: "bg-purple-400",
- icon: ShieldCheck,
- label: "BG Check",
- gradient: "from-purple-500 to-purple-600"
- },
- "Food Handler": {
- color: "bg-emerald-400",
- icon: FileText,
- label: "Food",
- gradient: "from-emerald-500 to-emerald-600"
- },
- "RBS": {
- color: "bg-blue-400",
- icon: Award,
- label: "RBS",
- gradient: "from-blue-500 to-blue-600"
- },
-};
-
-const STATUS_CONFIG = {
- current: { color: "bg-cyan-400", textColor: "text-white", label: "Current" },
- expiring_soon: { color: "bg-amber-300", textColor: "text-amber-800", label: "Expiring" },
- expired: { color: "bg-red-400", textColor: "text-white", label: "Expired" },
- pending: { color: "bg-yellow-200", textColor: "text-yellow-800", label: "Pending" },
- missing: { color: "bg-slate-200", textColor: "text-slate-500", label: "Missing" },
-};
-
-export default function VendorCompliance() {
- const { toast } = useToast();
- const queryClient = useQueryClient();
- const [searchTerm, setSearchTerm] = useState("");
- const [showUploadModal, setShowUploadModal] = useState(false);
- const [selectedCell, setSelectedCell] = useState(null);
- const [showActivityPanel, setShowActivityPanel] = useState(false);
- const [statusFilter, setStatusFilter] = useState("all");
- const [certTypeFilter, setCertTypeFilter] = useState("all");
-
- const { data: user } = useQuery({
- queryKey: ['current-user-compliance'],
- queryFn: () => base44.auth.me(),
- });
-
- const { data: certifications = [] } = useQuery({
- queryKey: ['certifications'],
- queryFn: () => base44.entities.Certification.list(),
- initialData: [],
- });
-
- const { data: staff = [] } = useQuery({
- queryKey: ['staff-for-compliance'],
- queryFn: () => base44.entities.Staff.list(),
- initialData: [],
- });
-
- const userRole = user?.user_role || user?.role || "admin";
- const isVendor = userRole === "vendor";
-
- // Filter staff by vendor
- const filteredStaff = useMemo(() => {
- let result = staff;
- if (isVendor && user?.vendor_id) {
- result = result.filter(s => s.vendor_id === user.vendor_id);
- }
- if (searchTerm) {
- result = result.filter(s =>
- s.employee_name?.toLowerCase().includes(searchTerm.toLowerCase())
- );
- }
- return result;
- }, [staff, isVendor, user, searchTerm]);
-
- // Calculate status from expiry date
- const calculateStatus = (expiryDate) => {
- if (!expiryDate) return "pending";
- const days = differenceInDays(parseISO(expiryDate), new Date());
- if (days < 0) return "expired";
- if (days <= 30) return "expiring_soon";
- return "current";
- };
-
- // Build compliance matrix
- const complianceMatrix = useMemo(() => {
- const matrix = {};
-
- filteredStaff.forEach(emp => {
- matrix[emp.id] = {
- employee: emp,
- certifications: {},
- completionRate: 0,
- canWork: false,
- };
-
- COMPLIANCE_TYPES.forEach(type => {
- matrix[emp.id].certifications[type] = null;
- });
- });
-
- certifications.forEach(cert => {
- if (matrix[cert.employee_id] && COMPLIANCE_TYPES.includes(cert.certification_type)) {
- const status = calculateStatus(cert.expiry_date);
- const daysUntilExpiry = cert.expiry_date
- ? differenceInDays(parseISO(cert.expiry_date), new Date())
- : null;
- matrix[cert.employee_id].certifications[cert.certification_type] = {
- ...cert,
- status,
- days_until_expiry: daysUntilExpiry
- };
- }
- });
-
- // Calculate completion rates
- Object.values(matrix).forEach(row => {
- const certs = Object.values(row.certifications);
- const current = certs.filter(c => c && (c.status === "current" || c.status === "expiring_soon")).length;
- const hasExpired = certs.some(c => c && c.status === "expired");
- row.completionRate = Math.round((current / COMPLIANCE_TYPES.length) * 100);
- // Only block if they have an expired certification (not for missing)
- row.canWork = !hasExpired;
- });
-
- return matrix;
- }, [filteredStaff, certifications]);
-
- // Stats
- const stats = useMemo(() => {
- let total = 0, current = 0, expiring = 0, expired = 0;
-
- Object.values(complianceMatrix).forEach(row => {
- Object.values(row.certifications).forEach(cert => {
- total++;
- if (!cert) return;
- if (cert.status === "current") current++;
- else if (cert.status === "expiring_soon") expiring++;
- else if (cert.status === "expired") expired++;
- });
- });
-
- const missing = total - current - expiring - expired;
- const compliantEmployees = Object.values(complianceMatrix).filter(row => row.canWork).length;
- return { total, current, expiring, expired, missing, compliantEmployees };
- }, [complianceMatrix]);
-
- // Save certification
- const saveMutation = useMutation({
- mutationFn: async (data) => {
- if (data.id) {
- return base44.entities.Certification.update(data.id, data);
- }
- return base44.entities.Certification.create(data);
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ['certifications'] });
- setShowUploadModal(false);
- setSelectedCell(null);
- toast({ title: "✅ Certification saved" });
- },
- });
-
- const handleCellClick = (employeeId, certType, existingCert) => {
- const emp = complianceMatrix[employeeId]?.employee;
- setSelectedCell({
- employee_id: employeeId,
- employee_name: emp?.employee_name,
- vendor_id: emp?.vendor_id,
- vendor_name: emp?.vendor_name,
- certification_type: certType,
- ...existingCert,
- });
- setShowUploadModal(true);
- };
-
- const renderCell = (cert, employeeId, certType) => {
- const status = cert?.status || "missing";
- const config = STATUS_CONFIG[status];
- const typeConfig = COMPLIANCE_CONFIG[certType];
-
- return (
-
- );
- };
-
- // Filter matrix by status and cert type
- const filteredMatrix = useMemo(() => {
- let result = { ...complianceMatrix };
-
- // Filter by status
- if (statusFilter !== "all") {
- result = Object.fromEntries(
- Object.entries(result).filter(([empId, row]) => {
- const certs = Object.values(row.certifications);
- if (statusFilter === "current") return certs.some(c => c?.status === "current");
- if (statusFilter === "expiring_soon") return certs.some(c => c?.status === "expiring_soon");
- if (statusFilter === "expired") return certs.some(c => c?.status === "expired");
- if (statusFilter === "missing") return certs.some(c => !c);
- if (statusFilter === "compliant") return row.canWork;
- if (statusFilter === "blocked") return !row.canWork;
- return true;
- })
- );
- }
-
- return result;
- }, [complianceMatrix, statusFilter, certTypeFilter]);
-
- // Calculate column completion percentages
- const columnStats = useMemo(() => {
- const stats = {};
- COMPLIANCE_TYPES.forEach(type => {
- const total = Object.keys(complianceMatrix).length;
- const current = Object.values(complianceMatrix).filter(
- row => row.certifications[type]?.status === "current"
- ).length;
- stats[type] = total > 0 ? Math.round((current / total) * 100) : 0;
- });
- return stats;
- }, [complianceMatrix]);
-
- return (
-
-
- {/* Header */}
-
-
-
-
-
-
-
Compliance Tracker
-
Background Check, Food Handler & RBS certifications
-
-
-
-
-
- {filteredStaff.slice(0, 3).map((emp) => (
-
-
- {emp.employee_name?.charAt(0)}
-
-
- ))}
- {filteredStaff.length > 3 && (
-
- +{filteredStaff.length - 3}
-
- )}
-
-
-
-
-
-
- {/* Stats Bar - Clickable */}
-
-
setStatusFilter('all')}
- >
-
-
-
-
-
-
-
{filteredStaff.length}
-
Employees
-
-
-
-
-
setStatusFilter('compliant')}
- >
-
-
-
-
-
-
-
{stats.compliantEmployees}
-
Compliant
-
-
-
-
-
setStatusFilter('current')}
- >
-
-
-
-
-
-
-
{stats.current}
-
Current
-
-
-
-
-
setStatusFilter('expiring_soon')}
- >
-
-
-
-
-
{stats.expiring}
-
Expiring 30d
-
-
-
-
-
setStatusFilter('expired')}
- >
-
-
-
-
-
-
-
{stats.expired}
-
Expired
-
-
-
-
-
setStatusFilter('missing')}
- >
-
-
-
-
-
{stats.missing}
-
Missing
-
-
-
-
-
-
- {/* Main Compliance Matrix */}
-
-
- {/* Search & Filter Bar */}
-
-
-
- setSearchTerm(e.target.value)}
- className="pl-10 bg-slate-50 border-0 h-10"
- />
-
-
- {/* Status Filter */}
-
-
- {/* Certificate Type Filter */}
-
-
- {(statusFilter !== "all" || certTypeFilter !== "all") && (
-
- )}
-
-
-
-
- {/* Matrix Table */}
-
-
-
-
- |
- Employees
- |
- {COMPLIANCE_TYPES.map(type => {
- const config = COMPLIANCE_CONFIG[type];
- return (
-
-
-
-
- = 25 ? config.color : 'bg-slate-200'}`} />
- = 50 ? 'bg-amber-400' : 'bg-slate-200'}`} />
- = 75 ? 'bg-red-400' : 'bg-slate-200'}`} />
- = 100 ? 'bg-emerald-400' : 'bg-slate-200'}`} />
-
- {columnStats[type]}% complete
-
- |
- );
- })}
-
- Status
- |
-
-
-
- {Object.entries(filteredMatrix).map(([empId, row], idx) => (
-
-
-
-
-
- {row.employee.employee_name?.charAt(0)}
-
-
-
- {row.employee.employee_name}
-
-
- {row.completionRate}%
-
-
-
- |
- {COMPLIANCE_TYPES.map(type => (
-
- {renderCell(row.certifications[type], empId, type)}
- |
- ))}
-
- {row.canWork ? (
-
-
- Clear
-
- ) : (
-
-
- Blocked
-
- )}
- |
-
- ))}
-
-
-
- {filteredStaff.length === 0 && (
-
- )}
-
-
- {/* Footer */}
-
-
- Hover over cells to see expiration dates • Click to add or update certifications
-
-
-
-
-
- {/* Upload Modal */}
-
-
- {/* Activity Panel */}
- {showActivityPanel && (
-
-
-
Recent Activity
-
-
-
- {[1,2,3,4,5].map(i => (
-
-
-
-
-
-
Certification updated
-
Background Check • 2 hours ago
-
-
- ))}
-
-
- )}
-
-
- );
-}
-
-function CertificationForm({ data, onSave, onCancel, isLoading }) {
- const [formData, setFormData] = useState({
- employee_id: data.employee_id || "",
- employee_name: data.employee_name || "",
- vendor_id: data.vendor_id || "",
- vendor_name: data.vendor_name || "",
- certification_type: data.certification_type || "",
- status: data.status || "current",
- expiry_date: data.expiry_date || "",
- issuer: data.issuer || "",
- certificate_number: data.certificate_number || "",
- document_url: data.document_url || "",
- notes: data.notes || "",
- ...data,
- });
-
- const [uploading, setUploading] = useState(false);
- const [verificationResult, setVerificationResult] = useState(null);
- const [verifying, setVerifying] = useState(false);
- const [isDragging, setIsDragging] = useState(false);
-
- const processFile = async (file) => {
- if (!file) return;
-
- setUploading(true);
- setVerificationResult(null);
- try {
- const result = await base44.integrations.Core.UploadFile({ file });
- setFormData(prev => ({ ...prev, document_url: result.file_url }));
-
- // Auto-extract data and verify
- setVerifying(true);
- const extraction = await base44.integrations.Core.InvokeLLM({
- prompt: `Analyze this ${formData.certification_type} certificate image. Extract the following information and verify authenticity:
-
-1. Extract the expiration/expiry date (format as YYYY-MM-DD)
-2. Extract the issuing authority/organization name
-3. Extract the certificate/license number
-4. Check for signs of tampering or editing
-
-Return the extracted data and verification results.`,
- file_urls: [result.file_url],
- response_json_schema: {
- type: "object",
- properties: {
- expiry_date: { type: "string", description: "Expiration date in YYYY-MM-DD format, or empty if not found" },
- issuer: { type: "string", description: "Issuing authority name" },
- certificate_number: { type: "string", description: "Certificate or license number" },
- is_authentic: { type: "boolean", description: "Whether document appears authentic" },
- confidence: { type: "number", description: "Confidence score 0-100" },
- risk_level: { type: "string", enum: ["low", "medium", "high"], description: "Risk level of tampering" },
- findings: { type: "array", items: { type: "string" }, description: "List of specific findings" },
- recommendation: { type: "string", description: "Brief recommendation" }
- }
- }
- });
-
- // Auto-fill extracted fields
- setFormData(prev => ({
- ...prev,
- expiry_date: extraction.expiry_date || prev.expiry_date,
- issuer: extraction.issuer || prev.issuer,
- certificate_number: extraction.certificate_number || prev.certificate_number,
- }));
-
- setVerificationResult(extraction);
- setVerifying(false);
- } catch (error) {
- console.error("Upload/verification failed:", error);
- setVerifying(false);
- }
- setUploading(false);
- };
-
- const handleFileUpload = (e) => {
- processFile(e.target.files?.[0]);
- };
-
- const handleDrop = (e) => {
- e.preventDefault();
- setIsDragging(false);
- const file = e.dataTransfer.files?.[0];
- if (file && (file.type.includes('image') || file.type === 'application/pdf')) {
- processFile(file);
- }
- };
-
- const handleDragOver = (e) => {
- e.preventDefault();
- setIsDragging(true);
- };
-
- const handleDragLeave = (e) => {
- e.preventDefault();
- setIsDragging(false);
- };
-
- const config = COMPLIANCE_CONFIG[formData.certification_type];
-
- return (
-
-
-
- {config &&
}
-
-
{formData.certification_type}
-
{formData.employee_name}
-
-
-
-
- {/* Drag & Drop Upload Area */}
-
-
-
document.getElementById('cert-upload').click()}
- >
-
- {uploading || verifying ? (
-
-
-
{uploading ? 'Uploading...' : 'AI Extracting Data...'}
-
- ) : formData.document_url ? (
-
-
- Certificate uploaded
-
- ) : (
-
-
-
Drag & drop or click to upload
-
PDF, JPG, PNG • AI will auto-extract details
-
- )}
-
-
-
- {/* Expiry Date - Primary field */}
-
-
- setFormData(prev => ({ ...prev, expiry_date: e.target.value }))}
- className="mt-1.5"
- required
- />
-
-
- {/* Auto-detected fields */}
-
-
- {/* AI Verification Result */}
- {verificationResult && (
-
-
-
- {verificationResult.risk_level === 'low' ? (
-
- ) : verificationResult.risk_level === 'medium' ? (
-
- ) : (
-
- )}
-
-
-
-
- AI Verification
-
- {verificationResult.confidence}% confidence
-
-
-
- {verificationResult.is_authentic ? 'Document appears authentic' : 'Potential issues detected'}
-
-
{verificationResult.recommendation}
-
- {verificationResult.findings?.length > 0 && (
-
- {verificationResult.findings.map((finding, idx) => (
-
- • {finding}
-
- ))}
-
- )}
-
-
-
- )}
-
-
-
-
-
-
- );
-}
\ No newline at end of file
diff --git a/frontend-web/src/pages/VendorDashboard.jsx b/frontend-web/src/pages/VendorDashboard.jsx
deleted file mode 100644
index 1a77f74a..00000000
--- a/frontend-web/src/pages/VendorDashboard.jsx
+++ /dev/null
@@ -1,1166 +0,0 @@
-import React, { useState, useMemo, useEffect } from "react";
-import { base44 } from "@/api/base44Client";
-import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
-import { Link, useNavigate } from "react-router-dom";
-import { createPageUrl } from "@/utils";
-import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
-import { Badge } from "@/components/ui/badge";
-import { Button } from "@/components/ui/button";
-import { Avatar, AvatarFallback } from "@/components/ui/avatar";
-import {
- DropdownMenu,
- DropdownMenuContent,
- DropdownMenuItem,
- DropdownMenuTrigger,
-} from "@/components/ui/dropdown-menu";
-import {
- Dialog,
- DialogContent,
- DialogHeader,
- DialogTitle,
-} from "@/components/ui/dialog";
-import { Award, TrendingUp, Users, DollarSign, Calendar, Package, Timer, Zap, Send, RefreshCw, Copy, Eye, MoreHorizontal, Star, Trophy, FileText, CheckCircle, ArrowRight, Target, Activity, Clock, Building2, MapPin, Play, Pause, UserCheck, Settings, GripVertical, Minus, Plus, Check, X, RotateCcw, Edit2 } from "lucide-react";
-import { format, differenceInHours, parseISO, startOfDay, isSameDay, addDays } from "date-fns";
-import { useToast } from "@/components/ui/use-toast";
-import { motion, AnimatePresence } from "framer-motion";
-import { DragDropContext, Droppable, Draggable } from "@hello-pangea/dnd";
-import SmartAssignModal from "@/components/events/SmartAssignModal";
-import ClientLoyaltyCard from "@/components/vendor/ClientLoyaltyCard";
-
-const convertTo12Hour = (time24) => {
- if (!time24 || time24 === "—") return time24;
- try {
- const parts = time24.split(':');
- if (!parts || parts.length < 2) return time24;
- const hours = parseInt(parts[0], 10);
- const minutes = parseInt(parts[1], 10);
- if (isNaN(hours) || isNaN(minutes)) return time24;
- const period = hours >= 12 ? 'PM' : 'AM';
- const hours12 = hours % 12 || 12;
- const minutesStr = minutes.toString().padStart(2, '0');
- return `${hours12}:${minutesStr} ${period}`;
- } catch (error) {
- return time24;
- }
-};
-
-const isDateToday = (dateValue) => {
- if (!dateValue) return false;
- try {
- let dateObj;
- if (typeof dateValue === 'string') {
- dateObj = parseISO(dateValue);
- if (isNaN(dateObj.getTime())) {
- dateObj = new Date(dateValue);
- }
- } else if (dateValue instanceof Date) {
- dateObj = dateValue;
- } else {
- return false;
- }
- if (isNaN(dateObj.getTime())) return false;
- const today = startOfDay(new Date());
- const compareDate = startOfDay(dateObj);
- return isSameDay(today, compareDate);
- } catch (error) {
- return false;
- }
-};
-
-const isDateTomorrow = (dateValue) => {
- if (!dateValue) return false;
- try {
- let dateObj;
- if (typeof dateValue === 'string') {
- dateObj = parseISO(dateValue);
- if (isNaN(dateObj.getTime())) {
- dateObj = new Date(dateValue);
- }
- } else if (dateValue instanceof Date) {
- dateObj = dateValue;
- } else {
- return false;
- }
- if (isNaN(dateObj.getTime())) return false;
- const tomorrow = startOfDay(addDays(new Date(), 1));
- const compareDate = startOfDay(dateObj);
- return isSameDay(tomorrow, compareDate);
- } catch (error) {
- return false;
- }
-};
-
-const AVAILABLE_WIDGETS = [
- {
- id: 'kpi-cards',
- title: 'KPI Cards',
- description: 'Orders Today, In Progress, RAPID, Staff Assigned',
- category: 'Metrics',
- categoryColor: 'bg-blue-100 text-blue-700',
- },
- {
- id: 'orders-table',
- title: 'Recent Orders',
- description: 'View and manage recent orders',
- category: 'Orders',
- categoryColor: 'bg-green-100 text-green-700',
- },
- {
- id: 'revenue-carousel',
- title: 'Revenue Stats',
- description: 'Monthly revenue, total, active orders',
- category: 'Analytics',
- categoryColor: 'bg-purple-100 text-purple-700',
- },
- {
- id: 'top-clients',
- title: 'Top Clients',
- description: 'Best performing clients by revenue',
- category: 'Analytics',
- categoryColor: 'bg-amber-100 text-amber-700',
- },
- {
- id: 'client-loyalty',
- title: 'Client Loyalty',
- description: 'See which clients are loyal vs at-risk',
- category: 'Insights',
- categoryColor: 'bg-pink-100 text-pink-700',
- },
- {
- id: 'top-performers',
- title: 'Top Performers',
- description: 'Highest rated staff members',
- category: 'Staff',
- categoryColor: 'bg-green-100 text-green-700',
- },
- {
- id: 'gold-vendors',
- title: 'Gold Vendors',
- description: 'Premier vendor partners',
- category: 'Partners',
- categoryColor: 'bg-amber-100 text-amber-700',
- },
- {
- id: 'quick-actions',
- title: 'Quick Actions',
- description: 'All Orders, My Staff shortcuts',
- category: 'Actions',
- categoryColor: 'bg-blue-100 text-blue-700',
- }
-];
-
-export default function VendorDashboard() {
- const navigate = useNavigate();
- const queryClient = useQueryClient();
- const { toast } = useToast();
- const [showRapidModal, setShowRapidModal] = useState(false);
- const [carouselIndex, setCarouselIndex] = useState(0);
- const [autoRotate, setAutoRotate] = useState(true);
- const [widgetOrder, setWidgetOrder] = useState(AVAILABLE_WIDGETS.map(w => w.id));
- const [hiddenWidgets, setHiddenWidgets] = useState([]);
- const [isCustomizing, setIsCustomizing] = useState(false);
- const [hasChanges, setHasChanges] = useState(false);
- const [assignModal, setAssignModal] = useState({ open: false, event: null });
-
- const { data: user } = useQuery({
- queryKey: ['current-user-vendor'],
- queryFn: () => base44.auth.me(),
- });
-
- useEffect(() => {
- if (user?.dashboard_layout_vendor?.widgets) {
- setWidgetOrder(user.dashboard_layout_vendor.widgets);
- setHiddenWidgets(user.dashboard_layout_vendor.hidden_widgets || []);
- }
- }, [user]);
-
- const { data: events } = useQuery({
- queryKey: ['vendor-events'],
- queryFn: async () => {
- const allEvents = await base44.entities.Event.list('-date');
- if (!user?.email) return [];
- return allEvents.filter(e =>
- e.vendor_name === user?.company_name ||
- e.vendor_id === user?.id ||
- e.created_by === user?.email
- );
- },
- initialData: [],
- enabled: !!user
- });
-
- const { data: staff } = useQuery({
- queryKey: ['vendor-staff'],
- queryFn: async () => {
- const allStaff = await base44.entities.Staff.list();
- if (!user?.company_name) return allStaff.slice(0, 10);
- return allStaff.filter(s => s.vendor_name === user?.company_name);
- },
- initialData: [],
- enabled: !!user
- });
-
- useEffect(() => {
- if (!autoRotate) return;
- const interval = setInterval(() => {
- setCarouselIndex(prev => (prev + 1) % 4);
- }, 4000);
- return () => clearInterval(interval);
- }, [autoRotate]);
-
- const saveLayoutMutation = useMutation({
- mutationFn: async (layoutData) => {
- await base44.auth.updateMe({
- dashboard_layout_vendor: layoutData
- });
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ['current-user-vendor'] });
- toast({
- title: "✅ Layout Saved",
- description: "Your dashboard layout has been updated",
- });
- setHasChanges(false);
- setIsCustomizing(false);
- },
- });
-
- const todayOrders = events.filter(e => {
- if (e.status === "Canceled") return false;
- return isDateToday(e.date);
- });
-
- const tomorrowOrders = events.filter(e => {
- if (e.status === "Canceled") return false;
- return isDateTomorrow(e.date);
- });
-
- const todayAndTomorrowOrders = [...todayOrders, ...tomorrowOrders].sort((a, b) => new Date(a.date) - new Date(b.date));
-
- const inProgressOrders = events.filter(e =>
- e.status === "Active" || e.status === "Confirmed" || e.status === "In Progress"
- );
-
- const completedOrders = events.filter(e => e.status === "Completed");
- const totalRevenue = completedOrders.reduce((sum, e) => sum + (e.total || 0), 0);
-
- const currentMonth = new Date().getMonth();
- const currentYear = new Date().getFullYear();
- const thisMonthOrders = events.filter(e => {
- const eventDate = new Date(e.date);
- return eventDate.getMonth() === currentMonth &&
- eventDate.getFullYear() === currentYear &&
- (e.status === "Completed" || e.status === "Active");
- });
- const thisMonthRevenue = thisMonthOrders.reduce((sum, e) => sum + (e.total || 0), 0);
-
- const activeStaff = staff.filter(s => s.employment_type !== "Medical Leave" && s.action !== "Inactive").length;
-
- const staffAssignedToday = todayOrders.reduce((sum, e) => sum + (e.requested || 0), 0);
- const staffAssignedTodayCompleted = todayOrders.reduce((sum, e) => {
- const assignedCount = e.assigned_staff?.length || 0;
- return sum + assignedCount;
- }, 0);
-
- const rapidOrders = events.filter(e => {
- const eventDate = new Date(e.date);
- const now = new Date();
- const hoursUntil = differenceInHours(eventDate, now);
- return hoursUntil > 0 && hoursUntil <= 24 &&
- (e.status === "Active" || e.status === "Confirmed" || e.status === "Pending");
- });
-
- const inProgressTotal = inProgressOrders.length;
- const inProgressStaffed = inProgressOrders.filter(e => {
- const assignedCount = e.assigned_staff?.length || 0;
- const requestedCount = e.requested || 0;
- return requestedCount > 0 && assignedCount >= requestedCount;
- }).length;
- const inProgressCompletion = inProgressTotal > 0 ? Math.round((inProgressStaffed / inProgressTotal) * 100) : 0;
-
- const clientRevenue = completedOrders.reduce((acc, event) => {
- const client = event.business_name || "Unknown";
- if (!acc[client]) {
- acc[client] = { name: client, revenue: 0, orders: 0 };
- }
- acc[client].revenue += (event.total || 0);
- acc[client].orders++;
- return acc;
- }, {});
-
- const topClients = Object.values(clientRevenue)
- .sort((a, b) => b.revenue - a.revenue)
- .slice(0, 3);
-
- const topPerformers = staff
- .filter(s => s.rating > 0)
- .sort((a, b) => (b.rating || 0) - (a.rating || 0))
- .slice(0, 3)
- .map(s => ({
- ...s,
- shifts: s.total_shifts || Math.floor(Math.random() * 30) + 5
- }));
-
- const hour = new Date().getHours();
- const greeting = hour < 12 ? "Good morning" : hour < 18 ? "Good afternoon" : "Good evening";
-
- const getOrderStatusBadge = (order) => {
- const assignedCount = order.assigned_staff?.length || 0;
- const requestedCount = order.requested || 0;
-
- if (order.is_rapid === true || order.event_name?.includes('RAPID')) {
- return
RAPID;
- }
-
- if (order.status === "Canceled") {
- return
Canceled;
- }
-
- if (assignedCount >= requestedCount && requestedCount > 0) {
- return
Fully Staffed;
- }
-
- if (order.status === "Pending") {
- return
Pending;
- }
-
- if (order.status === "Assigned") {
- return
Assigned;
- }
-
- return
{order.status || "Active"};
- };
-
- const getShiftTimes = (order) => {
- if (order.shifts && order.shifts.length > 0) {
- const shift = order.shifts[0];
- if (shift.roles && shift.roles.length > 0) {
- const role = shift.roles[0];
- const startTime = convertTo12Hour(role.start_time) || "—";
- const endTime = convertTo12Hour(role.end_time) || "—";
- return { startTime, endTime };
- }
- }
- return { startTime: "—", endTime: "—" };
- };
-
- const handleSendNotification = (order) => {
- toast({
- title: "Notification Sent",
- description: `Notification sent for order: ${order.event_name}`,
- });
- };
-
- const handleAssignStaff = (order) => {
- setAssignModal({ open: true, event: order });
- };
-
- const handleViewOrder = (order) => {
- navigate(createPageUrl(`EventDetail?id=${order.id}`));
- };
-
- const handleCopyOrder = (order) => {
- navigator.clipboard.writeText(order.id);
- toast({
- title: "Order ID Copied",
- description: `Order ID ${order.id} copied to clipboard`,
- });
- };
-
- const handleRapidClick = () => {
- if (rapidOrders.length === 0) {
- toast({
- title: "No Urgent Orders",
- description: "There are currently no rapid orders.",
- });
- } else if (rapidOrders.length === 1) {
- navigate(createPageUrl(`EventDetail?id=${rapidOrders[0].id}`));
- } else {
- setShowRapidModal(true);
- }
- };
-
- const handleDragEnd = (result) => {
- if (!result.destination) return;
-
- const items = Array.from(widgetOrder);
- const [reorderedItem] = items.splice(result.source.index, 1);
- items.splice(result.destination.index, 0, reorderedItem);
-
- setWidgetOrder(items);
- setHasChanges(true);
- };
-
- const handleRemoveWidget = (widgetId) => {
- setHiddenWidgets([...hiddenWidgets, widgetId]);
- setHasChanges(true);
- };
-
- const handleAddWidget = (widgetId) => {
- setHiddenWidgets(hiddenWidgets.filter(id => id !== widgetId));
- setHasChanges(true);
- };
-
- const handleSaveLayout = () => {
- saveLayoutMutation.mutate({
- widgets: widgetOrder,
- hidden_widgets: hiddenWidgets,
- layout_version: "2.0"
- });
- };
-
- const handleCancelCustomize = () => {
- if (user?.dashboard_layout_vendor) {
- setWidgetOrder(user.dashboard_layout_vendor.widgets || AVAILABLE_WIDGETS.map(w => w.id));
- setHiddenWidgets(user.dashboard_layout_vendor.hidden_widgets || []);
- }
- setIsCustomizing(false);
- setHasChanges(false);
- };
-
- const handleResetLayout = () => {
- setWidgetOrder(AVAILABLE_WIDGETS.map(w => w.id));
- setHiddenWidgets([]);
- setHasChanges(true);
- };
-
- const carouselSlides = [
- {
- title: "This Month",
- value: `$${Math.round(thisMonthRevenue / 1000)}k`,
- subtitle: `${thisMonthOrders.length} orders completed`,
- icon: TrendingUp,
- color: "from-emerald-500 via-emerald-600 to-emerald-700"
- },
- {
- title: "Total Revenue",
- value: `$${Math.round(totalRevenue / 1000)}k`,
- subtitle: "All time earnings",
- icon: DollarSign,
- color: "from-[#0A39DF] via-blue-700 to-[#1C323E]"
- },
- {
- title: "Active Orders",
- value: `${inProgressOrders.length}`,
- subtitle: `${inProgressCompletion}% staffed`,
- icon: Activity,
- color: "from-purple-500 via-purple-600 to-purple-700"
- },
- {
- title: "Avg Fill Time",
- value: "1h 12m",
- subtitle: "14m faster than last week",
- icon: Clock,
- color: "from-indigo-500 via-indigo-600 to-blue-700"
- }
- ];
-
- const visibleWidgetIds = widgetOrder.filter(id => !hiddenWidgets.includes(id));
- const availableToAdd = AVAILABLE_WIDGETS.filter(w => hiddenWidgets.includes(w.id));
-
- const renderKPICards = () => (
-
-
-
-
- {todayOrders.length}
- Active
-
-
-
-
-
-
- {inProgressOrders.length}
-
- {inProgressCompletion}%
- Coverage
-
-
-
-
-
!isCustomizing && handleRapidClick()}
- >
-
-
-
URGENT
- {rapidOrders.length > 0 ? (
-
- {rapidOrders.length}
-
- ) : (
-
- 0
-
- )}
-
-
-
-
-
-
-
-
- {staffAssignedToday}
- {staffAssignedTodayCompleted}/{staffAssignedToday} filled
-
-
-
- );
-
- const renderTodayAndTomorrowOrders = () => (
-
-
-
-
-
-
-
-
-
Today & Tomorrow Orders
-
- {format(new Date(), 'EEEE, MMMM d')} - {format(addDays(new Date(), 1), 'EEEE, MMMM d, yyyy')}
-
-
-
-
- {todayAndTomorrowOrders.length} Orders
-
-
-
-
- {todayAndTomorrowOrders.length > 0 ? (
-
-
-
-
- | BUSINESS |
- HUB |
- EVENT |
- DATE & TIME |
- STATUS |
- REQUESTED |
- ASSIGNED |
- INVOICE |
- ACTIONS |
-
-
-
- {todayAndTomorrowOrders.map((order, index) => {
- const assignedCount = order.assigned_staff?.length || 0;
- const requestedCount = order.requested || 0;
- const { startTime, endTime } = getShiftTimes(order);
- const isLastRow = index === todayAndTomorrowOrders.length - 1;
- const percentage = requestedCount > 0 ? Math.round((assignedCount / requestedCount) * 100) : 0;
- const invoiceReady = order.status === "Completed";
-
- return (
-
- |
-
- {order.business_name || "Sports Arena LLC"}
-
- |
-
-
-
- {order.hub || order.event_location || "Main Hub"}
-
- |
-
-
- {order.event_name}
-
- |
-
-
-
- {order.date ? format(new Date(order.date), 'MM.dd.yyyy') : "—"}
-
-
- {order.date ? format(new Date(order.date), 'EEEE') : "—"}
-
-
-
- {startTime} - {endTime}
-
-
- |
-
- {getOrderStatusBadge(order)}
- |
-
-
- {requestedCount}
-
- |
-
-
- {assignedCount}
-
- {percentage}%
-
-
- |
-
-
- |
-
-
-
-
-
-
- |
-
- );
- })}
-
-
-
- ) : (
-
-
-
No orders for today or tomorrow
-
- )}
-
-
- );
-
- const renderRevenueCarousel = () => (
-
-
-
-
-
- {carouselSlides.map((_, index) => (
-
-
-
-
-
- {React.createElement(carouselSlides[carouselIndex].icon, {
- className: "w-6 h-6 text-white/80"
- })}
-
- {carouselSlides[carouselIndex].title}
-
-
-
- {carouselSlides[carouselIndex].value}
-
-
- {carouselSlides[carouselIndex].subtitle}
-
-
-
-
-
- );
-
- const renderTopClients = () => (
-
-
-
-
- Top Clients
-
-
-
- {topClients.length > 0 ? (
- topClients.map((client, idx) => (
-
-
-
- {idx + 1}
-
-
-
{client.name}
-
+{client.orders}% growth
-
-
-
${(client.revenue / 1000).toFixed(0)}k
-
- ))
- ) : (
- No data
- )}
-
-
- );
-
- const renderTopPerformers = () => (
-
-
-
-
- Top Performers
-
-
-
- {topPerformers.length > 0 ? (
- topPerformers.map((member, idx) => (
-
-
-
- {idx + 1}
-
-
-
{member.employee_name}
-
{member.shifts} shifts
-
-
-
- {(member.rating || 0).toFixed(1)}
-
-
-
- ))
- ) : (
- No data
- )}
-
-
- );
-
- const renderClientLoyalty = () => (
-
- );
-
- const renderGoldVendors = () => (
-
-
-
-
- Gold Vendors
-
-
-
-
-
-
- );
-
- const renderQuickActions = () => (
-
-
-
-
-
- All Orders
-
-
-
-
-
-
-
-
-
-
- My Staff
-
-
-
-
- );
-
- const renderWidget = (widgetId) => {
- switch (widgetId) {
- case 'kpi-cards':
- return renderKPICards();
- case 'orders-table':
- return renderTodayAndTomorrowOrders();
- case 'revenue-carousel':
- return renderRevenueCarousel();
- case 'top-clients':
- return renderTopClients();
- case 'top-performers':
- return renderTopPerformers();
- case 'client-loyalty':
- return renderClientLoyalty();
- case 'gold-vendors':
- return renderGoldVendors();
- case 'quick-actions':
- return renderQuickActions();
- default:
- return null;
- }
- };
-
- return (
-
-
-
-
-
-
-
- {greeting} here's what matters today
-
-
-
- {isCustomizing && hasChanges && (
-
- Unsaved Changes
-
- )}
- {isCustomizing ? (
- <>
-
-
-
- >
- ) : (
-
- )}
-
-
-
-
-
- {(provided) => (
-
- {visibleWidgetIds.map((widgetId, index) => {
- const widget = AVAILABLE_WIDGETS.find(w => w.id === widgetId);
- if (!widget) return null;
-
- if (widgetId !== 'kpi-cards') {
- return null;
- }
-
- return (
-
- {(provided, snapshot) => (
-
- {isCustomizing && (
- <>
-
-
-
-
- >
- )}
-
- {renderWidget(widgetId)}
-
-
- )}
-
- );
- })}
- {provided.placeholder}
-
- )}
-
-
-
- {visibleWidgetIds.includes('orders-table') && (
-
- {isCustomizing && (
-
- )}
- {renderWidget('orders-table')}
-
- )}
-
- {(visibleWidgetIds.includes('revenue-carousel') || visibleWidgetIds.includes('top-clients') || visibleWidgetIds.includes('top-performers') || visibleWidgetIds.includes('client-loyalty') || visibleWidgetIds.includes('gold-vendors') || visibleWidgetIds.includes('quick-actions')) && (
-
- {(visibleWidgetIds.includes('revenue-carousel') || visibleWidgetIds.includes('quick-actions')) && (
-
- {visibleWidgetIds.includes('revenue-carousel') && (
-
- {isCustomizing && (
-
- )}
- {renderWidget('revenue-carousel')}
-
- )}
- {visibleWidgetIds.includes('quick-actions') && (
-
- {isCustomizing && (
-
- )}
- {renderWidget('quick-actions')}
-
- )}
-
- )}
-
- {(visibleWidgetIds.includes('top-clients') || visibleWidgetIds.includes('top-performers') || visibleWidgetIds.includes('client-loyalty') || visibleWidgetIds.includes('gold-vendors')) && (
-
- {visibleWidgetIds.includes('top-clients') && (
-
- {isCustomizing && (
-
- )}
- {renderWidget('top-clients')}
-
- )}
- {visibleWidgetIds.includes('top-performers') && (
-
- {isCustomizing && (
-
- )}
- {renderWidget('top-performers')}
-
- )}
- {visibleWidgetIds.includes('client-loyalty') && (
-
- {isCustomizing && (
-
- )}
- {renderWidget('client-loyalty')}
-
- )}
- {visibleWidgetIds.includes('gold-vendors') && (
-
- {isCustomizing && (
-
- )}
- {renderWidget('gold-vendors')}
-
- )}
-
- )}
-
- )}
-
- {isCustomizing && availableToAdd.length > 0 && (
-
-
-
-
Add Widgets
-
{availableToAdd.length} available
-
-
- {availableToAdd.map((widget) => (
-
- ))}
-
-
- )}
-
-
-
- );
-}
diff --git a/frontend-web/src/pages/VendorMarketplace.jsx b/frontend-web/src/pages/VendorMarketplace.jsx
deleted file mode 100644
index b305709b..00000000
--- a/frontend-web/src/pages/VendorMarketplace.jsx
+++ /dev/null
@@ -1,1006 +0,0 @@
-import React, { useState, useMemo } from "react";
-import { base44 } from "@/api/base44Client";
-import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
-import { Link, useNavigate } from "react-router-dom";
-import { createPageUrl } from "@/utils";
-import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
-import { Button } from "@/components/ui/button";
-import { Badge } from "@/components/ui/badge";
-import { Input } from "@/components/ui/input";
-import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
-import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
-} from "@/components/ui/select";
-import {
- Dialog,
- DialogContent,
- DialogHeader,
- DialogTitle,
- DialogDescription,
- DialogFooter,
-} from "@/components/ui/dialog";
-import {
- Collapsible,
- CollapsibleContent,
- CollapsibleTrigger,
-} from "@/components/ui/collapsible";
-import { Textarea } from "@/components/ui/textarea";
-import { Search, MapPin, Users, Star, DollarSign, TrendingUp, MessageSquare, CheckCircle, Award, Filter, Grid, List, Phone, Mail, Building2, Zap, ArrowRight, ChevronDown, ChevronUp, UserCheck, Briefcase, Shield, Crown, X, Edit2, Clock, Target, Handshake, Settings } from "lucide-react";
-import { useToast } from "@/components/ui/use-toast";
-import ClientVendorPreferences from "@/components/vendor/ClientVendorPreferences";
-
-export default function VendorMarketplace() {
- const navigate = useNavigate();
- const { toast } = useToast();
- const queryClient = useQueryClient();
- const [searchTerm, setSearchTerm] = useState("");
- const [regionFilter, setRegionFilter] = useState("all");
- const [categoryFilter, setCategoryFilter] = useState("all");
- const [sortBy, setSortBy] = useState("rating");
- const [viewMode, setViewMode] = useState("grid");
- const [contactModal, setContactModal] = useState({ open: false, vendor: null });
- const [message, setMessage] = useState("");
- const [expandedVendors, setExpandedVendors] = useState({});
-
- const { data: user } = useQuery({
- queryKey: ['current-user-marketplace'],
- queryFn: () => base44.auth.me(),
- });
-
- const { data: vendors = [] } = useQuery({
- queryKey: ['approved-vendors'],
- queryFn: async () => {
- const allVendors = await base44.entities.Vendor.list();
- return allVendors.filter(v => v.approval_status === 'approved' && v.is_active);
- },
- });
-
- const { data: vendorRates = [] } = useQuery({
- queryKey: ['vendor-rates-marketplace'],
- queryFn: () => base44.entities.VendorRate.list(),
- });
-
- const { data: staff = [] } = useQuery({
- queryKey: ['vendor-staff-count'],
- queryFn: () => base44.entities.Staff.list(),
- });
-
- const { data: events = [] } = useQuery({
- queryKey: ['events-vendor-marketplace'],
- queryFn: () => base44.entities.Event.list(),
- initialData: [],
- });
-
- const { data: businesses = [] } = useQuery({
- queryKey: ['businesses-vendor-marketplace'],
- queryFn: () => base44.entities.Business.list(),
- initialData: [],
- });
-
- const vendorsWithMetrics = useMemo(() => {
- return vendors.map(vendor => {
- const rates = vendorRates.filter(r => r.vendor_name === vendor.legal_name || r.vendor_id === vendor.id);
- const vendorStaff = staff.filter(s => s.vendor_name === vendor.legal_name);
-
- const avgRate = rates.length > 0
- ? rates.reduce((sum, r) => sum + (r.client_rate || 0), 0) / rates.length
- : 0;
-
- const minRate = rates.length > 0
- ? Math.min(...rates.map(r => r.client_rate || 999))
- : 0;
-
- const rating = 4.5 + (Math.random() * 0.5);
- const completedJobs = Math.floor(Math.random() * 200) + 50;
-
- const vendorEvents = events.filter(e =>
- e.vendor_name === vendor.legal_name ||
- e.vendor_id === vendor.id
- );
-
- const uniqueClients = new Set(
- vendorEvents.map(e => e.business_name || e.client_email)
- ).size;
-
- const userSector = user?.sector || user?.company_name;
- const sectorClients = businesses.filter(b =>
- b.sector === userSector || b.area === user?.area
- );
-
- const clientsInSector = new Set(
- vendorEvents
- .filter(e => sectorClients.some(sc =>
- sc.business_name === e.business_name ||
- sc.contact_name === e.client_name
- ))
- .map(e => e.business_name || e.client_email)
- ).size;
-
- const ratesByCategory = rates.reduce((acc, rate) => {
- const category = rate.category || 'Other';
- if (!acc[category]) {
- acc[category] = [];
- }
- acc[category].push(rate);
- return acc;
- }, {});
-
- return {
- ...vendor,
- rates,
- ratesByCategory,
- avgRate,
- minRate,
- rating,
- completedJobs,
- staffCount: vendorStaff.length,
- responseTime: `${Math.floor(Math.random() * 3) + 1}h`,
- totalClients: uniqueClients,
- clientsInSector: clientsInSector,
- };
- });
- }, [vendors, vendorRates, staff, events, businesses, user]);
-
- const filteredVendors = useMemo(() => {
- let filtered = vendorsWithMetrics;
-
- if (searchTerm) {
- const lower = searchTerm.toLowerCase();
- filtered = filtered.filter(v =>
- v.legal_name?.toLowerCase().includes(lower) ||
- v.doing_business_as?.toLowerCase().includes(lower) ||
- v.service_specialty?.toLowerCase().includes(lower)
- );
- }
-
- if (regionFilter !== "all") {
- filtered = filtered.filter(v => v.region === regionFilter);
- }
-
- if (categoryFilter !== "all") {
- filtered = filtered.filter(v => v.service_specialty === categoryFilter);
- }
-
- filtered.sort((a, b) => {
- switch (sortBy) {
- case "rating":
- return b.rating - a.rating;
- case "price-low":
- return a.minRate - b.minRate;
- case "price-high":
- return b.avgRate - a.avgRate;
- case "staff":
- return b.staffCount - a.staffCount;
- default:
- return 0;
- }
- });
-
- return filtered;
- }, [vendorsWithMetrics, searchTerm, regionFilter, categoryFilter, sortBy]);
-
- const preferredVendor = vendorsWithMetrics.find(v => v.id === user?.preferred_vendor_id);
- const otherVendors = filteredVendors.filter(v => v.id !== user?.preferred_vendor_id);
-
- const uniqueRegions = [...new Set(vendors.map(v => v.region).filter(Boolean))];
- const uniqueCategories = [...new Set(vendors.map(v => v.service_specialty).filter(Boolean))];
-
- const setPreferredMutation = useMutation({
- mutationFn: (vendor) => base44.auth.updateMe({
- preferred_vendor_id: vendor.id,
- preferred_vendor_name: vendor.legal_name || vendor.doing_business_as
- }),
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ['current-user'] });
- queryClient.invalidateQueries({ queryKey: ['current-user-marketplace'] });
- toast({
- title: "✅ Preferred Vendor Set",
- description: "All new orders will route to this vendor by default",
- });
- },
- });
-
- const removePreferredMutation = useMutation({
- mutationFn: () => base44.auth.updateMe({
- preferred_vendor_id: null,
- preferred_vendor_name: null
- }),
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ['current-user'] });
- toast({
- title: "✅ Preferred Vendor Removed",
- description: "You can now select a new preferred vendor",
- });
- },
- });
-
- const handleContactVendor = (vendor) => {
- setContactModal({ open: true, vendor });
- setMessage(`Hi ${vendor.legal_name},\n\nI'm interested in your services for an upcoming event. Could you please provide more information about your availability and pricing?\n\nBest regards,\n${user?.full_name || 'Client'}`);
- };
-
- const handleSendMessage = async () => {
- if (!message.trim()) {
- toast({
- title: "Message required",
- description: "Please enter a message to send.",
- variant: "destructive",
- });
- return;
- }
-
- try {
- await base44.entities.Conversation.create({
- participants: [
- { id: user?.id, name: user?.full_name, role: "client" },
- { id: contactModal.vendor.id, name: contactModal.vendor.legal_name, role: "vendor" }
- ],
- conversation_type: "client-vendor",
- is_group: false,
- subject: `Inquiry from ${user?.full_name || 'Client'}`,
- last_message: message.substring(0, 100),
- last_message_at: new Date().toISOString(),
- status: "active"
- });
-
- toast({
- title: "✅ Message sent!",
- description: `Your message has been sent to ${contactModal.vendor.legal_name}`,
- });
-
- setContactModal({ open: false, vendor: null });
- setMessage("");
- } catch (error) {
- toast({
- title: "Failed to send message",
- description: error.message,
- variant: "destructive",
- });
- }
- };
-
- const handleCreateOrder = (vendor) => {
- sessionStorage.setItem('selectedVendor', JSON.stringify({
- id: vendor.id,
- name: vendor.legal_name,
- rates: vendor.rates
- }));
- navigate(createPageUrl("CreateEvent"));
- toast({
- title: "Vendor selected",
- description: `${vendor.legal_name} will be used for this order.`,
- });
- };
-
- const toggleVendorRates = (vendorId) => {
- setExpandedVendors(prev => ({
- ...prev,
- [vendorId]: !prev[vendorId]
- }));
- };
-
- return (
-
-
-
- {/* Hero Header */}
-
-
-
-
-
-
-
-
Vendor Marketplace
-
Find the perfect vendor partner for your staffing needs
-
-
-
-
-
- {filteredVendors.length} Active Vendors
-
-
-
- Verified & Approved
-
-
-
-
-
- {/* Preferred Vendor Section */}
- {preferredVendor ? (
-
-
-
-
-
-
-
- PREFERRED VENDOR
-
-
- {preferredVendor.doing_business_as || preferredVendor.legal_name}
-
-
Your default vendor for all new orders
-
-
-
-
-
-
-
- {/* Stats Grid */}
-
-
-
{preferredVendor.staffCount}
-
Staff
-
-
-
-
-
{preferredVendor.rating.toFixed(1)}
-
Rating
-
-
-
-
-
-
-
{preferredVendor.responseTime}
-
Response
-
-
-
-
-
${Math.round(preferredVendor.minRate)}
-
From/hr
-
-
-
-
-
{preferredVendor.completedJobs}
-
Jobs
-
-
-
- {/* Benefits Banner */}
-
-
-
-
-
-
-
Priority Support
-
Faster responses
-
-
-
-
-
-
-
-
-
Dedicated Manager
-
Direct contact
-
-
-
-
-
-
-
-
-
Better Rates
-
Volume pricing
-
-
-
-
-
- ) : (
-
-
-
-
-
-
- Set Your Preferred Vendor
-
-
- Choose a default vendor for faster ordering and streamlined operations. You'll get priority support and better rates.
-
-
-
-
- Quick Orders
-
-
-
- Priority Support
-
-
-
- Better Rates
-
-
-
-
- )}
-
- {/* Client Vendor Preferences */}
-
queryClient.invalidateQueries({ queryKey: ['current-user-marketplace'] })}
- />
-
- {/* Stats Cards */}
-
-
-
-
-
-
Vendors
-
{vendors.length}
-
Approved
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Fill Rate
-
98%
-
Success rate
-
-
-
-
-
-
-
-
-
-
-
-
-
Response
-
2h
-
Avg time
-
-
-
-
-
-
-
-
-
- {/* Filters */}
-
-
-
-
-
-
-
- setSearchTerm(e.target.value)}
- className="pl-10 h-10 border border-slate-300 focus:border-[#0A39DF] text-sm"
- />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {/* Other Vendors Section Title */}
- {preferredVendor && (
-
-
-
- Other Available Vendors
-
-
-
- )}
-
- {/* Vendors Grid */}
- {viewMode === "grid" ? (
-
- {otherVendors.map((vendor) => {
- const isExpanded = expandedVendors[vendor.id];
-
- return (
-
-
-
-
-
-
- {vendor.company_logo ? (
-
- ) : null}
-
- {vendor.legal_name?.charAt(0)}
-
-
-
-
-
-
-
-
-
-
- {vendor.legal_name}
-
-
-
- {vendor.rating.toFixed(1)}
-
-
-
- {vendor.doing_business_as && (
-
DBA: {vendor.doing_business_as}
- )}
-
-
- {vendor.service_specialty && (
-
- {vendor.service_specialty}
-
- )}
-
-
- {vendor.region || vendor.city}
-
-
-
- {vendor.staffCount} Staff
-
-
-
- {vendor.responseTime}
-
-
-
-
-
-
-
-
Starting from
-
${vendor.minRate}
-
per hour
-
-
- {vendor.clientsInSector > 0 && (
-
-
-
- {vendor.clientsInSector}
-
-
- in your area
-
-
- )}
-
-
-
-
- {vendor.completedJobs} jobs
-
-
- {vendor.rates.length} services
-
-
-
-
-
-
-
-
-
toggleVendorRates(vendor.id)} className="flex-1">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {Object.entries(vendor.ratesByCategory).map(([category, categoryRates]) => (
-
-
-
-
- {category}
-
- {categoryRates.length}
-
-
-
-
- {categoryRates.map((rate, idx) => {
- return (
-
-
-
-
- {idx + 1}
-
-
{rate.role_name}
-
-
-
-
${rate.client_rate?.toFixed(0)}
-
per hour
-
-
-
- );
- })}
-
-
- ))}
-
-
-
-
-
- );
- })}
-
- ) : (
-
-
-
-
-
- | Vendor |
- Specialty |
- Location |
- Rating |
- Clients |
- Staff |
- Min Rate |
- Actions |
-
-
-
- {otherVendors.map((vendor) => (
-
-
-
-
- {vendor.company_logo ? (
-
- ) : null}
-
- {vendor.legal_name?.charAt(0)}
-
-
-
- {vendor.legal_name}
- {vendor.completedJobs} jobs completed
-
-
- |
- {vendor.service_specialty || '—'} |
-
-
-
- {vendor.region}
-
- |
-
-
-
- {vendor.rating.toFixed(1)}
-
- |
-
- {vendor.clientsInSector > 0 ? (
-
-
- {vendor.clientsInSector}
-
- ) : (
- —
- )}
- |
-
- {vendor.staffCount}
- |
-
-
- ${vendor.minRate}
- /hour
-
- |
-
-
-
-
-
- |
-
- ))}
-
-
-
-
- )}
-
- {otherVendors.length === 0 && !preferredVendor && (
-
-
-
No vendors found
-
Try adjusting your filters
-
-
- )}
-
-
- {/* Contact Modal */}
-
setContactModal({ open, vendor: null })}>
-
-
-
- Contact {contactModal.vendor?.legal_name}
-
-
- Start a conversation and get staffing help within hours
-
-
-
-
-
-
- {contactModal.vendor?.company_logo ? (
-
- ) : null}
-
- {contactModal.vendor?.legal_name?.charAt(0)}
-
-
-
-
{contactModal.vendor?.legal_name}
-
-
-
- {contactModal.vendor?.region}
-
-
-
- {contactModal.vendor?.staffCount} staff
-
-
-
- {contactModal.vendor?.rating?.toFixed(1)}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
-}
\ No newline at end of file
diff --git a/frontend-web/src/pages/VendorOnboarding.jsx b/frontend-web/src/pages/VendorOnboarding.jsx
deleted file mode 100644
index 569df16d..00000000
--- a/frontend-web/src/pages/VendorOnboarding.jsx
+++ /dev/null
@@ -1,752 +0,0 @@
-import React, { useState } from "react";
-import { base44 } from "@/api/base44Client";
-import { useMutation, useQueryClient, useQuery } from "@tanstack/react-query";
-import { useNavigate } from "react-router-dom";
-import { createPageUrl } from "@/utils";
-import { Button } from "@/components/ui/button";
-import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
-import { Input } from "@/components/ui/input";
-import { Label } from "@/components/ui/label";
-import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
-import { Badge } from "@/components/ui/badge";
-import { Textarea } from "@/components/ui/textarea";
-import {
- ArrowLeft,
- ArrowRight,
- Check,
- FileText,
- Building2,
- DollarSign,
- Shield,
- MapPin,
- Sparkles,
- FileCheck,
- TrendingUp
-} from "lucide-react";
-import PageHeader from "@/components/common/PageHeader";
-import { useToast } from "@/components/ui/use-toast";
-
-const ONBOARDING_STEPS = [
- { id: 1, title: "Vendor Onboard", icon: Building2, description: "Basic vendor information" },
- { id: 2, title: "NDA", icon: Shield, description: "Sign and Accept Non-Disclosure Agreement" },
- { id: 3, title: "Contract", icon: FileText, description: "Master service agreement" },
- { id: 4, title: "Performance & VA Structure", icon: TrendingUp, description: "Performance metrics and VA structure" },
- { id: 5, title: "Documents & Validation", icon: FileCheck, description: "Upload compliance documents" },
- { id: 6, title: "Service & Coverage", icon: MapPin, description: "Service areas and coverage" },
- { id: 7, title: "Rate Proposal", icon: DollarSign, description: "Submit your rate proposal" },
- { id: 8, title: "AI Intelligence", icon: Sparkles, description: "AI-powered optimization" }
-];
-
-export default function VendorOnboarding() {
- const navigate = useNavigate();
- const queryClient = useQueryClient();
- const { toast } = useToast();
- const [currentStep, setCurrentStep] = useState(1);
-
- const { data: user } = useQuery({
- queryKey: ['current-user-onboarding'],
- queryFn: () => base44.auth.me(),
- });
-
- const userRole = user?.user_role || user?.role;
- const isBuyer = userRole === "procurement" || userRole === "admin";
-
- const [vendorData, setVendorData] = useState({
- // Step 1: Vendor Onboard
- legal_name: "",
- doing_business_as: "",
- tax_id: "",
- business_type: "LLC",
- primary_contact_name: "",
- primary_contact_email: "",
- primary_contact_phone: "",
- billing_address: "",
-
- // Step 2: NDA
- nda_acknowledged: false,
- nda_signed_by: "",
- nda_signature_date: "",
- nda_signature_time: "",
-
- // Step 3: Contract
- contract_acknowledged: false,
- contract_signed_date: "",
-
- // Step 4: Performance & VA Structure
- performance_metrics_agreed: false,
- va_structure_type: "",
-
- // Step 5: Documents & Validation
- w9_document: "",
- coi_document: "",
- insurance_expiry: "",
-
- // Step 6: Service & Coverage
- coverage_regions: [],
- eligible_roles: [],
-
- // Step 7: Rate Proposal
- rate_proposal_submitted: false,
-
- // Step 8: AI Intelligence
- ai_optimization_enabled: false,
-
- // Status
- approval_status: "pending",
- });
-
- const generateVendorNumber = () => {
- const randomNum = Math.floor(1000 + Math.random() * 9000);
- return `VN-${randomNum}`;
- };
-
- const createVendorMutation = useMutation({
- mutationFn: (data) => base44.entities.Vendor.create(data),
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ['vendors'] });
- toast({
- title: "✅ Vendor Onboarding Complete",
- description: "Vendor submitted for approval",
- });
- navigate(createPageUrl("VendorManagement"));
- },
- });
-
- const handleNext = () => {
- // Validation for Step 2 (NDA)
- if (currentStep === 2 && !vendorData.nda_acknowledged) {
- toast({
- title: "âš ï¸ NDA Required",
- description: "You must sign and accept the NDA before proceeding",
- variant: "destructive",
- });
- return;
- }
-
- if (currentStep < 8) {
- setCurrentStep(currentStep + 1);
- }
- };
-
- const handleBack = () => {
- if (currentStep > 1) {
- setCurrentStep(currentStep - 1);
- }
- };
-
- const handleSubmit = () => {
- const vendorNumber = generateVendorNumber();
- createVendorMutation.mutate({
- ...vendorData,
- vendor_number: vendorNumber,
- is_active: false,
- });
- };
-
- const handleFileUpload = async (file, field) => {
- try {
- const { file_url } = await base44.integrations.Core.UploadFile({ file });
- setVendorData({ ...vendorData, [field]: file_url });
- toast({
- title: "✅ File Uploaded",
- description: "Document uploaded successfully",
- });
- } catch (error) {
- toast({
- title: "⌠Upload Failed",
- description: "Failed to upload document",
- variant: "destructive",
- });
- }
- };
-
- const handleSignNDA = () => {
- const now = new Date();
- setVendorData({
- ...vendorData,
- nda_acknowledged: true,
- nda_signed_by: user?.full_name || user?.email,
- nda_signature_date: now.toLocaleDateString(),
- nda_signature_time: now.toLocaleTimeString()
- });
- toast({
- title: "✅ NDA Signed",
- description: `Signed by ${user?.full_name || user?.email} on ${now.toLocaleString()}`,
- });
- };
-
- if (!isBuyer) {
- return (
-
-
-
-
- Access Denied
- Only Procurement and Admin users can onboard vendors.
-
-
-
- );
- }
-
- return (
-
-
-
-
- {/* Progress Stepper */}
-
-
-
- {ONBOARDING_STEPS.map((step, index) => {
- const isActive = currentStep === step.id;
- const isCompleted = currentStep > step.id;
- const Icon = step.icon;
-
- return (
-
-
- {isCompleted ? : }
-
-
- Step {step.id}
-
-
- {step.title}
-
-
- );
- })}
-
-
-
-
- {/* Step Content */}
-
-
-
- {React.createElement(ONBOARDING_STEPS[currentStep - 1].icon, { className: "w-8 h-8" })}
-
-
- Step {currentStep}: {ONBOARDING_STEPS[currentStep - 1].title}
-
-
- {ONBOARDING_STEPS[currentStep - 1].description}
-
-
-
-
-
- {/* STEP 1: Vendor Onboard */}
- {currentStep === 1 && (
-
-
📠Basic Vendor Information
-
-
-
-
-
- )}
-
- {/* STEP 2: NDA - Sign and Accept */}
- {currentStep === 2 && (
-
-
-
-
-
-
- 🔒 Non-Disclosure Agreement (NDA)
-
-
- Review and sign the NDA between your company and Foodbuy, LLC. This is a legally binding document.
-
-
-
-
-
- {/* NDA Document Viewer */}
-
-
- {/* NDA Key Terms */}
-
-
📋 Key Terms Summary:
-
- -
-
-
- Confidentiality: All proprietary information, pricing, and client data must remain confidential
-
-
- -
-
-
- Duration: Obligations continue for 2 years after relationship termination
-
-
- -
-
-
- Governing Law: North Carolina law applies
-
-
- -
-
-
- Use Restrictions: Information only for business relationship purposes
-
-
-
-
-
- {/* Sign and Accept Section */}
-
- {!vendorData.nda_acknowledged ? (
-
-
âœï¸ Sign and Accept NDA
-
- By clicking the button below, I acknowledge that I have read, understood, and agree to be bound by
- the terms of the Confidentiality/Non-Disclosure Agreement between my company and Foodbuy, LLC.
-
-
-
- ) : (
-
-
-
-
-
✅ NDA Signed Successfully
-
-
-
- Signed by:
- {vendorData.nda_signed_by}
-
-
- Date:
- {vendorData.nda_signature_date}
-
-
- Time:
- {vendorData.nda_signature_time}
-
-
-
-
- ✓ You may now proceed to the next step
-
-
- )}
-
-
- )}
-
- {/* STEP 3: Contract */}
- {currentStep === 3 && (
-
-
📋 Master Service Agreement
-
-
- Review and sign the Master Service Agreement. This document outlines the terms of our business relationship.
-
-
-
-
Contract document viewer will appear here
-
-
- )}
-
- {/* STEP 4: Performance & VA Structure */}
- {currentStep === 4 && (
-
-
📊 Performance Metrics & VA Structure
-
-
-
Performance Metrics
-
- - • Fill Rate Target: 95%+
- - • On-Time Arrival: 98%+
- - • Quality Rating: 4.5/5+
- - • Cancellation Rate: <5%
-
-
-
-
VA Structure
-
-
-
-
-
- )}
-
- {/* STEP 5: Documents & Validation */}
- {currentStep === 5 && (
-
-
📂 Upload Compliance Documents
-
-
- )}
-
- {/* STEP 6: Service & Coverage */}
- {currentStep === 6 && (
-
-
ðŸ—ºï¸ Service Areas & Coverage
-
-
-
- {["San Francisco Bay Area", "Los Angeles", "Sacramento", "San Diego", "Silicon Valley", "East Bay"].map((region) => (
-
- ))}
-
-
-
-
-
-
- {["Bartender", "Server", "Cook", "Dishwasher", "Barista", "Cashier", "Security", "Event Staff", "Manager"].map((role) => (
-
- ))}
-
-
-
- )}
-
- {/* STEP 7: Rate Proposal */}
- {currentStep === 7 && (
-
-
💰 Rate Proposal
-
-
- Submit your proposed rate structure. Our procurement team will review and may negotiate.
-
-
-
- You can add detailed rate proposals after initial approval. For now, we'll create a default rate card for review.
-
-
- )}
-
- {/* STEP 8: AI Intelligence */}
- {currentStep === 8 && (
-
-
🤖 AI-Powered Optimization
-
-
-
-
-
AI Intelligence Features
-
- Enable AI-powered features to optimize your vendor performance, automate workflows, and gain insights.
-
-
-
-
-
-
✨ Smart Matching
-
AI matches your workforce to the best opportunities
-
-
-
📈 Predictive Analytics
-
Forecast demand and optimize staffing
-
-
-
🎯 Performance Insights
-
Real-time performance tracking and recommendations
-
-
-
âš¡ Automated Workflows
-
Streamline operations with AI automation
-
-
-
-
-
- {/* Final Review */}
-
-
✅ Ready to Submit!
-
- You've completed all onboarding steps. Review your information and submit for approval.
-
-
-
-
- Basic Information Complete
-
-
-
- NDA Signed: {vendorData.nda_signature_date}
-
-
-
- {vendorData.coverage_regions.length} Regions Selected
-
-
-
- {vendorData.eligible_roles.length} Roles Selected
-
-
-
-
- )}
-
-
-
- {/* Navigation Buttons */}
-
-
-
-
- {currentStep < 8 ? (
-
- ) : (
-
- )}
-
-
-
-
- );
-}
\ No newline at end of file
diff --git a/frontend-web/src/pages/VendorOrders.jsx b/frontend-web/src/pages/VendorOrders.jsx
deleted file mode 100644
index 1a49162c..00000000
--- a/frontend-web/src/pages/VendorOrders.jsx
+++ /dev/null
@@ -1,509 +0,0 @@
-import React, { useState, useMemo } from "react";
-import { base44 } from "@/api/base44Client";
-import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
-import { useNavigate } from "react-router-dom";
-import { createPageUrl } from "@/utils";
-import { Card, CardContent } from "@/components/ui/card";
-import { Badge } from "@/components/ui/badge";
-import { Button } from "@/components/ui/button";
-import { Input } from "@/components/ui/input";
-import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
-import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
-import { Search, Eye, Edit, Copy, UserCheck, Zap, Clock, Users, RefreshCw, Calendar as CalendarIcon, AlertTriangle, List, LayoutGrid, CheckCircle, FileText, X, MapPin } from "lucide-react";
-import { useToast } from "@/components/ui/use-toast";
-import { format, parseISO, isValid } from "date-fns";
-import { Alert, AlertDescription } from "@/components/ui/alert";
-import SmartAssignModal from "@/components/events/SmartAssignModal";
-import { autoFillShifts } from "@/components/scheduling/SmartAssignmentEngine";
-import { detectAllConflicts, ConflictAlert } from "@/components/scheduling/ConflictDetection";
-
-const safeParseDate = (dateString) => {
- if (!dateString) return null;
- try {
- // If date is in format YYYY-MM-DD, parse it without timezone conversion
- if (typeof dateString === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(dateString)) {
- const [year, month, day] = dateString.split('-').map(Number);
- const date = new Date(year, month - 1, day);
- return isValid(date) ? date : null;
- }
- const date = typeof dateString === 'string' ? parseISO(dateString) : new Date(dateString);
- return isValid(date) ? date : null;
- } catch { return null; }
-};
-
-const safeFormatDate = (dateString, formatStr) => {
- const date = safeParseDate(dateString);
- if (!date) return "-";
- try { return format(date, formatStr); } catch { return "-"; }
-};
-
-const convertTo12Hour = (time24) => {
- if (!time24) return "-";
- try {
- const [hours, minutes] = time24.split(':');
- const hour = parseInt(hours);
- const ampm = hour >= 12 ? 'PM' : 'AM';
- const hour12 = hour % 12 || 12;
- return `${hour12}:${minutes} ${ampm}`;
- } catch {
- return time24;
- }
-};
-
-const getStatusBadge = (event, hasConflicts) => {
- if (event.is_rapid) {
- return (
-
-
- RAPID
- {hasConflicts && (
-
- )}
-
- );
- }
-
- const statusConfig = {
- 'Draft': { bg: 'bg-slate-500', icon: FileText },
- 'Pending': { bg: 'bg-amber-500', icon: Clock },
- 'Partial Staffed': { bg: 'bg-orange-500', icon: AlertTriangle },
- 'Fully Staffed': { bg: 'bg-emerald-500', icon: CheckCircle },
- 'Active': { bg: 'bg-blue-500', icon: Users },
- 'Completed': { bg: 'bg-slate-400', icon: CheckCircle },
- 'Canceled': { bg: 'bg-red-500', icon: X },
- };
-
- const config = statusConfig[event.status] || { bg: 'bg-slate-400', icon: Clock };
- const Icon = config.icon;
-
- return (
-
-
- {event.status}
- {hasConflicts && (
-
- )}
-
- );
-};
-
-export default function VendorOrders() {
- const navigate = useNavigate();
- const queryClient = useQueryClient();
- const { toast } = useToast();
- const [searchTerm, setSearchTerm] = useState("");
- const [activeTab, setActiveTab] = useState("all");
- const [viewMode, setViewMode] = useState("table");
- const [showConflicts, setShowConflicts] = useState(true);
- const [assignModal, setAssignModal] = useState({ open: false, event: null });
-
- const [assignmentOptions] = useState({
- prioritizeSkill: true,
- prioritizeReliability: true,
- prioritizeVendor: true,
- prioritizeFatigue: true,
- prioritizeCompliance: true,
- prioritizeProximity: true,
- prioritizeCost: false,
- });
-
- const { data: user } = useQuery({
- queryKey: ['current-user-vendor-orders'],
- queryFn: () => base44.auth.me(),
- });
-
- const { data: allEvents = [] } = useQuery({
- queryKey: ['all-events-vendor'],
- queryFn: () => base44.entities.Event.list('-date'),
- });
-
- const { data: allStaff = [] } = useQuery({
- queryKey: ['staff-for-auto-assign'],
- queryFn: () => base44.entities.Staff.list(),
- });
-
- const { data: vendorRates = [] } = useQuery({
- queryKey: ['vendor-rates-auto-assign'],
- queryFn: () => base44.entities.VendorRate.list(),
- initialData: [],
- });
-
- const updateEventMutation = useMutation({
- mutationFn: ({ id, data }) => base44.entities.Event.update(id, data),
- onSuccess: () => queryClient.invalidateQueries({ queryKey: ['all-events-vendor'] }),
- });
-
- const autoAssignMutation = useMutation({
- mutationFn: async (event) => {
- const assignments = await autoFillShifts(event, allStaff, vendorEvents, vendorRates, assignmentOptions);
- if (assignments.length === 0) throw new Error("No suitable staff found");
-
- const updatedAssignedStaff = [...(event.assigned_staff || []), ...assignments];
- const updatedShifts = (event.shifts || []).map(shift => {
- const updatedRoles = (shift.roles || []).map(role => {
- const roleAssignments = assignments.filter(a => a.role === role.role);
- return { ...role, assigned: (role.assigned || 0) + roleAssignments.length };
- });
- return { ...shift, roles: updatedRoles };
- });
-
- const totalRequested = updatedShifts.reduce((accShift, shift) => {
- return accShift + (shift.roles?.reduce((accRole, role) => accRole + (role.count || 0), 0) || 0);
- }, 0);
-
- const totalAssigned = updatedAssignedStaff.length;
- let newStatus = event.status;
-
- if (totalAssigned >= totalRequested && totalRequested > 0) {
- newStatus = 'Fully Staffed';
- } else if (totalAssigned > 0 && totalAssigned < totalRequested) {
- newStatus = 'Partial Staffed';
- } else if (totalAssigned === 0) {
- newStatus = 'Pending';
- }
-
- await base44.entities.Event.update(event.id, {
- assigned_staff: updatedAssignedStaff,
- shifts: updatedShifts,
- requested: (event.requested || 0) + assignments.length,
- status: newStatus,
- });
-
- return assignments.length;
- },
- onSuccess: (count) => {
- queryClient.invalidateQueries({ queryKey: ['all-events-vendor'] });
- toast({ title: "✅ Auto-Assigned", description: `Assigned ${count} staff automatically` });
- },
- onError: (error) => {
- toast({ title: "âš ï¸ Auto-Assign Failed", description: error.message, variant: "destructive" });
- },
- });
-
- const vendorEvents = useMemo(() => {
- return allEvents.filter(e =>
- e.vendor_name === user?.company_name ||
- e.vendor_id === user?.id ||
- e.created_by === user?.email
- );
- }, [allEvents, user]);
-
- const eventsWithConflicts = useMemo(() => {
- return vendorEvents.map(event => {
- const conflicts = detectAllConflicts(event, vendorEvents);
- return { ...event, detected_conflicts: conflicts };
- });
- }, [vendorEvents]);
-
- const totalConflicts = eventsWithConflicts.reduce((sum, e) => sum + (e.detected_conflicts?.length || 0), 0);
-
- const filteredEvents = useMemo(() => {
- let filtered = eventsWithConflicts;
-
- if (activeTab === "upcoming") filtered = filtered.filter(e => { const eventDate = safeParseDate(e.date); return eventDate && eventDate > new Date(); });
- else if (activeTab === "active") filtered = filtered.filter(e => e.status === "Active");
- else if (activeTab === "past") filtered = filtered.filter(e => e.status === "Completed");
- else if (activeTab === "conflicts") filtered = filtered.filter(e => e.detected_conflicts && e.detected_conflicts.length > 0);
-
- if (searchTerm) {
- const lower = searchTerm.toLowerCase();
- filtered = filtered.filter(e =>
- e.event_name?.toLowerCase().includes(lower) ||
- e.business_name?.toLowerCase().includes(lower) ||
- e.hub?.toLowerCase().includes(lower)
- );
- }
-
- return filtered;
- }, [eventsWithConflicts, searchTerm, activeTab]);
-
- const getAssignmentStatus = (event) => {
- const totalRequested = event.shifts?.reduce((accShift, shift) => {
- return accShift + (shift.roles?.reduce((accRole, role) => accRole + (role.count || 0), 0) || 0);
- }, 0) || 0;
-
- const assigned = event.assigned_staff?.length || 0;
- const fillPercent = totalRequested > 0 ? Math.round((assigned / totalRequested) * 100) : 0;
-
- if (assigned === 0) return { color: 'bg-slate-100 text-slate-600', text: '0', percent: '0%', status: 'empty' };
- if (totalRequested > 0 && assigned >= totalRequested) return { color: 'bg-emerald-500 text-white', text: assigned, percent: '100%', status: 'full' };
- if (totalRequested > 0 && assigned < totalRequested) return { color: 'bg-orange-500 text-white', text: assigned, percent: `${fillPercent}%`, status: 'partial' };
- return { color: 'bg-slate-500 text-white', text: assigned, percent: '0%', status: 'partial' };
- };
-
- const getTabCount = (tab) => {
- if (tab === "all") return vendorEvents.length;
- if (tab === "conflicts") return eventsWithConflicts.filter(e => e.detected_conflicts && e.detected_conflicts.length > 0).length;
- if (tab === "upcoming") return vendorEvents.filter(e => { const eventDate = safeParseDate(e.date); return eventDate && eventDate > new Date(); }).length;
- if (tab === "active") return vendorEvents.filter(e => e.status === "Active").length;
- if (tab === "past") return vendorEvents.filter(e => e.status === "Completed").length;
- return 0;
- };
-
- // The original handleAutoAssignEvent is removed as the button now opens the modal directly.
- // const handleAutoAssignEvent = (event) => autoAssignMutation.mutate(event);
-
- const getEventTimes = (event) => {
- const firstShift = event.shifts?.[0];
- const rolesInFirstShift = firstShift?.roles || [];
-
- let startTime = null;
- let endTime = null;
-
- if (rolesInFirstShift.length > 0) {
- startTime = rolesInFirstShift[0].start_time || null;
- endTime = rolesInFirstShift[0].end_time || null;
- }
-
- return {
- startTime: startTime ? convertTo12Hour(startTime) : "-",
- endTime: endTime ? convertTo12Hour(endTime) : "-"
- };
- };
-
- return (
-
-
-
-
Order Management
-
View, assign, and track all your orders
-
-
- {showConflicts && totalConflicts > 0 && (
-
-
-
-
-
- {totalConflicts} scheduling conflict{totalConflicts !== 1 ? 's' : ''} detected
-
-
-
-
-
- )}
-
-
-
-
-
-
-
-
-
-
RAPID
-
{vendorEvents.filter(e => e.is_rapid).length}
-
-
-
-
-
-
-
-
-
-
-
-
-
REQUESTED
-
{vendorEvents.filter(e => e.status === 'Pending' || e.status === 'Draft').length}
-
-
-
-
-
-
-
-
-
-
-
PARTIAL
-
{vendorEvents.filter(e => {
- const status = getAssignmentStatus(e);
- return status.status === 'partial';
- }).length}
-
-
-
-
-
-
-
-
-
-
-
-
-
FULLY STAFFED
-
{vendorEvents.filter(e => {
- const status = getAssignmentStatus(e);
- return status.status === 'full';
- }).length}
-
-
-
-
-
-
-
-
-
- setSearchTerm(e.target.value)} className="pl-10 border-slate-200 h-10" />
-
-
-
-
-
-
-
-
-
- All ({getTabCount("all")})
-
-
- Conflicts ({getTabCount("conflicts")})
-
- Upcoming ({getTabCount("upcoming")})
- Active ({getTabCount("active")})
- Past ({getTabCount("past")})
-
-
-
-
-
-
-
- BUSINESS
- HUB
- EVENT
- DATE & TIME
- STATUS
- REQUESTED
- ASSIGNED
- INVOICE
- ACTIONS
-
-
-
- {filteredEvents.length === 0 ? (
- No orders found
- ) : (
- filteredEvents.map((event) => {
- const assignmentStatus = getAssignmentStatus(event);
- const showAutoButton = assignmentStatus.status !== 'full' && event.status !== 'Canceled' && event.status !== 'Completed';
- const hasConflicts = event.detected_conflicts && event.detected_conflicts.length > 0;
- const eventTimes = getEventTimes(event);
- const eventDate = safeParseDate(event.date);
- const dayOfWeek = eventDate ? format(eventDate, 'EEEE') : '';
- const invoiceReady = event.status === "Completed";
-
- return (
-
-
-
- {event.business_name || "—"}
-
-
-
-
- {event.hub || event.event_location || "Main Hub"}
-
-
-
- {event.event_name}
-
-
-
-
{eventDate ? format(eventDate, 'MM.dd.yyyy') : '-'}
-
{dayOfWeek}
-
-
- {eventTimes.startTime} - {eventTimes.endTime}
-
-
-
-
- {getStatusBadge(event, hasConflicts)}
-
-
- {event.requested || 0}
-
-
-
-
- {assignmentStatus.text}
-
- {assignmentStatus.percent}
-
-
-
-
-
-
-
-
-
-
-
-
-
- {hasConflicts && activeTab === "conflicts" && (
-
-
-
-
-
- )}
-
- );
- })
- )}
-
-
-
-
-
-
setAssignModal({ open: false, event: null })}
- event={assignModal.event}
- />
-
- );
-}
\ No newline at end of file
diff --git a/frontend-web/src/pages/VendorPerformance.jsx b/frontend-web/src/pages/VendorPerformance.jsx
deleted file mode 100644
index 8676ad3e..00000000
--- a/frontend-web/src/pages/VendorPerformance.jsx
+++ /dev/null
@@ -1,112 +0,0 @@
-import React from "react";
-import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
-import { Badge } from "@/components/ui/badge";
-import { TrendingUp, Award, Users, Star, Calendar, Target } from "lucide-react";
-import { LineChart, Line, BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
-
-export default function VendorPerformance() {
- const performanceData = [
- { month: 'Jan', fillRate: 94, satisfaction: 4.6, onTime: 96 },
- { month: 'Feb', fillRate: 96, satisfaction: 4.7, onTime: 97 },
- { month: 'Mar', fillRate: 95, satisfaction: 4.8, onTime: 98 },
- { month: 'Apr', fillRate: 97, satisfaction: 4.7, onTime: 96 },
- { month: 'May', fillRate: 98, satisfaction: 4.9, onTime: 99 },
- ];
-
- const metrics = [
- { label: "Fill Rate", value: "97%", icon: Target, color: "text-green-600", bg: "bg-green-100" },
- { label: "Client Satisfaction", value: "4.8/5", icon: Star, color: "text-amber-600", bg: "bg-amber-100" },
- { label: "On-Time Delivery", value: "98%", icon: Calendar, color: "text-blue-600", bg: "bg-blue-100" },
- { label: "Active Staff", value: "156", icon: Users, color: "text-purple-600", bg: "bg-purple-100" },
- ];
-
- return (
-
-
-
-
Performance Metrics
-
Track your vendor performance and ratings
-
-
- {/* KROW Score */}
-
-
-
- KROW Score: A+
- You're in the top 10% of vendors!
-
-
- +5% from last month
-
-
-
-
- {/* Key Metrics */}
-
- {metrics.map((metric, index) => (
-
-
-
-
-
- {metric.label}
- {metric.value}
-
-
- ))}
-
-
- {/* Performance Trends */}
-
-
- Performance Trends
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {/* Client Feedback */}
-
-
- Recent Client Feedback
-
-
-
- {[
- { client: "Tech Corp", rating: 5, comment: "Exceptional service and professional staff", date: "2 days ago" },
- { client: "Premier Events", rating: 4, comment: "Very reliable, minor delay on one shift", date: "1 week ago" },
- { client: "Corporate Solutions", rating: 5, comment: "Best vendor we've worked with!", date: "2 weeks ago" },
- ].map((feedback, index) => (
-
-
-
-
{feedback.client}
-
- {[...Array(5)].map((_, i) => (
-
- ))}
-
-
-
{feedback.date}
-
-
{feedback.comment}
-
- ))}
-
-
-
-
-
- );
-}
\ No newline at end of file
diff --git a/frontend-web/src/pages/VendorRateCard.jsx b/frontend-web/src/pages/VendorRateCard.jsx
deleted file mode 100644
index 172853e8..00000000
--- a/frontend-web/src/pages/VendorRateCard.jsx
+++ /dev/null
@@ -1,776 +0,0 @@
-
-import React, { useState } from "react";
-import { base44 } from "@/api/base44Client";
-import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
-import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
-import { Button } from "@/components/ui/button";
-import { Input } from "@/components/ui/input";
-import { Label } from "@/components/ui/label";
-import { Badge } from "@/components/ui/badge";
-import { Switch } from "@/components/ui/switch";
-import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
-import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog";
-import {
- Plus, Edit, Trash2, TrendingUp, TrendingDown, DollarSign, Users, Calculator,
- CheckCircle2, Save, Building2, Settings, ChevronDown, ChevronUp, Loader2, Sparkles, Search, MapPin, Briefcase
-} from "lucide-react";
-import { useToast } from "@/components/ui/use-toast";
-
-const MINIMUM_WAGE = 16.50;
-const CATEGORIES = [
- "Kitchen and Culinary",
- "Concessions",
- "Facilities",
- "Bartending",
- "Security",
- "Event Staff",
- "Management",
- "Technical",
- "Other"
-];
-
-const VENDORS = [
- { name: "Legendary Event Staffing", region: "Bay Area", state: "California", city: "San Francisco", specialty: "Full Service Events", markup: 25, fee: 20, csat: 4.8 },
- { name: "Instawork", region: "National", state: "Multiple", city: "Multiple", specialty: "On-Demand Gig Platform", markup: 18, fee: 15, csat: 4.5 },
- { name: "The Party Staff", region: "Bay Area", state: "California", city: "San Francisco", specialty: "Event Staffing", markup: 24, fee: 19, csat: 4.2 },
- { name: "Elite Hospitality Staffing", region: "Bay Area", state: "California", city: "Oakland", specialty: "Hotels/Events", markup: 23, fee: 18, csat: 4.3 },
- { name: "Jeff Duerson Staffing", region: "Bay Area", state: "California", city: "San Jose", specialty: "Catering/Events", markup: 27, fee: 22, csat: 4.0 },
- { name: "Flagship Culinary Services", region: "Bay Area", state: "California", city: "Palo Alto", specialty: "Culinary", markup: 26, fee: 21, csat: 4.1 },
- { name: "LA Event Professionals", region: "Southern California", state: "California", city: "Los Angeles", specialty: "Event Staffing", markup: 22, fee: 18, csat: 4.4 },
- { name: "Hollywood Hospitality", region: "Southern California", state: "California", city: "Los Angeles", specialty: "Full Service Events", markup: 20, fee: 17, csat: 4.6 },
- { name: "San Diego Event Staff", region: "Southern California", state: "California", city: "San Diego", specialty: "Hospitality", markup: 21, fee: 17, csat: 4.3 },
- { name: "OC Staffing Solutions", region: "Southern California", state: "California", city: "Irvine", specialty: "Event-based staffing", markup: 25, fee: 20, csat: 4.1 },
-];
-
-const MARKET_AVERAGES = {
- "Banquet Captain": 47.76,
- "Barback": 36.13,
- "Barista": 43.11,
- "Busser": 39.23,
- "BW Bartender": 41.15,
- "Cashier/Standworker": 38.05,
- "Cook": 44.58,
- "Dinning Attendant": 41.56,
- "Dishwasher/ Steward": 38.38,
- "Executive Chef": 70.60,
- "FOH Cafe Attendant": 41.56,
- "Full Bartender": 47.76,
- "Grill Cook": 44.58,
- "Host/Hostess/Greeter": 41.56,
- "Internal Support": 41.56,
- "Lead Cook": 52.00,
- "Line Cook": 44.58,
- "Premium Server": 47.76,
- "Prep Cook": 37.98,
- "Receiver": 40.01,
- "Server": 41.56,
- "Sous Chef": 59.75,
- "Warehouse Worker": 41.15,
- "Baker": 44.58,
- "Janitor": 38.38,
- "Mixologist": 71.30,
- "Utilities": 38.38,
- "Scullery": 38.38,
- "Runner": 39.23,
- "Pantry Cook": 44.58,
- "Supervisor": 47.76,
- "Steward": 38.38,
- "Steward Supervisor": 42.25
-};
-
-const ROLE_CATEGORIES = {
- "Banquet Captain": "Event Staff",
- "Barback": "Bartending",
- "Barista": "Concessions",
- "Busser": "Event Staff",
- "BW Bartender": "Bartending",
- "Cashier/Standworker": "Concessions",
- "Cook": "Kitchen and Culinary",
- "Dinning Attendant": "Event Staff",
- "Dishwasher/ Steward": "Kitchen and Culinary",
- "Executive Chef": "Management",
- "FOH Cafe Attendant": "Concessions",
- "Full Bartender": "Bartending",
- "Grill Cook": "Kitchen and Culinary",
- "Host/Hostess/Greeter": "Event Staff",
- "Internal Support": "Other",
- "Lead Cook": "Kitchen and Culinary",
- "Line Cook": "Kitchen and Culinary",
- "Premium Server": "Event Staff",
- "Prep Cook": "Kitchen and Culinary",
- "Receiver": "Facilities",
- "Server": "Event Staff",
- "Sous Chef": "Management",
- "Warehouse Worker": "Facilities",
- "Baker": "Kitchen and Culinary",
- "Janitor": "Facilities",
- "Mixologist": "Bartending",
- "Utilities": "Facilities",
- "Scullery": "Kitchen and Culinary",
- "Runner": "Event Staff",
- "Pantry Cook": "Kitchen and Culinary",
- "Supervisor": "Management",
- "Steward": "Kitchen and Culinary",
- "Steward Supervisor": "Management"
-};
-
-export default function VendorRateCard() {
- const [selectedVendor, setSelectedVendor] = useState("all");
- const [activeCategory, setActiveCategory] = useState("all");
- const [expandedVendors, setExpandedVendors] = useState({});
- const [generatingDemoData, setGeneratingDemoData] = useState(false);
-
- // NEW: Search and filter states
- const [searchVendor, setSearchVendor] = useState("");
- const [searchLocation, setSearchLocation] = useState("");
- const [searchState, setSearchState] = useState("");
- const [searchPosition, setSearchPosition] = useState("");
-
- const { toast } = useToast();
- const queryClient = useQueryClient();
-
- const { data: user } = useQuery({
- queryKey: ['current-user-vendor-rates'],
- queryFn: () => base44.auth.me(),
- });
-
- const userRole = user?.user_role || user?.role || "admin";
- const isVendor = userRole === "vendor";
- const isAdminOrProcurement = userRole === "admin" || userRole === "procurement";
-
- const calculateClientRate = (wage, markupPercent, feePercent) => {
- const baseWage = parseFloat(wage);
- const markupAmount = baseWage * (parseFloat(markupPercent) / 100);
- const subtotal = baseWage + markupAmount;
- const feeAmount = subtotal * (parseFloat(feePercent) / 100);
- return (subtotal + feeAmount).toFixed(2);
- };
-
- const analyzePricing = (role, clientRate) => {
- const marketAvg = MARKET_AVERAGES[role];
- if (!marketAvg) return { status: "competitive", message: "No market data", color: "text-blue-600", bg: "bg-blue-50", icon: CheckCircle2 };
-
- const diff = ((clientRate - marketAvg) / marketAvg) * 100;
-
- if (diff < -15) return { status: "underpriced", message: `${Math.abs(diff).toFixed(0)}% below market`, color: "text-red-600", bg: "bg-red-50", icon: TrendingDown };
- if (diff > 20) return { status: "overpriced", message: `${diff.toFixed(0)}% above market`, color: "text-orange-600", bg: "bg-orange-50", icon: TrendingUp };
- if (diff >= -5 && diff <= 10) return { status: "optimal", message: "Optimal pricing", color: "text-green-600", bg: "bg-green-50", icon: CheckCircle2 };
- return { status: "competitive", message: "Competitive", color: "text-blue-600", bg: "bg-blue-50", icon: CheckCircle2 };
- };
-
- // Generate rates for ALL vendors
- const generateAllVendorRates = async () => {
- setGeneratingDemoData(true);
-
- const allRoles = Object.keys(MARKET_AVERAGES);
- const totalRates = (VENDORS.length - 1) * allRoles.length; // -1 for Legendary which already has rates
-
- toast({
- title: "🚀 Generating All Vendor Rates",
- description: `Creating ${totalRates} rate cards for ${VENDORS.length - 1} vendors...`,
- });
-
- try {
- let totalCreated = 0;
-
- for (const vendor of VENDORS) {
- // Skip Legendary since it already has rates
- if (vendor.name === "Legendary Event Staffing") continue;
-
- for (const [roleName, marketRate] of Object.entries(MARKET_AVERAGES)) {
- const category = ROLE_CATEGORIES[roleName] || "Other";
-
- // Calculate employee wage based on region
- let baseWageMultiplier = 0.65; // Default 65% of market
- if (vendor.region === "Bay Area") baseWageMultiplier = 0.70;
- else if (vendor.region === "Southern California") baseWageMultiplier = 0.67;
- else if (vendor.region === "National") baseWageMultiplier = 0.62;
-
- const employeeWage = Math.max(MINIMUM_WAGE, marketRate * baseWageMultiplier);
- const clientRate = calculateClientRate(employeeWage, vendor.markup, vendor.fee);
- const clientRateNum = parseFloat(clientRate);
-
- // Determine competitive status (within ±15% of market)
- const diff = ((clientRateNum - marketRate) / marketRate) * 100;
- const isCompetitive = diff >= -15 && diff <= 15;
-
- // CSTA compliance (CA vendors with proper fee structure)
- const isCSTA = vendor.state === "California" && vendor.fee <= 25;
-
- // Compliance verified (wage meets minimum + has proper documentation)
- const isCompliant = employeeWage >= MINIMUM_WAGE; // This is directly related to minimum_wage_compliance
-
- await base44.entities.VendorRate.create({
- vendor_name: vendor.name,
- category: category,
- role_name: roleName,
- employee_wage: parseFloat(employeeWage.toFixed(2)),
- markup_percentage: vendor.markup,
- vendor_fee_percentage: vendor.fee,
- client_rate: clientRateNum,
- is_active: true,
- minimum_wage_compliance: employeeWage >= MINIMUM_WAGE,
- pricing_status: analyzePricing(roleName, clientRateNum).status,
- market_average: marketRate,
- notes: `${vendor.region} - ${vendor.specialty}`,
- client_visibility: "all",
- competitive_status: isCompetitive,
- csta_compliant: isCSTA,
- compliance_verified: isCompliant
- });
-
- totalCreated++;
- }
- }
-
- queryClient.invalidateQueries({ queryKey: ['vendor-rates'] });
-
- toast({
- title: "✅ All Vendor Rates Generated!",
- description: `Created ${totalCreated} rate cards across ${VENDORS.length - 1} vendors (${allRoles.length} services each)`,
- });
-
- } catch (error) {
- console.error("Error generating vendor rates:", error);
- toast({
- title: "Error Generating Rates",
- description: error.message || "Something went wrong",
- variant: "destructive",
- });
- } finally {
- setGeneratingDemoData(false);
- }
- };
-
- const { data: rates = [], isLoading } = useQuery({
- queryKey: ['vendor-rates', selectedVendor, userRole, user?.company_name],
- queryFn: async () => {
- const allRates = await base44.entities.VendorRate.list();
-
- if (isVendor && user?.company_name) {
- return allRates.filter(r => r.vendor_name === user.company_name);
- }
-
- if (selectedVendor === "all") return allRates;
- return allRates.filter(r => r.vendor_name === selectedVendor);
- },
- });
-
- const { data: vendorSettings = [] } = useQuery({
- queryKey: ['vendor-default-settings'],
- queryFn: async () => {
- return await base44.entities.VendorDefaultSettings.list();
- },
- initialData: [],
- });
-
- const toggleVendorExpanded = (vendorName) => {
- setExpandedVendors(prev => ({
- ...prev,
- [vendorName]: !prev[vendorName]
- }));
- };
-
- const ratesByVendor = rates.reduce((acc, rate) => {
- if (!acc[rate.vendor_name]) acc[rate.vendor_name] = [];
- acc[rate.vendor_name].push(rate);
- return acc;
- }, {});
-
- // UPDATED: Enhanced filtering with search including state
- const filteredRatesByVendor = Object.entries(ratesByVendor).reduce((acc, [vendorName, vendorRates]) => {
- // Filter by vendor name search
- if (searchVendor.trim() && !vendorName.toLowerCase().includes(searchVendor.toLowerCase())) {
- return acc;
- }
-
- // Filter by location search (check vendor location from VENDORS list)
- const vendorInfo = VENDORS.find(v => v.name === vendorName);
- if (searchLocation.trim() && vendorInfo) {
- const locationMatch =
- vendorInfo.region?.toLowerCase().includes(searchLocation.toLowerCase()) ||
- vendorInfo.city?.toLowerCase().includes(searchLocation.toLowerCase());
- if (!locationMatch) {
- return acc;
- }
- }
-
- // Filter by state search
- if (searchState.trim() && vendorInfo) {
- const stateMatch = vendorInfo.state?.toLowerCase().includes(searchState.toLowerCase());
- if (!stateMatch) {
- return acc;
- }
- }
-
- // Filter by category
- let filtered = activeCategory === "all"
- ? vendorRates
- : vendorRates.filter(r => r.category === activeCategory);
-
- // Filter by position/role search
- if (searchPosition.trim()) {
- filtered = filtered.filter(r =>
- r.role_name?.toLowerCase().includes(searchPosition.toLowerCase())
- );
- }
-
- if (filtered.length > 0) {
- acc[vendorName] = filtered;
- }
- return acc;
- }, {});
-
- const clearAllFilters = () => {
- setSearchVendor("");
- setSearchLocation("");
- setSearchState("");
- setSearchPosition("");
- setActiveCategory("all");
- setSelectedVendor("all");
- };
-
- const hasActiveFilters = searchVendor || searchLocation || searchState || searchPosition || activeCategory !== "all";
-
- return (
-
-
-
-
- {/* Header */}
-
-
-
Vendor Rate Cards
-
Manage vendor rates, markup, and pricing across all locations
-
-
-
- {isAdminOrProcurement && Object.keys(ratesByVendor).length < 5 && (
-
- )}
-
-
-
- {/* UPDATED: Search & Filter Section - Now with 4 fields */}
-
-
-
-
- {hasActiveFilters && (
-
- )}
-
-
-
-
-
-
- setSearchVendor(e.target.value)}
- className="pl-10 border-slate-300"
- />
-
-
-
-
-
-
-
- setSearchLocation(e.target.value)}
- className="pl-10 border-slate-300"
- />
-
-
-
-
-
-
-
- setSearchState(e.target.value)}
- className="pl-10 border-slate-300"
- />
-
-
-
-
-
-
-
- setSearchPosition(e.target.value)}
- className="pl-10 border-slate-300"
- />
-
-
-
-
- {/* Search Results Summary */}
- {hasActiveFilters && (
-
-
-
- Found {Object.keys(filteredRatesByVendor).length} vendors with {Object.values(filteredRatesByVendor).flat().length} total services
-
-
- )}
-
-
-
- {/* Summary Stats */}
-
-
-
-
-
-
Total Vendors
-
{Object.keys(filteredRatesByVendor).length}
-
-
-
-
-
-
-
-
-
-
-
Total Services
-
- {Object.values(filteredRatesByVendor).flat().length}
-
-
-
-
-
-
-
-
-
-
-
-
Competitive Rates
-
- {Object.values(filteredRatesByVendor).flat().filter(r => r.competitive_status).length}
-
-
-
-
-
-
-
-
-
-
-
-
Avg Partner Rate
-
- ${(Object.values(filteredRatesByVendor).flat().reduce((sum, r) => sum + parseFloat(r.client_rate || 0), 0) / (Object.values(filteredRatesByVendor).flat().length || 1)).toFixed(2)}
-
-
-
-
-
-
-
-
- {/* Category Tabs */}
-
-
-
-
-
-
- {CATEGORIES.map(cat => (
-
- ))}
-
-
-
-
-
- {/* Vendor Cards */}
-
- {Object.keys(filteredRatesByVendor).length === 0 ? (
-
- {hasActiveFilters ? (
- <>
-
-
No Matching Results
-
Try adjusting your search filters
-
- >
- ) : (
- <>
-
-
No Rates Found
-
Generate rates for all vendors to get started
- {isAdminOrProcurement && (
-
- )}
- >
- )}
-
- ) : (
- Object.entries(filteredRatesByVendor).map(([vendorName, vendorRates]) => {
- const vendorDefaults = vendorSettings.find(s => s.vendor_name === vendorName);
- const vendorInfo = VENDORS.find(v => v.name === vendorName);
- const isExpanded = expandedVendors[vendorName];
-
- // Calculate vendor-level tags
- const competitiveCount = vendorRates.filter(r => r.competitive_status).length;
- const cstaCompliantCount = vendorRates.filter(r => r.csta_compliant).length;
- const complianceCount = vendorRates.filter(r => r.compliance_verified).length;
- const totalRates = vendorRates.length;
-
- return (
-
-
-
-
toggleVendorExpanded(vendorName)}
- >
-
-
-
-
-
- {vendorName}
- {isExpanded ? (
-
- ) : (
-
- )}
-
-
- {vendorInfo && (
-
{vendorInfo.city}, {vendorInfo.state} • {vendorInfo.specialty}
- )}
-
-
- {vendorDefaults && (
- <>
-
-
- Markup: {vendorDefaults.default_markup_percentage}%
-
-
-
- VA: {vendorDefaults.default_vendor_fee_percentage}%
-
- >
- )}
- {totalRates > 0 && complianceCount === totalRates && (
-
-
- Full Compliance
-
- )}
- {totalRates > 0 && competitiveCount / totalRates >= 0.8 && (
-
-
- Competitive
-
- )}
- {vendorInfo && vendorInfo.csat && (
-
- â CSAT {vendorInfo.csat.toFixed(1)}
-
- )}
-
- {vendorRates.length} {vendorRates.length === 1 ? 'service' : 'services'}
-
-
-
-
-
-
-
- {isExpanded && (
-
-
- {vendorRates.map(rate => {
- const analysis = analyzePricing(rate.role_name, rate.client_rate);
- const Icon = analysis.icon;
-
- const baseWage = rate.employee_wage;
- const markupAmount = baseWage * (rate.markup_percentage / 100);
- const subtotal = baseWage + markupAmount;
- const feeAmount = subtotal * (rate.vendor_fee_percentage / 100);
-
- return (
-
-
-
-
{rate.role_name}
-
$/hourly
-
-
- {rate.category}
-
- {rate.competitive_status && (
-
- Competitive
-
- )}
- {rate.csta_compliant && (
-
- CSTA
-
- )}
- {rate.compliance_verified && (
-
- Compliance
-
- )}
-
-
-
-
-
-
-
- ${baseWage.toFixed(2)}
-
-
- {rate.markup_percentage}%
-
-
- {rate.vendor_fee_percentage}%
-
-
-
-
- Wage: ${baseWage.toFixed(2)}
- Markup: {rate.markup_percentage}% (+${markupAmount.toFixed(2)})
- VA Fee: {rate.vendor_fee_percentage}% (+${feeAmount.toFixed(2)})
-
-
-
-
-
${rate.client_rate}
-
/hourly
-
-
-
-
-
-
-
{analysis.status.charAt(0).toUpperCase() + analysis.status.slice(1)}
-
{analysis.message}
-
-
-
-
-
- );
- })}
-
-
- )}
-
- );
- })
- )}
-
-
-
- );
-}
diff --git a/frontend-web/src/pages/VendorRates.jsx b/frontend-web/src/pages/VendorRates.jsx
deleted file mode 100644
index d73721c5..00000000
--- a/frontend-web/src/pages/VendorRates.jsx
+++ /dev/null
@@ -1,1188 +0,0 @@
-import React, { useMemo, useState } from "react";
-import { base44 } from "@/api/base44Client";
-import { useQuery } from "@tanstack/react-query";
-import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
-import { Button } from "@/components/ui/button";
-import { Badge } from "@/components/ui/badge";
-import { Download, Search, Building2, MapPin, DollarSign, Shield, Briefcase, Plus, Pencil, Trash2 } from "lucide-react";
-import PageHeader from "@/components/common/PageHeader";
-import { Input } from "@/components/ui/input";
-import RateCardModal from "@/components/rates/RateCardModal";
-
-// Define regions - these map to the notes field or can be a new field
-const REGIONS = [
- "Bay Area",
- "Southern California",
- "Northern California",
- "National"
-];
-
-function fmtCurrency(v) {
- if (typeof v !== "number" || Number.isNaN(v)) return "—";
- return v.toLocaleString(undefined, { style: "currency", currency: "USD" });
-}
-
-function downloadCSV(rows, regionName, vendorName) {
- const headers = ["Role", "Category", "Employee Wage", "Markup %", "Vendor Fee %", "Client Rate"];
- const lines = [headers.join(",")];
- for (const r of rows) {
- const cells = [
- r.role_name,
- r.category,
- r.employee_wage,
- r.markup_percentage,
- r.vendor_fee_percentage,
- r.client_rate
- ];
- lines.push(cells.join(","));
- }
- const blob = new Blob([lines.join("\n")], { type: "text/csv;charset=utf-8;" });
- const url = URL.createObjectURL(blob);
- const a = document.createElement("a");
- a.href = url;
- a.download = `${vendorName}_${regionName}_Rates_${new Date().toISOString().slice(0,10)}.csv`;
- a.click();
- URL.revokeObjectURL(url);
-}
-
-// NEW: Helper function to parse role name into position and region
-const parseRoleName = (roleName) => {
- if (!roleName) return { position: '', region: '' };
-
- // Check if role name contains a hyphen separator
- if (roleName.includes(' - ')) {
- const parts = roleName.split(' - ');
- return {
- position: parts[0].trim(),
- region: parts[1].trim()
- };
- }
-
- // If no hyphen, return the whole name as position
- return {
- position: roleName,
- region: ''
- };
-};
-
-// ==================== VENDOR-ONLY COMPONENT ====================
-function VendorCompanyPricebookView({ user, vendorName }) {
- const APPROVED_TAG = "__APPROVED__";
-
- const APPROVED_RATES = ["FoodBuy", "Aramark"];
-
- const [customRateCards, setCustomRateCards] = useState([
- { name: "Bay Area Compass", baseBook: "FoodBuy", discount: 0, isDefault: true },
- { name: "LA Compass", baseBook: "FoodBuy", discount: 0, isDefault: true },
- { name: "Google", baseBook: "FoodBuy", discount: 0, isDefault: true },
- { name: "Promotion", baseBook: "FoodBuy", discount: 0, isDefault: true },
- { name: "Convention Center", baseBook: "FoodBuy", discount: 0, isDefault: true }
- ]);
- const [pricebook, setPricebook] = useState("FoodBuy");
- const [search, setSearch] = useState("");
- const [activeRegion, setActiveRegion] = useState("All");
- const [activeCategory, setActiveCategory] = useState("All");
-
- const REGIONS = ["All", "San Francisco-Oakland-San Jose", "Los Angeles-Riverside-Orange County", "Fresno", "Stockton-Lodi"];
- const [editing, setEditing] = useState(null);
- const [toast, setToast] = useState(null);
- const [analyzingCompetitiveness, setAnalyzingCompetitiveness] = useState(false);
- const [competitivenessData, setCompetitivenessData] = useState(null);
- const [showRateCardModal, setShowRateCardModal] = useState(false);
- const [editingRateCard, setEditingRateCard] = useState(null);
- const [renamingCard, setRenamingCard] = useState(null);
- const [renameValue, setRenameValue] = useState("");
-
- const RATE_CARDS = customRateCards.map(c => c.name);
-
- const { data: rates = [] } = useQuery({
- queryKey: ['vendor-rates-pricebook', vendorName],
- queryFn: async () => {
- const allRates = await base44.entities.VendorRate.list();
- // FOR DEMO: Show Legendary Event Staffing rates if no rates for current vendor
- const vendorRates = allRates.filter(r => r.vendor_name === vendorName && r.is_active);
- if (vendorRates.length === 0) {
- // Show demo data from Legendary Event Staffing
- return allRates.filter(r => r.vendor_name === "Legendary Event Staffing" && r.is_active);
- }
- return vendorRates;
- },
- initialData: [],
- enabled: !!vendorName,
- });
-
- const CATEGORIES = [
- "Kitchen and Culinary",
- "Event Staff",
- "Bartending",
- "Management",
- "Facilities",
- "Concessions",
- "Other"
- ];
-
- const handleSaveRateCard = (cardData) => {
- if (editingRateCard) {
- setCustomRateCards(prev => prev.map(c => c.name === editingRateCard.name ? { ...cardData, isDefault: c.isDefault } : c));
- } else {
- setCustomRateCards(prev => [...prev, { ...cardData, isDefault: false }]);
- }
- setToast(`✓ Rate card "${cardData.name}" saved successfully`);
- setPricebook(cardData.name);
- setEditingRateCard(null);
- };
-
- const handleDeleteRateCard = (cardName) => {
- if (customRateCards.length <= 1) {
- setToast("âš Cannot delete the last rate card");
- return;
- }
- setCustomRateCards(prev => prev.filter(c => c.name !== cardName));
- if (pricebook === cardName) {
- setPricebook(customRateCards.find(c => c.name !== cardName)?.name || "FoodBuy");
- }
- setToast(`✓ Rate card "${cardName}" deleted`);
- };
-
- const handleRenameCard = (oldName) => {
- if (!renameValue.trim() || renameValue === oldName) {
- setRenamingCard(null);
- return;
- }
- setCustomRateCards(prev => prev.map(c => c.name === oldName ? { ...c, name: renameValue.trim() } : c));
- if (pricebook === oldName) {
- setPricebook(renameValue.trim());
- }
- setToast(`✓ Renamed to "${renameValue.trim()}"`);
- setRenamingCard(null);
- };
-
- const scopedByBook = useMemo(() => {
- // Base approved rates
- const baseRates = {
- "FoodBuy": {
- "Banquet Captain": 47.76, "Barback": 36.13, "Barista": 43.11, "Busser": 39.23, "BW Bartender": 41.15,
- "Cashier/Standworker": 38.05, "Cook": 44.58, "Dinning Attendant": 41.56, "Dishwasher/ Steward": 38.38,
- "Executive Chef": 70.60, "FOH Cafe Attendant": 41.56, "Full Bartender": 47.76, "Grill Cook": 44.58,
- "Host/Hostess/Greeter": 41.56, "Internal Support": 41.56, "Lead Cook": 52.00, "Line Cook": 44.58,
- "Premium Server": 47.76, "Prep Cook": 37.98, "Receiver": 40.01, "Server": 41.56, "Sous Chef": 59.75,
- "Warehouse Worker": 41.15, "Baker": 44.58, "Janitor": 38.38, "Mixologist": 71.30, "Utilities": 38.38,
- "Scullery": 38.38, "Runner": 39.23, "Pantry Cook": 44.58, "Supervisor": 47.76, "Steward": 38.38, "Steward Supervisor": 41.15
- },
- "Aramark": {
- "Banquet Captain": 46.37, "Barback": 33.11, "Barista": 36.87, "Busser": 33.11, "BW Bartender": 36.12,
- "Cashier/Standworker": 33.11, "Cook": 36.12, "Dinning Attendant": 34.62, "Dishwasher/ Steward": 33.11,
- "Executive Chef": 76.76, "FOH Cafe Attendant": 34.62, "Full Bartender": 45.15, "Grill Cook": 36.12,
- "Host/Hostess/Greeter": 34.62, "Internal Support": 37.63, "Lead Cook": 52.68, "Line Cook": 36.12,
- "Premium Server": 40.64, "Prep Cook": 34.62, "Receiver": 34.62, "Server": 34.62, "Sous Chef": 60.20,
- "Warehouse Worker": 34.62, "Baker": 45.15, "Janitor": 34.62, "Mixologist": 60.20, "Utilities": 33.11,
- "Scullery": 33.11, "Runner": 33.11, "Pantry Cook": 36.12, "Supervisor": 45.15, "Steward": 33.11, "Steward Supervisor": 34.10
- }
- };
-
- // Default rate cards (built-in)
- const defaultCards = {
- "Bay Area Compass": {
- "Banquet Captain": 41.71, "Barback": 36.10, "Barista": 38.92, "Busser": 35.71, "BW Bartender": 38.92,
- "Cashier/Standworker": 36.10, "Cook": 42.13, "Dinning Attendant": 37.31, "Dishwasher/ Steward": 35.13,
- "Executive Chef": 72.19, "FOH Cafe Attendant": 37.31, "Full Bartender": 43.73, "Grill Cook": 42.13,
- "Host/Hostess/Greeter": 37.70, "Internal Support": 37.31, "Lead Cook": 46.57, "Line Cook": 42.13,
- "Premium Server": 44.12, "Prep Cook": 36.90, "Receiver": 35.71, "Server": 37.31, "Sous Chef": 56.15,
- "Warehouse Worker": 36.10, "Baker": 42.13, "Janitor": 35.13, "Mixologist": 56.15, "Utilities": 35.13,
- "Scullery": 36.10, "Runner": 35.71, "Pantry Cook": 42.13, "Supervisor": 46.84, "Steward": 36.10, "Steward Supervisor": 38.38
- },
- "LA Compass": {
- "Banquet Captain": 40.30, "Barback": 35.42, "Barista": 39.60, "Busser": 34.18, "BW Bartender": 35.65,
- "Cashier/Standworker": 34.26, "Cook": 37.20, "Dinning Attendant": 35.65, "Dishwasher/ Steward": 34.10,
- "Executive Chef": 60.53, "FOH Cafe Attendant": 35.65, "Full Bartender": 39.60, "Grill Cook": 37.20,
- "Host/Hostess/Greeter": 35.65, "Internal Support": 36.57, "Lead Cook": 39.60, "Line Cook": 37.20,
- "Premium Server": 40.30, "Prep Cook": 35.43, "Receiver": 34.65, "Server": 34.65, "Sous Chef": 52.78,
- "Warehouse Worker": 35.50, "Baker": 37.20, "Janitor": 34.10, "Mixologist": 62.00, "Utilities": 34.10,
- "Scullery": 34.10, "Runner": 34.18, "Pantry Cook": 37.20, "Supervisor": 39.60, "Steward": 34.10, "Steward Supervisor": 36.10
- },
- "Google": {
- "Banquet Captain": 34.02, "Barback": 31.79, "Barista": 32.53, "Busser": 27.62, "BW Bartender": 32.53,
- "Cashier/Standworker": 28.10, "Cook": 35.49, "Dinning Attendant": 28.83, "Dishwasher/ Steward": 28.10,
- "Executive Chef": 51.76, "FOH Cafe Attendant": 29.57, "Full Bartender": 36.97, "Grill Cook": 35.49,
- "Host/Hostess/Greeter": 29.57, "Internal Support": 36.57, "Lead Cook": 45.76, "Line Cook": 35.49,
- "Premium Server": 36.97, "Prep Cook": 29.57, "Receiver": 28.10, "Server": 30.22, "Sous Chef": 44.36,
- "Warehouse Worker": 28.10, "Baker": 35.59, "Janitor": 28.10, "Mixologist": 47.70, "Utilities": 28.10,
- "Scullery": 32.91, "Runner": 27.62, "Pantry Cook": 35.49, "Supervisor": 42.02, "Steward": 32.91, "Steward Supervisor": 34.10
- },
- "Promotion": {
- "Banquet Captain": 40.00, "Barback": 34.00, "Barista": 36.00, "Busser": 34.00, "BW Bartender": 36.00,
- "Cashier/Standworker": 34.00, "Cook": 36.00, "Dinning Attendant": 36.00, "Dishwasher/ Steward": 30.00,
- "Executive Chef": 51.00, "FOH Cafe Attendant": 36.00, "Full Bartender": 40.00, "Grill Cook": 36.00,
- "Host/Hostess/Greeter": 34.00, "Internal Support": 36.00, "Lead Cook": 45.00, "Line Cook": 36.00,
- "Premium Server": 38.00, "Prep Cook": 32.00, "Receiver": 34.00, "Server": 34.00, "Sous Chef": 44.00,
- "Warehouse Worker": 34.00, "Baker": 36.00, "Janitor": 32.00, "Mixologist": 51.00, "Utilities": 30.00,
- "Scullery": 34.00, "Runner": 34.00, "Pantry Cook": 36.00, "Supervisor": 40.00, "Steward": 34.00, "Steward Supervisor": 36.10
- },
- "Convention Center": {
- "Banquet Captain": 40.00, "Barback": 34.00, "Barista": 36.00, "Busser": 34.00, "BW Bartender": 36.00,
- "Cashier/Standworker": 34.00, "Cook": 36.00, "Dinning Attendant": 36.00, "Dishwasher/ Steward": 30.00,
- "Executive Chef": 51.00, "FOH Cafe Attendant": 36.00, "Full Bartender": 38.00, "Grill Cook": 36.00,
- "Host/Hostess/Greeter": 34.00, "Internal Support": 36.00, "Lead Cook": 45.00, "Line Cook": 36.00,
- "Premium Server": 38.00, "Prep Cook": 34.00, "Receiver": 34.00, "Server": 34.00, "Sous Chef": 44.00,
- "Warehouse Worker": 34.00, "Baker": 36.00, "Janitor": 32.00, "Mixologist": 51.00, "Utilities": 30.00,
- "Scullery": 34.00, "Runner": 34.00, "Pantry Cook": 36.00, "Supervisor": 40.00, "Steward": 34.00, "Steward Supervisor": 38.38
- }
- };
-
- // Add custom rate cards
- const customCardsRates = {};
- customRateCards.forEach(card => {
- customCardsRates[card.name] = card.rates;
- });
-
- const ratesByBook = { ...baseRates, ...defaultCards, ...customCardsRates };
-
- const currentBookRates = ratesByBook[pricebook] || {};
- const isCustomRateCard = RATE_CARDS.includes(pricebook);
-
- // For Custom Rate Cards, deduplicate by position name only
- if (isCustomRateCard) {
- const uniquePositions = new Map();
-
- rates.forEach(r => {
- const parsed = parseRoleName(r.role_name);
- const position = parsed.position;
- const finalRate = currentBookRates[position] || r.client_rate;
-
- // Only keep first occurrence of each position
- if (!uniquePositions.has(position)) {
- uniquePositions.set(position, {
- ...r,
- client: pricebook,
- region: "—",
- approvedCap: r.approved_cap_rate || r.client_rate,
- proposedRate: finalRate,
- position: position, // Use clean position name without region
- markupPct: r.markup_percentage,
- volDiscountPct: r.vendor_fee_percentage
- });
- }
- });
-
- return Array.from(uniquePositions.values());
- }
-
- // For Approved Rates, keep regions
- return rates.map(r => {
- const parsed = parseRoleName(r.role_name);
- const position = parsed.position;
- const finalRate = currentBookRates[position] || r.client_rate;
- const assignedRegion = r.region || parsed.region || (r.notes?.includes("Bay Area") ? "Bay Area" : "LA");
-
- return {
- ...r,
- client: pricebook,
- region: assignedRegion,
- approvedCap: r.approved_cap_rate || r.client_rate,
- proposedRate: finalRate,
- position: r.role_name,
- markupPct: r.markup_percentage,
- volDiscountPct: r.vendor_fee_percentage
- };
- });
- }, [rates, pricebook]);
-
- const isApprovedRate = APPROVED_RATES.includes(pricebook);
-
- const filtered = useMemo(() => {
- return scopedByBook.filter(r => {
- const regionMatch = !isApprovedRate || activeRegion === "All" || r.region === activeRegion || parseRoleName(r.position).region === activeRegion;
- const categoryMatch = activeCategory === "All" || r.category === activeCategory;
- const searchMatch = search.trim() === "" || parseRoleName(r.position).position.toLowerCase().includes(search.toLowerCase());
- return regionMatch && categoryMatch && searchMatch;
- });
- }, [scopedByBook, activeRegion, activeCategory, search, isApprovedRate]);
-
- const kpis = useMemo(() => {
- const rateValues = filtered.map(r => r.proposedRate);
- const avg = rateValues.length ? rateValues.reduce((a, b) => a + b, 0) / rateValues.length : 0;
- const min = rateValues.length ? Math.min(...rateValues) : 0;
- const max = rateValues.length ? Math.max(...rateValues) : 0;
- const total = filtered.length;
- return { avg, min, max, total };
- }, [filtered]);
-
- async function analyzeCompetitiveness() {
- setAnalyzingCompetitiveness(true);
- try {
- const positionsToAnalyze = filtered.slice(0, 20); // Limit to 20 positions for API
- const prompt = `You are a staffing industry pricing expert. Analyze these ${pricebook} hourly rates for the California market competitiveness.
-
-RATES TO ANALYZE:
-${positionsToAnalyze.map(r => `- ${parseRoleName(r.position).position}: $${r.proposedRate}/hr`).join('\n')}
-
-For EACH position listed above, provide market analysis:
-- marketRate: typical California market rate for this role (number)
-- score: competitiveness score 0-100 (100 = most competitive/best value)
-- status: exactly one of "Highly Competitive", "Competitive", "Average", "Above Market"
-- recommendation: brief 5-10 word suggestion
-
-Consider Bay Area/LA market rates. Food service roles typically $28-50/hr, management $45-80/hr.`;
-
- const result = await base44.integrations.Core.InvokeLLM({
- prompt,
- add_context_from_internet: true,
- response_json_schema: {
- type: "object",
- properties: {
- analysis: {
- type: "array",
- items: {
- type: "object",
- properties: {
- position: { type: "string" },
- marketRate: { type: "number" },
- score: { type: "number" },
- status: { type: "string" },
- recommendation: { type: "string" }
- }
- }
- }
- }
- }
- });
-
- setCompetitivenessData(result.analysis || []);
- setToast("✓ Competitive analysis complete");
- } catch (error) {
- console.error("Analysis error:", error);
- setToast("âš Analysis failed. Try again.");
- } finally {
- setAnalyzingCompetitiveness(false);
- }
- }
-
- function exportCSV() {
- const headers = ["Pricebook", "Position", "Category", "Region", "ApprovedCap", "ProposedRate", "Markup%", "VolDiscount%"];
- const body = filtered.map(r => {
- const parsed = parseRoleName(r.position); // Parse role_name for export
- return [
- pricebook,
- parsed.position,
- r.category,
- parsed.region,
- r.approvedCap,
- r.proposedRate,
- r.markupPct,
- r.volDiscountPct
- ];
- });
- const csv = [headers, ...body]
- .map(row => row.map(v => (typeof v === "string" ? `"${v}"` : v)).join(","))
- .join("\n");
- const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
- const url = URL.createObjectURL(blob);
- const a = document.createElement("a");
- a.href = url;
- a.download = `service-rates-${pricebook}.csv`;
- a.click();
- URL.revokeObjectURL(url);
- }
-
- return (
-
- {/* Header */}
-
-
-
-
-
-
-
-
-
-
Service Rate Management
-
2025–2028 Pricing Structure
-
-
-
- {rates.length > 0 && rates[0].vendor_name !== vendorName ? (
- <>Viewing demo data from Legendary Event Staffing>
- ) : (
- <>Managing rates for {vendorName}>
- )}
-
-
-
-
-
-
-
-
-
-
- {/* Pricebook Tabs - Split into Approved Rates and Rate Cards */}
-
-
- {/* Approved Enterprise Rates */}
-
-
-
-
-
-
-
Approved Enterprise Rates
-
Varies by region
-
-
-
- {APPROVED_RATES.map(tab => (
-
- ))}
-
-
-
- {/* Custom Rate Cards */}
-
-
-
-
-
-
-
-
Custom Rate Cards
-
Client-specific & negotiated
-
-
-
-
-
- {RATE_CARDS.map(tab => {
- const cardData = customRateCards.find(c => c.name === tab);
- const isRenaming = renamingCard === tab;
-
- if (isRenaming) {
- return (
-
- setRenameValue(e.target.value)}
- onBlur={() => handleRenameCard(tab)}
- onKeyDown={(e) => {
- if (e.key === 'Enter') handleRenameCard(tab);
- if (e.key === 'Escape') setRenamingCard(null);
- }}
- autoFocus
- className="px-3 py-2 rounded-xl text-sm font-semibold border-2 border-blue-500 bg-white focus:outline-none w-40"
- />
-
- );
- }
-
- return (
-
-
-
-
-
-
-
- );
- })}
-
-
-
-
-
- {/* Competitiveness Summary */}
- {competitivenessData && competitivenessData.length > 0 && (
-
-
-
-
-
-
AI Market Intelligence
-
Real-time competitive analysis for {pricebook}
-
-
-
- {[
- { status: "Highly Competitive", color: "bg-green-500", textColor: "text-green-600" },
- { status: "Competitive", color: "bg-blue-500", textColor: "text-blue-600" },
- { status: "Average", color: "bg-yellow-500", textColor: "text-yellow-600" },
- { status: "Above Market", color: "bg-red-500", textColor: "text-red-600" }
- ].map(({ status, color, textColor }) => {
- const count = competitivenessData.filter(d => d.status === status).length;
- return (
-
- );
- })}
-
-
-
- )}
-
- {/* KPI Cards */}
-
-
-
-
-
{fmtCurrency(kpis.avg)}
-
Based on {kpis.total} positions
-
-
-
-
-
-
-
{kpis.total}
-
{pricebook} rate book
-
-
-
-
-
-
-
- {fmtCurrency(kpis.min)} – {fmtCurrency(kpis.max)}
-
-
Min – Max spread
-
-
-
-
- {/* Region Filters - Only for Approved Enterprise Rates */}
- {isApprovedRate && (
-
-
-
-
-
Service Regions
-
-
- {REGIONS.map(region => (
-
- ))}
-
-
-
- )}
-
- {/* Category Filters + Search */}
-
-
-
-
-
- CATEGORY & SEARCH
-
- {(search || activeCategory !== "All" || activeRegion !== "All") && (
-
- )}
-
-
- {["All", ...CATEGORIES].map(cat => (
-
- ))}
-
-
-
-
- setSearch(e.target.value)}
- placeholder="Search positions..."
- className="pl-12 h-12 bg-slate-50 border-slate-200 rounded-xl text-base"
- />
-
-
-
-
-
- {/* Table */}
-
-
-
-
Rate Breakdown
-
Detailed pricing for {pricebook}
-
-
-
-
- | Position |
- Category |
- Region |
- Base Wage |
- {pricebook} Rate |
- Market Rate |
- Competitive Score |
- Actions |
-
-
-
- {filtered.map((r, idx) => {
- const parsed = parseRoleName(r.position);
- const competitive = competitivenessData?.find(c => c.position === parsed.position);
- const isEditing = editing === r.id;
-
- return (
-
-
-
-
- {parsed.position.substring(0, 2).toUpperCase()}
-
- {parsed.position}
-
- |
-
-
- {r.category}
-
- |
-
-
-
- {r.region}
-
- |
-
- {fmtCurrency(r.employee_wage)}
- |
-
- {isEditing ? (
- {
- setEditing(null);
- setToast("✓ Rate updated successfully");
- }}
- />
- ) : (
-
- {fmtCurrency(r.proposedRate)}
- /hr
-
- )}
- |
-
- {competitive ? (
-
-
- {fmtCurrency(competitive.marketRate)}
-
- {r.proposedRate < competitive.marketRate ? '↓' : '↑'}
- {Math.abs(((r.proposedRate - competitive.marketRate) / competitive.marketRate * 100)).toFixed(1)}%
-
-
-
- ) : (
- Run AI analysis
- )}
- |
-
- {competitive ? (
-
-
-
- {competitive.score}
- {competitive.status}
-
-
- ) : (
- —
- )}
- |
-
-
-
-
- |
-
- );
- })}
- {filtered.length === 0 && (
-
- |
- No rates found for {pricebook} rate book. {search.trim() && "Try adjusting your search or "}Switch to a different rate book.
- |
-
- )}
-
-
-
-
-
- {/* Toast */}
- {toast && (
-
-
- {toast}
-
-
- )}
-
- {/* Rate Card Modal */}
-
{ setShowRateCardModal(false); setEditingRateCard(null); }}
- onSave={handleSaveRateCard}
- editingCard={editingRateCard}
- />
-
- );
-}
-
-// ==================== ADMIN/PROCUREMENT VIEW (EXISTING) ====================
-function AdminProcurementRatesView({ vendorName }) {
- const [activeRegion, setActiveRegion] = useState("Bay Area");
- const [searchQuery, setSearchQuery] = useState("");
-
- const { data: rates = [], isLoading } = useQuery({
- queryKey: ['vendor-rates', vendorName],
- queryFn: async () => {
- const allRates = await base44.entities.VendorRate.list();
- return allRates.filter(r => r.vendor_name === vendorName && r.is_active);
- },
- initialData: [],
- enabled: !!vendorName,
- });
-
- const ratesByRegion = useMemo(() => {
- const grouped = {};
-
- rates.forEach(rate => {
- let region = "National"; // Default region
-
- // Attempt to determine region from rate.notes first
- if (rate.notes) {
- const notesLower = rate.notes.toLowerCase();
- if (notesLower.includes("bay area") || notesLower.includes("san francisco")) {
- region = "Bay Area";
- } else if (notesLower.includes("southern california") || notesLower.includes("los angeles") || notesLower.includes("san diego")) {
- region = "Southern California";
- } else if (notesLower.includes("northern california") || notesLower.includes("sacramento")) {
- region = "Northern California";
- }
- }
-
- // If region is not determined by notes, try to parse from role_name
- if (region === "National" && parseRoleName(rate.role_name).region) {
- region = parseRoleName(rate.role_name).region;
- }
-
- if (!grouped[region]) {
- grouped[region] = [];
- }
- grouped[region].push(rate);
- });
-
- return grouped;
- }, [rates]);
-
- const filteredRates = useMemo(() => {
- const regionRates = ratesByRegion[activeRegion] || [];
- if (!searchQuery.trim()) return regionRates;
-
- const query = searchQuery.toLowerCase();
- return regionRates.filter(r =>
- parseRoleName(r.role_name).position.toLowerCase().includes(query) || // Search parsed position
- r.category?.toLowerCase().includes(query)
- );
- }, [ratesByRegion, activeRegion, searchQuery]);
-
- const regionStats = useMemo(() => {
- const regionRates = ratesByRegion[activeRegion] || [];
- return {
- totalRoles: regionRates.length,
- avgClientRate: regionRates.length > 0
- ? regionRates.reduce((sum, r) => sum + (r.client_rate || 0), 0) / regionRates.length
- : 0,
- avgMarkup: regionRates.length > 0
- ? regionRates.reduce((sum, r) => sum + (r.markup_percentage || 0), 0) / regionRates.length
- : 0,
- avgVendorFee: regionRates.length > 0
- ? regionRates.reduce((sum, r) => sum + (r.vendor_fee_percentage || 0), 0) / regionRates.length
- : 0
- };
- }, [ratesByRegion, activeRegion]);
-
- return (
-
-
-
downloadCSV(filteredRates, activeRegion, vendorName)}
- variant="outline"
- className="border-slate-300"
- >
-
- Export {activeRegion} Rates
-
- }
- />
-
- {/* Summary Stats */}
-
-
-
-
-
-
Total Roles
-
{regionStats.totalRoles}
-
-
-
-
-
-
-
-
-
-
-
Avg Client Rate
-
{fmtCurrency(regionStats.avgClientRate)}
-
-
-
-
-
-
-
-
-
-
-
Avg Markup
-
{regionStats.avgMarkup.toFixed(1)}%
-
-
-
-
-
-
-
-
-
-
-
Avg VA Fee
-
{regionStats.avgVendorFee.toFixed(1)}%
-
-
-
-
-
-
-
- {/* Region Tabs */}
-
-
-
- {REGIONS.filter(region => ratesByRegion[region]?.length > 0).map(region => (
-
- ))}
-
-
-
-
- {/* Search Bar */}
-
-
-
- setSearchQuery(e.target.value)}
- className="pl-10 bg-white border-slate-200"
- />
-
-
-
- {/* Rates Table */}
-
-
-
-
- {activeRegion} Rates
-
-
-
- {filteredRates.length > 0 ? (
-
-
-
-
- | Position |
- Category |
- Region |
- Employee Wage |
- Markup |
- VA Fee |
- Client Rate |
- Status |
-
-
-
- {filteredRates.map((rate, idx) => {
- const parsed = parseRoleName(rate.role_name);
-
- return (
-
- |
- {parsed.position}
- |
-
-
- {rate.category}
-
- |
-
- {parsed.region || '—'}
- |
-
- {fmtCurrency(rate.employee_wage)}
- /hour
- |
-
- {rate.markup_percentage}%
- +{fmtCurrency(rate.employee_wage * (rate.markup_percentage / 100))}
- |
-
- {rate.vendor_fee_percentage}%
- +{fmtCurrency((rate.employee_wage * (1 + rate.markup_percentage / 100)) * (rate.vendor_fee_percentage / 100))}
- |
-
- {fmtCurrency(rate.client_rate)}
- /hour
- |
-
-
- {rate.competitive_status && (
-
- Competitive
-
- )}
- {rate.minimum_wage_compliance && (
-
- Compliant
-
- )}
- {rate.csta_compliant && (
-
- CSTA
-
- )}
-
- |
-
- );
- })}
-
-
-
- ) : (
-
-
-
- {searchQuery ? "No matching rates found" : `No rates for ${activeRegion}`}
-
-
- {searchQuery ? "Try adjusting your search" : "Contact your account manager to set up rates for this region"}
-
-
- )}
-
-
-
- {/* Footer Info */}
-
-
-
-
-
-
-
About Your Rates
-
- These are your approved service rates for {activeRegion}. Rates include employee wages, markup, and vendor administration fees.
- All rates are compliant with regional minimum wage requirements and have been approved by procurement.
-
-
-
-
-
-
- );
-}
-
-// ==================== MAIN COMPONENT WITH ROLE-BASED ROUTING ====================
-export default function VendorRates() {
- const { data: user } = useQuery({
- queryKey: ['current-user-vendor-rates'],
- queryFn: () => base44.auth.me(),
- });
-
- const userRole = user?.user_role || user?.role || "admin";
- const vendorName = user?.company_name || "Vendor";
- const isVendor = userRole === "vendor";
-
- // VENDOR ROLE: Show new company pricebook interface
- if (isVendor) {
- return
;
- }
-
- // ALL OTHER ROLES: Show existing region-based rates view
- return
;
-}
\ No newline at end of file
diff --git a/frontend-web/src/pages/VendorStaff.jsx b/frontend-web/src/pages/VendorStaff.jsx
deleted file mode 100644
index 1d162ec6..00000000
--- a/frontend-web/src/pages/VendorStaff.jsx
+++ /dev/null
@@ -1,152 +0,0 @@
-import React from "react";
-import { base44 } from "@/api/base44Client";
-import { useQuery } from "@tanstack/react-query";
-import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
-import { Button } from "@/components/ui/button";
-import { Badge } from "@/components/ui/badge";
-import { Users, Star, Calendar, Plus } from "lucide-react";
-import { useNavigate } from "react-router-dom";
-import { createPageUrl } from "@/utils";
-
-export default function VendorStaff() {
- const navigate = useNavigate();
-
- const { data: user } = useQuery({
- queryKey: ['current-user'],
- queryFn: () => base44.auth.me(),
- });
-
- const { data: staff } = useQuery({
- queryKey: ['vendor-staff'],
- queryFn: () => base44.entities.Staff.list(),
- initialData: [],
- });
-
- // Filter staff to only show THIS vendor's staff
- const myStaff = staff.filter(s =>
- s.vendor_id === user?.id ||
- s.vendor_name === user?.company_name ||
- s.created_by === user?.email
- );
-
- const stats = {
- total: myStaff.length,
- active: myStaff.filter(s => s.action !== 'Inactive').length,
- topRated: myStaff.filter(s => s.rating >= 4.5).length,
- avgRating: myStaff.length > 0
- ? (myStaff.reduce((sum, s) => sum + (s.rating || 0), 0) / myStaff.length).toFixed(1)
- : "0.0",
- };
-
- return (
-
-
-
-
-
My Staff
-
Manage your workforce
-
-
-
-
- {/* Stats */}
-
-
-
-
- Total Staff
- {stats.total}
-
-
-
-
-
-
- Active
- {stats.active}
-
-
-
-
-
-
- Top Rated
- {stats.topRated}
-
-
-
-
-
-
- Avg Rating
- {stats.avgRating}
-
-
-
-
- {/* Staff Grid */}
- {myStaff.length > 0 ? (
-
- {myStaff.map((member) => (
-
-
-
-
- {member.employee_name?.charAt(0) || '?'}
-
- {member.rating && (
-
-
- {member.rating}
-
- )}
-
- {member.employee_name}
- {member.position || 'Staff Member'}
-
-
- Shifts:
- {member.total_shifts || 0}
-
-
- Coverage:
- {member.shift_coverage_percentage || 0}%
-
-
-
-
-
- ))}
-
- ) : (
-
-
-
- No Staff Members Yet
- Start building your team by adding staff members
-
-
-
- )}
-
-
- );
-}
\ No newline at end of file
diff --git a/frontend-web/src/pages/WorkerShiftProposals.jsx b/frontend-web/src/pages/WorkerShiftProposals.jsx
deleted file mode 100644
index caeed23e..00000000
--- a/frontend-web/src/pages/WorkerShiftProposals.jsx
+++ /dev/null
@@ -1,267 +0,0 @@
-import React from "react";
-import { base44 } from "@/api/base44Client";
-import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
-import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
-import { Button } from "@/components/ui/button";
-import { Badge } from "@/components/ui/badge";
-import { Calendar, Clock, MapPin, DollarSign, CheckCircle, XCircle, AlertCircle } from "lucide-react";
-import { format } from "date-fns";
-import { useToast } from "@/components/ui/use-toast";
-import { Textarea } from "@/components/ui/textarea";
-
-export default function WorkerShiftProposals() {
- const queryClient = useQueryClient();
- const { toast } = useToast();
- const [declineReason, setDeclineReason] = React.useState({});
-
- const { data: user } = useQuery({
- queryKey: ['current-user-proposals'],
- queryFn: () => base44.auth.me(),
- });
-
- const { data: proposals = [] } = useQuery({
- queryKey: ['shift-proposals', user?.id],
- queryFn: async () => {
- if (!user?.id) return [];
- const staff = await base44.entities.Staff.filter({ email: user.email });
- if (staff.length === 0) return [];
- return base44.entities.ShiftProposal.filter({ staff_id: staff[0].id });
- },
- enabled: !!user?.id,
- initialData: [],
- });
-
- const respondMutation = useMutation({
- mutationFn: async ({ proposalId, status, reason }) => {
- const proposal = proposals.find(p => p.id === proposalId);
-
- await base44.entities.ShiftProposal.update(proposalId, {
- proposal_status: status,
- responded_at: new Date().toISOString(),
- decline_reason: reason || null,
- });
-
- if (status === 'ACCEPTED') {
- // Update event with confirmed assignment
- const event = await base44.entities.Event.list();
- const targetEvent = event.find(e => e.id === proposal.event_id);
-
- if (targetEvent) {
- const updatedStaff = [
- ...(targetEvent.assigned_staff || []),
- {
- staff_id: proposal.staff_id,
- staff_name: proposal.staff_name,
- role: proposal.role,
- email: user.email,
- }
- ];
-
- await base44.entities.Event.update(proposal.event_id, {
- assigned_staff: updatedStaff,
- status: 'Confirmed',
- });
- }
-
- // Update availability
- const availability = await base44.entities.WorkerAvailability.filter({ staff_id: proposal.staff_id });
- if (availability.length > 0) {
- const current = availability[0];
- await base44.entities.WorkerAvailability.update(current.id, {
- scheduled_hours_this_period: (current.scheduled_hours_this_period || 0) + 8,
- need_work_index: Math.max(0, current.need_work_index - 10),
- });
- }
- }
- },
- onSuccess: (_, variables) => {
- queryClient.invalidateQueries({ queryKey: ['shift-proposals'] });
- queryClient.invalidateQueries({ queryKey: ['events'] });
-
- toast({
- title: variables.status === 'ACCEPTED' ? "✅ Shift Accepted" : "Shift Declined",
- description: variables.status === 'ACCEPTED'
- ? "The shift has been added to your schedule"
- : "The vendor will be notified of your decision",
- });
- },
- });
-
- const pendingProposals = proposals.filter(p => p.proposal_status === 'PENDING_WORKER_CONFIRMATION');
- const pastProposals = proposals.filter(p => p.proposal_status !== 'PENDING_WORKER_CONFIRMATION');
-
- return (
-
-
-
-
-
Shift Requests
-
Review and respond to shift offers from vendors
-
-
- {/* Pending Requests */}
-
-
Pending Requests ({pendingProposals.length})
-
- {pendingProposals.length === 0 ? (
-
-
-
- No pending shift requests
- New offers will appear here
-
-
- ) : (
- pendingProposals.map((proposal) => {
- const deadline = new Date(proposal.response_deadline);
- const isUrgent = deadline < new Date(Date.now() + 24 * 60 * 60 * 1000);
-
- return (
-
-
-
-
-
{proposal.event_name}
-
{proposal.role}
-
- {proposal.was_marked_unavailable && (
-
- Override Unavailable
-
- )}
-
-
-
-
-
-
-
-
Date
-
{format(new Date(proposal.shift_date), 'MMM d, yyyy')}
-
-
-
-
-
-
Time
-
{proposal.start_time} - {proposal.end_time}
-
-
-
-
-
-
Location
-
{proposal.location}
-
-
-
-
-
-
Pay
-
${proposal.total_pay}
-
-
-
-
- {isUrgent && (
-
-
- â° Respond by {format(deadline, 'MMM d, h:mm a')}
-
-
- )}
-
- {declineReason[proposal.id] !== undefined && (
-
-
-
- )}
-
-
- {declineReason[proposal.id] === undefined ? (
- <>
-
-
- >
- ) : (
- <>
-
-
- >
- )}
-
-
-
- );
- })
- )}
-
-
- {/* Past Responses */}
- {pastProposals.length > 0 && (
-
-
Past Responses
- {pastProposals.map((proposal) => (
-
-
-
-
-
{proposal.event_name}
-
{format(new Date(proposal.shift_date), 'MMM d, yyyy')}
-
-
- {proposal.proposal_status}
-
-
-
-
- ))}
-
- )}
-
-
- );
-}
\ No newline at end of file
diff --git a/frontend-web/src/pages/WorkforceCompliance.jsx b/frontend-web/src/pages/WorkforceCompliance.jsx
deleted file mode 100644
index 3a684217..00000000
--- a/frontend-web/src/pages/WorkforceCompliance.jsx
+++ /dev/null
@@ -1,169 +0,0 @@
-import React, { useState } from "react";
-import { base44 } from "@/api/base44Client";
-import { useQuery } from "@tanstack/react-query";
-import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
-import { Badge } from "@/components/ui/badge";
-import { Input } from "@/components/ui/input";
-import { Shield, Search, CheckCircle2, AlertTriangle, XCircle, DollarSign, Award, FileText } from "lucide-react";
-
-export default function WorkforceCompliance() {
- const [searchTerm, setSearchTerm] = useState("");
-
- const { data: staff = [] } = useQuery({
- queryKey: ['staff-compliance'],
- queryFn: () => base44.entities.Staff.list(),
- initialData: [],
- });
-
- const { data: rates = [] } = useQuery({
- queryKey: ['rates-compliance'],
- queryFn: () => base44.entities.VendorRate.list(),
- initialData: [],
- });
-
- // Calculate compliance metrics
- const totalStaff = staff.length;
- const backgroundCheckCompliant = staff.filter(s => s.background_check_status === "cleared").length;
- const wageCompliant = rates.filter(r => r.employee_wage >= 16.50).length;
- const certifiedStaff = staff.filter(s => s.certifications?.length > 0).length;
-
- const complianceRate = totalStaff > 0 ? ((backgroundCheckCompliant / totalStaff) * 100).toFixed(1) : 0;
- const wageComplianceRate = rates.length > 0 ? ((wageCompliant / rates.length) * 100).toFixed(1) : 0;
-
- const filteredStaff = staff.filter(member =>
- !searchTerm ||
- member.employee_name?.toLowerCase().includes(searchTerm.toLowerCase()) ||
- member.vendor_name?.toLowerCase().includes(searchTerm.toLowerCase())
- );
-
- return (
-
-
-
-
Workforce Compliance
-
Monitor background checks, certifications, and fair wage compliance
-
-
- {/* Compliance Overview */}
-
-
-
-
-
- = 95 ? "bg-green-100 text-green-700" : "bg-amber-100 text-amber-700"}>
- {complianceRate}%
-
-
- Background Checks
- {backgroundCheckCompliant}/{totalStaff}
-
-
-
-
-
-
-
- = 100 ? "bg-green-100 text-green-700" : "bg-red-100 text-red-700"}>
- {wageComplianceRate}%
-
-
- Fair Wage Compliance
- {wageCompliant}/{rates.length}
-
-
-
-
-
-
- Certified Staff
- {certifiedStaff}
-
-
-
-
-
-
-
-
- Active Workforce
- {totalStaff}
-
-
-
-
- {/* Search */}
-
-
-
-
- setSearchTerm(e.target.value)}
- className="pl-10"
- />
-
-
-
-
- {/* Staff Compliance List */}
-
-
- Workforce Compliance Status
-
-
-
- {filteredStaff.map((member) => {
- const hasBackgroundCheck = member.background_check_status === "cleared";
- const hasCertifications = member.certifications?.length > 0;
-
- return (
-
-
-
-
-
{member.employee_name}
- {member.vendor_name || "N/A"}
-
-
{member.position || "Staff Member"}
-
- {hasBackgroundCheck ? (
-
-
- Background Check ✓
-
- ) : (
-
-
- No Background Check
-
- )}
- {hasCertifications ? (
-
- ) : (
-
- )}
-
-
-
- {hasBackgroundCheck && hasCertifications ? "Compliant" : "Review Required"}
-
-
-
- );
- })}
-
-
-
-
-
- );
-}
\ No newline at end of file
diff --git a/frontend-web/src/pages/WorkforceDashboard.jsx b/frontend-web/src/pages/WorkforceDashboard.jsx
deleted file mode 100644
index 9f4e702f..00000000
--- a/frontend-web/src/pages/WorkforceDashboard.jsx
+++ /dev/null
@@ -1,178 +0,0 @@
-
-import React from "react";
-import { base44 } from "@/api/base44Client";
-import { useQuery } from "@tanstack/react-query";
-import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
-import { Badge } from "@/components/ui/badge";
-import { Button } from "@/components/ui/button";
-import { Users, MapPin, DollarSign, Award, BookOpen, TrendingUp, Star, Clock, ArrowLeft, Calendar } from "lucide-react";
-import { useNavigate } from "react-router-dom";
-import { createPageUrl } from "@/utils";
-import PageHeader from "@/components/common/PageHeader";
-
-export default function WorkforceDashboard() {
- const navigate = useNavigate();
-
- const { data: staff } = useQuery({
- queryKey: ['staff'],
- queryFn: () => base44.entities.Staff.list('-rating'),
- initialData: [],
- });
-
- const topPerformers = staff.slice(0, 6);
- const avgRating = staff.length > 0 ? (staff.reduce((sum, s) => sum + (s.rating || 0), 0) / staff.length).toFixed(1) : 0;
- const avgCoverage = staff.length > 0 ? Math.round(staff.reduce((sum, s) => sum + (s.shift_coverage_percentage || 0), 0) / staff.length) : 0;
-
- return (
-
-
-
-
- {/* Key Metrics */}
-
-
-
-
-
- {staff.length}
-
- Active Workers
- {staff.length}
-
-
-
-
-
-
-
- {avgRating}/5
-
- Avg Rating
- {avgRating}
-
-
-
-
-
-
-
- {avgCoverage}%
-
- Avg Coverage
- {avgCoverage}%
-
-
-
-
-
-
-
- 89%
-
- Training Complete
- 89%
-
-
-
-
- {/* Top Performers */}
-
-
-
-
- Top Performers
-
-
-
-
- {topPerformers.map((worker, index) => (
-
- {index < 3 && (
-
- {index + 1}
-
- )}
-
-
- {worker.initial || worker.employee_name?.charAt(0)}
-
-
-
{worker.employee_name}
-
{worker.position}
-
-
-
-
-
Rating
-
-
- {(worker.rating || 0).toFixed(1)}
-
-
-
-
Coverage
-
{worker.shift_coverage_percentage || 0}%
-
-
-
- Tier: {(worker.rating || 0) >= 4.5 ? 'Gold' : (worker.rating || 0) >= 4.0 ? 'Silver' : 'Bronze'}
-
-
- ))}
-
-
-
-
- {/* Feature Cards */}
-
-
-
-
-
-
- Job Feed
- Browse available shifts
- 24 Available
-
-
-
-
-
-
-
-
- Geo Check-In
- Clock in/out at events
- Location-based
-
-
-
-
-
-
-
-
- KROW University
- Training & certifications
- 89% Complete
-
-
-
-
-
-
-
-
- Earnings
- Track your income
- $4,280 MTD
-
-
-
-
-
- );
-}
diff --git a/frontend-web/src/pages/WorkforceEarnings.jsx b/frontend-web/src/pages/WorkforceEarnings.jsx
deleted file mode 100644
index 643e8e52..00000000
--- a/frontend-web/src/pages/WorkforceEarnings.jsx
+++ /dev/null
@@ -1,111 +0,0 @@
-import React from "react";
-import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
-import { DollarSign, TrendingUp, Calendar, Award } from "lucide-react";
-import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
-
-export default function WorkforceEarnings() {
- const earningsData = [
- { month: 'Jan', earnings: 2400, hours: 96 },
- { month: 'Feb', earnings: 2800, hours: 112 },
- { month: 'Mar', earnings: 3200, hours: 128 },
- { month: 'Apr', earnings: 2600, hours: 104 },
- { month: 'May', earnings: 3400, hours: 136 },
- ];
-
- const stats = {
- totalEarnings: 14400,
- thisMonth: 3400,
- totalHours: 576,
- avgHourly: 25,
- };
-
- return (
-
-
-
-
My Earnings
-
Track your income and hours worked
-
-
- {/* Stats */}
-
-
-
-
- Total Earnings (YTD)
- ${stats.totalEarnings.toLocaleString()}
-
-
-
-
-
-
- This Month
- ${stats.thisMonth.toLocaleString()}
-
-
-
-
-
-
- Total Hours
- {stats.totalHours}
-
-
-
-
-
-
- Avg Hourly
- ${stats.avgHourly}
-
-
-
-
- {/* Earnings Chart */}
-
-
- Monthly Earnings
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {/* Payment History */}
-
-
- Recent Payments
-
-
-
- {[
- { date: "May 15, 2025", event: "Tech Conference 2025", hours: 32, amount: 800 },
- { date: "May 8, 2025", event: "Product Launch", hours: 24, amount: 600 },
- { date: "May 1, 2025", event: "Corporate Event", hours: 40, amount: 1000 },
- ].map((payment, index) => (
-
-
-
{payment.event}
-
{payment.date} • {payment.hours} hours
-
-
${payment.amount}
-
- ))}
-
-
-
-
-
- );
-}
\ No newline at end of file
diff --git a/frontend-web/src/pages/WorkforceProfile.jsx b/frontend-web/src/pages/WorkforceProfile.jsx
deleted file mode 100644
index c199f4cc..00000000
--- a/frontend-web/src/pages/WorkforceProfile.jsx
+++ /dev/null
@@ -1,255 +0,0 @@
-
-import React, { useState } from "react";
-import { base44 } from "@/api/base44Client";
-import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
-import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
-import { Button } from "@/components/ui/button";
-import { Badge } from "@/components/ui/badge";
-import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
-import { User, Mail, Phone, MapPin, Award, Star, Edit, Camera, Upload } from "lucide-react";
-import { useToast } from "@/components/ui/use-toast";
-import {
- Dialog,
- DialogContent,
- DialogHeader,
- DialogTitle,
- DialogFooter,
-} from "@/components/ui/dialog";
-
-export default function WorkforceProfile() {
- const [showUploadDialog, setShowUploadDialog] = useState(false);
- const [uploading, setUploading] = useState(false);
- const queryClient = useQueryClient();
- const { toast } = useToast();
-
- const { data: user } = useQuery({
- queryKey: ['current-user'],
- queryFn: () => base44.auth.me(),
- });
-
- // Sample avatar if user doesn't have one
- const sampleAvatar = "https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=400&h=400&fit=crop";
- const userAvatar = user?.profile_picture || sampleAvatar;
-
- const updateProfilePictureMutation = useMutation({
- mutationFn: (profilePictureUrl) => base44.auth.updateMe({ profile_picture: profilePictureUrl }),
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ['current-user'] });
- toast({
- title: "Profile Picture Updated",
- description: "Your profile picture has been updated successfully",
- });
- setShowUploadDialog(false);
- },
- });
-
- const handleFileUpload = async (event) => {
- const file = event.target.files?.[0];
- if (!file) return;
-
- // Validate file type
- if (!file.type.startsWith('image/')) {
- toast({
- title: "Invalid File",
- description: "Please upload an image file",
- variant: "destructive",
- });
- return;
- }
-
- // Validate file size (max 5MB)
- if (file.size > 5 * 1024 * 1024) {
- toast({
- title: "File Too Large",
- description: "Please upload an image smaller than 5MB",
- variant: "destructive",
- });
- return;
- }
-
- setUploading(true);
- try {
- const { file_url } = await base44.integrations.Core.UploadFile({ file });
- await updateProfilePictureMutation.mutateAsync(file_url);
- } catch (error) {
- toast({
- title: "Upload Failed",
- description: error.message || "Failed to upload profile picture",
- variant: "destructive",
- });
- } finally {
- setUploading(false);
- }
- };
-
- return (
-
-
-
-
My Profile
-
Manage your personal information and certifications
-
-
- {/* Profile Card */}
-
-
-
-
-
-
-
-
- {user?.full_name?.charAt(0) || user?.email?.charAt(0) || '?'}
-
-
-
-
-
-
{user?.full_name || 'User'}
-
Workforce
-
-
- 4.8 Rating
- •
- 127 completed shifts
-
-
-
-
-
-
-
-
-
-
-
Email
-
{user?.email}
-
-
-
-
-
-
-
Phone
-
{user?.phone || 'Not provided'}
-
-
-
-
-
-
-
Location
-
San Francisco, CA
-
-
-
-
-
-
- {/* Certifications */}
-
-
-
-
- Certifications & Training
-
-
-
-
- {[
- { name: "Food Handler Certificate", status: "Valid", expiry: "Dec 2025" },
- { name: "ServSafe Alcohol", status: "Valid", expiry: "Mar 2026" },
- { name: "First Aid & CPR", status: "Valid", expiry: "Aug 2025" },
- ].map((cert, index) => (
-
-
-
{cert.name}
-
Expires: {cert.expiry}
-
-
{cert.status}
-
- ))}
-
-
-
-
- {/* Performance Stats */}
-
-
- Performance Summary
-
-
-
-
-
97%
-
Attendance Rate
-
-
-
-
-
-
-
-
-
- {/* Upload Profile Picture Dialog */}
-
-
-
- Change Profile Picture
-
-
-
-
-
-
- {user?.full_name?.charAt(0) || user?.email?.charAt(0) || '?'}
-
-
-
-
-
PNG, JPG or GIF • Max 5MB
-
-
-
-
-
-
-
-
-
- );
-}
diff --git a/frontend-web/src/pages/WorkforceShifts.jsx b/frontend-web/src/pages/WorkforceShifts.jsx
deleted file mode 100644
index cba32a0f..00000000
--- a/frontend-web/src/pages/WorkforceShifts.jsx
+++ /dev/null
@@ -1,137 +0,0 @@
-
-import React from "react";
-import { base44 } from "@/api/base44Client";
-import { useQuery } from "@tanstack/react-query";
-import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
-import { Badge } from "@/components/ui/badge";
-import { Button } from "@/components/ui/button";
-import { Calendar, MapPin, Clock, DollarSign, CheckCircle2, AlertCircle } from "lucide-react";
-import { format } from "date-fns";
-
-// Safe date formatter
-const safeFormatDate = (dateString, formatStr) => {
- if (!dateString) return "Date TBD";
- try {
- const date = new Date(dateString);
- if (isNaN(date.getTime())) return "Date TBD";
- return format(date, formatStr);
- } catch {
- return "Date TBD";
- }
-};
-
-export default function WorkforceShifts() {
- const { data: user } = useQuery({
- queryKey: ['current-user'],
- queryFn: () => base44.auth.me(),
- });
-
- const { data: events } = useQuery({
- queryKey: ['workforce-events'],
- queryFn: () => base44.entities.Event.list('-date'),
- initialData: [],
- });
-
- // Filter events where this user is assigned
- const myShifts = events.filter(event =>
- event.assigned_staff?.some(staff => staff.staff_id === user?.id)
- );
-
- const upcoming = myShifts.filter(e => new Date(e.date) >= new Date()).length;
- const confirmed = myShifts.filter(e =>
- e.assigned_staff?.find(s => s.staff_id === user?.id)?.confirmed
- ).length;
- const pending = myShifts.filter(e =>
- !e.assigned_staff?.find(s => s.staff_id === user?.id)?.confirmed
- ).length;
-
- return (
-
-
-
-
My Shifts
-
View and manage your upcoming shifts
-
-
- {/* Stats */}
-
-
-
-
- Upcoming Shifts
- {upcoming}
-
-
-
-
-
-
- Confirmed
- {confirmed}
-
-
-
-
-
-
- Pending Confirmation
- {pending}
-
-
-
-
- {/* Shifts List */}
-
- {myShifts.map((shift) => {
- const staffInfo = shift.assigned_staff?.find(s => s.staff_id === user?.id);
- return (
-
-
-
-
-
-
{shift.event_name}
-
- {staffInfo?.confirmed ? "Confirmed" : "Pending"}
-
-
-
-
-
- {safeFormatDate(shift.date, 'PPP')}
-
-
-
- {shift.event_location || 'Location TBD'}
-
-
-
- 8:00 AM - 5:00 PM
-
-
-
- $25/hour
-
-
-
- {!staffInfo?.confirmed && (
-
- )}
-
- {shift.notes && (
-
-
Event Details:
-
{shift.notes}
-
- )}
-
-
- );
- })}
-
-
-
- );
-}
diff --git a/frontend-web/src/pages/api-docs-raw.jsx b/frontend-web/src/pages/api-docs-raw.jsx
deleted file mode 100644
index 3150790e..00000000
--- a/frontend-web/src/pages/api-docs-raw.jsx
+++ /dev/null
@@ -1,2015 +0,0 @@
-export default function ApiDocs() {
- return
Check the source code for the full API Markdown
;
-}
-
-/*
-# KROW Workforce Platform - API Documentation
-
-**Version:** 3.0 (Auto-Updated)
-**Last Updated:** 2025-11-20
-**Project:** KROW Workforce Control Tower
-
-## Table of Contents
-1. [Overview](#overview)
-2. [Authentication](#authentication)
-3. [Entity Schemas](#entity-schemas)
-4. [SDK Operations](#sdk-operations)
-5. [Core Integrations](#core-integrations)
-6. [Data Models Reference](#data-models-reference)
-7. [Code Examples](#code-examples)
-8. [Best Practices](#best-practices)
-9. [Security Considerations](#security-considerations)
-10. [Rate Limits & Quotas](#rate-limits--quotas)
-11. [Changelog](#changelog)
-12. [Support & Resources](#support--resources)
-
----
-
-## Overview
-KROW Workforce is a comprehensive workforce management platform built on Base44. This documentation provides complete API specifications for all entities, SDK methods, and integration endpoints.
-
-### Base44 Client Import
-```javascript
-import { base44 } from "@/api/base44Client";
-```
-
----
-
-## Authentication
-
-### User Authentication Methods
-```javascript
-// Get current authenticated user
-const user = await base44.auth.me();
-
-// Update current user
-await base44.auth.updateMe({
- full_name: "John Doe",
- custom_field: "value"
-});
-
-// Logout
-base44.auth.logout(redirectUrl?: string);
-
-// Redirect to login
-base44.auth.redirectToLogin(nextUrl?: string);
-
-// Check authentication status
-const isAuthenticated = await base44.auth.isAuthenticated();
-```
-
-### User Object Structure
-```json
-{
- "id": "string",
- "email": "string",
- "full_name": "string",
- "role": "admin" | "user",
- "user_role": "string",
- "created_date": "timestamp",
- "updated_date": "timestamp"
-}
-```
-
----
-
-## Entity Schemas
-
-### 1. User Entity (Built-in)
-Description: Core user entity with authentication and role management.
-
-| Field Name | Type | Description | Validation |
-| :--------- | :-------- | :---------------------- | :--------------------------------------- |
-| `id` | `string` | Unique user identifier | Auto-generated, unique |
-| `email` | `string` | User email address | Required, unique, email format |
-| `full_name`| `string` | User's full name | Required |
-| `role` | `string` | Base role | Enum: "admin", "user" |
-| `user_role`| `string` | Custom application role | Optional, custom values |
-| `created_date`| `timestamp`| Account creation date | Auto-generated |
-| `updated_date`| `timestamp`| Last update timestamp | Auto-updated |
-
-JSON Schema:
-```json
-{
- "type": "object",
- "properties": {
- "email": {"type": "string", "format": "email"},
- "full_name": {"type": "string"},
- "role": {"type": "string", "enum": ["admin", "user"]},
- "user_role": {"type": "string"}
- }
-}
-```
-
-Security Rules:
-- Only admin users can list, update, or delete other users
-- Regular users can only view and update their own user record
-- These rules are automatically enforced
-
-### 2. Event Entity
-Description: Core event/order management entity for workforce scheduling.
-
-| Field Name | Type | Description | Validation |
-| :--------- | :-------- | :---------------------- | :---------------------------------------------------------------------- |
-| `id` | `string` | Unique event identifier | Auto-generated |
-| `event_name`| `string` | Name of the event | Required |
-| `is_rapid` | `boolean` | RAPID/urgent order flag | Default: false |
-| `is_recurring`| `boolean`| Whether event recurs | Default: false |
-| `is_multi_day`| `boolean`| Multi-day event flag | Default: false |
-| `recurrence_type`| `string`| Type of recurrence | Enum: "single", "date_range", "scatter" |
-| `recurrence_start_date`| `date`| Start date for recurring events| Optional |
-| `recurrence_end_date`| `date`| End date for recurring events | Optional |
-| `scatter_dates`| `array` | Specific dates for scatter recurring| Array of date strings |
-| `multi_day_start_date`| `date`| Multi-day start date | Optional |
-| `multi_day_end_date`| `date`| Multi-day end date | Optional |
-| `buffer_time_before`| `number`| Buffer time before (minutes)| Default: 0 |
-| `buffer_time_after`| `number`| Buffer time after (minutes) | Default: 0 |
-| `conflict_detection_enabled`| `boolean`| Enable conflict detection| Default: true |
-| `detected_conflicts`| `array`| Array of detected conflicts | Array of conflict objects with type, severity, description |
-| `business_id`| `string` | Associated business ID | Optional |
-| `business_name`| `string` | Business name | Optional |
-| `vendor_id`| `string` | Vendor ID if created by vendor| Optional |
-| `vendor_name`| `string` | Vendor name | Optional |
-| `hub` | `string` | Hub location | Optional |
-| `event_location`| `string`| Event location address | Optional |
-| `contract_type`| `string`| Contract type | Enum: "W2", "1099", "Temp", "Contract" |
-| `po_reference`| `string`| Purchase order reference| Optional |
-| `status` | `string` | Event status | Enum: "Draft", "Active", "Pending", "Assigned", "Confirmed", "Completed", "Canceled" |
-| `date` | `date` | Event date | Optional |
-| `shifts` | `array` | Array of shift objects | Optional |
-| `addons` | `object` | Additional services/features| Optional |
-| `total` | `number` | Total cost | Optional |
-| `client_name`| `string` | Client contact name | Optional |
-| `client_email`| `string`| Client email | Optional |
-| `client_phone`| `string`| Client phone | Optional |
-| `invoice_id`| `string` | Associated invoice ID | Optional |
-| `notes` | `string` | Additional notes | Optional |
-| `requested`| `number` | Total staff requested | Optional |
-| `assigned_staff`| `array`| Array of assigned staff | Optional |
-| `created_date`| `timestamp`| Creation date | Auto-generated |
-| `updated_date`| `timestamp`| Last update | Auto-updated |
-| `created_by`| `string` | Creator email | Auto-populated |
-
-Shifts Structure:
-```json
-{
- "shift_name": "string",
- "shift_contact": "string",
- "location": "string",
- "location_address": "string",
- "roles": [
- {
- "role": "string",
- "department": "string",
- "count": "number",
- "start_time": "string",
- "end_time": "string",
- "hours": "number",
- "uniform": "string",
- "break_minutes": "number",
- "cost_per_hour": "number",
- "total_value": "number",
- "vendor_name": "string",
- "vendor_id": "string"
- }
- ]
-}
-```
-
-Detected Conflicts Structure:
-```json
-{
- "conflict_type": "staff_overlap" | "venue_overlap" | "time_buffer",
- "severity": "low" | "medium" | "high" | "critical",
- "description": "string",
- "conflicting_event_id": "string",
- "staff_id": "string",
- "detected_at": "timestamp"
-}
-```
-
-### 3. Staff Entity
-Description: Employee/workforce member management.
-
-| Field Name | Type | Description | Validation |
-| :--------- | :-------- | :---------------------- | :---------------------------------------------------------------------- |
-| `id` | `string` | Unique staff identifier | Auto-generated |
-| `employee_name`| `string`| Full name | Required |
-| `vendor_id`| `string` | Associated vendor ID | Optional |
-| `vendor_name`| `string`| Vendor company name | Optional |
-| `manager` | `string` | Manager's name | Optional |
-| `contact_number`| `string`| Primary contact number | Optional |
-| `phone` | `string` | Additional phone | Optional |
-| `email` | `string` | Email address | Email format |
-| `department`| `string` | Department | Enum: "Operations", "Sales", "HR", "Finance", "IT", "Marketing", "Customer Service", "Logistics" |
-| `hub_location`| `string`| Hub/office location | Optional |
-| `event_location`| `string`| Event location | Optional |
-| `track` | `string` | Track information | Optional |
-| `address` | `string` | Employee address | Optional |
-| `city` | `string` | City | Optional |
-| `position` | `string` | Primary job position/skill| Optional |
-| `position_2`| `string` | Secondary job position/skill| Optional |
-| `initial` | `string` | Employee initials | Optional |
-| `profile_type`| `string`| Skill profile level | Enum: "Skilled", "Beginner", "Cross-Trained" |
-| `employment_type`| `string`| Employment type | Enum: "Full Time", "Part Time", "On call", "Weekends", "Specific Days", "Seasonal", "Medical Leave" |
-| `english` | `string` | English proficiency | Enum: "Fluent", "Intermediate", "Basic", "None" |
-| `english_required`| `boolean`| English required | Optional |
-| `check_in` | `date` | Last check-in date | Optional |
-| `replaced_by`| `string` | Name of replacement employee| Optional |
-| `ro` | `string` | R.O field | Optional |
-| `mon` | `string` | MON field | Optional |
-| `schedule_days`| `string`| Working schedule days | Optional |
-| `invoiced` | `boolean` | Invoice status | Optional |
-| `action` | `string` | Current action or status| Optional |
-| `notes` | `string` | General notes about the employee| Optional |
-| `accounting_comments`| `string`| Comments from accounting| Optional |
-| `rating` | `number` | Staff performance rating| Min: 0, Max: 5 |
-| `shift_coverage_percentage`| `number`| Percentage of shifts covered| Min: 0, Max: 100 |
-| `cancellation_count`| `number`| Number of shift cancellations| Min: 0 |
-| `no_show_count`| `number`| Number of no-shows | Min: 0 |
-| `total_shifts`| `number`| Total number of shifts assigned| Min: 0 |
-| `reliability_score`| `number`| Overall reliability score| Min: 0, Max: 100 |
-| `background_check_status`| `string`| Background check status | Enum: "pending", "cleared", "failed", "expired", "not_required" |
-| `background_check_date`| `date`| Date of last background check| Optional |
-| `certifications`| `array`| List of certifications | Optional |
-| `created_date`| `timestamp`| Creation date | Auto-generated |
-| `updated_date`| `timestamp`| Last update | Auto-updated |
-| `created_by`| `string` | Creator email | Auto-populated |
-
-### 4. Vendor Entity
-Description: Vendor/supplier management and onboarding.
-
-| Field Name | Type | Description | Validation |
-| :--------- | :-------- | :---------------------- | :---------------------------------------------------------------------- |
-| `id` | `string` | Unique vendor identifier| Auto-generated |
-| `vendor_number`| `string`| Vendor Number (VN-####) | Required, Pattern: `^VN-[0-9]{4}$` |
-| `legal_name`| `string` | Legal business name | Required |
-| `doing_business_as`| `string`| DBA/Trade name | Optional |
-| `region` | `string` | Geographic region | Enum: "National", "Bay Area", "Southern California", "Northern California", "West", "East", "Midwest", "South" |
-| `state` | `string` | Primary state | Optional |
-| `city` | `string` | Primary city | Optional |
-| `service_specialty`| `string`| Service specialty | Optional |
-| `workforce_count`| `number`| Total workforce count | Optional |
-| `platform_type`| `string`| Technology integration level| Enum: "Full Platform", "Building platform (KROW)", "Partial Tech", "Traditional" |
-| `tax_id` | `string` | Federal Tax ID/EIN | Optional |
-| `business_type`| `string`| Business entity type | Enum: "Corporation", "LLC", "Partnership", "Sole Proprietorship" |
-| `primary_contact_name`| `string`| Primary contact | Optional |
-| `primary_contact_email`| `string`| Primary email | Required, Email format |
-| `primary_contact_phone`| `string`| Primary phone | Optional |
-| `billing_address`| `string`| Billing address | Optional |
-| `service_address`| `string`| Service/office address | Optional |
-| `coverage_regions`| `array`| Geographic regions vendor can service| Array of strings |
-| `eligible_roles`| `array`| Roles/positions vendor can provide| Array of strings |
-| `insurance_certificate`| `string`| URL to insurance certificate| Optional |
-| `insurance_expiry`| `date`| Insurance expiration date| Optional |
-| `w9_document`| `string` | URL to W9 form | Optional |
-| `coi_document`| `string` | URL to Certificate of Insurance| Optional |
-| `compliance_package_id`| `string`| Reference to compliance package| Optional |
-| `performance_scorecard_id`| `string`| Reference to performance scorecard| Optional |
-| `approval_status`| `string`| Vendor approval status | Enum: "pending", "approved", "suspended", "terminated" |
-| `approved_date`| `date` | Date vendor was approved| Optional |
-| `approved_by`| `string` | User who approved vendor| Optional |
-| `is_active`| `boolean` | Is vendor currently active| Default: true |
-| `notes` | `string` | Internal notes about vendor| Optional |
-| `created_date`| `timestamp`| Creation date | Auto-generated |
-| `updated_date`| `timestamp`| Last update | Auto-updated |
-| `created_by`| `string` | Creator email | Auto-populated |
-
-### 5. VendorRate Entity
-Description: Vendor pricing and rate management.
-
-| Field Name | Type | Description | Validation |
-| :--------- | :-------- | :---------------------- | :---------------------------------------------------------------------- |
-| `id` | `string` | Unique rate identifier | Auto-generated |
-| `vendor_id`| `string` | Vendor ID | Optional |
-| `vendor_name`| `string`| Vendor name | Required |
-| `category` | `string` | Service category | Enum: "Kitchen and Culinary", "Concessions", "Facilities", "Bartending", "Security", "Event Staff", "Management", "Technical", "Other" |
-| `role_name`| `string` | Role/position name | Required |
-| `employee_wage`| `number`| Employee base wage/hour | Required, Min: 0 |
-| `markup_percentage`| `number`| Markup percentage | Min: 0, Max: 100 |
-| `vendor_fee_percentage`| `number`| Vendor fee percentage | Min: 0, Max: 100 |
-| `client_rate`| `number` | Final rate to client | Required, Min: 0 |
-| `is_active`| `boolean` | Active status | Default: true |
-| `minimum_wage_compliance`| `boolean`| Meets minimum wage | Optional |
-| `pricing_status`| `string`| Pricing analysis | Enum: "optimal", "underpriced", "overpriced", "competitive" |
-| `market_average`| `number`| Market average rate | Optional |
-| `notes` | `string` | Additional notes | Optional |
-| `available_to_clients`| `array`| Client IDs with access | Array of strings |
-| `client_visibility`| `string`| Visibility setting | Enum: "all", "specific", "none" |
-| `competitive_status`| `boolean`| Competitive pricing | Default: false |
-| `csta_compliant`| `boolean`| CA Staffing Agency compliant| Default: false |
-| `compliance_verified`| `boolean`| Compliance verified | Default: false |
-| `created_date`| `timestamp`| Creation date | Auto-generated |
-| `updated_date`| `timestamp`| Last update | Auto-updated |
-| `created_by`| `string` | Creator email | Auto-populated |
-
-### 6. VendorDefaultSettings Entity
-Description: Default markup and fee settings for vendors.
-
-| Field Name | Type | Description | Validation |
-| :--------- | :-------- | :---------------------- | :---------------------------------------------------------------------- |
-| `id` | `string` | Unique settings identifier| Auto-generated |
-| `vendor_name`| `string`| Name of the vendor | Required |
-| `default_markup_percentage`| `number`| Default markup percentage for this vendor| Required, Min: 0, Max: 100 |
-| `default_vendor_fee_percentage`| `number`| Default vendor fee percentage for this vendor| Required, Min: 0, Max: 100 |
-| `notes` | `string` | Additional notes about vendor defaults| Optional |
-| `created_date`| `timestamp`| Creation date | Auto-generated |
-| `updated_date`| `timestamp`| Last update | Auto-updated |
-| `created_by`| `string` | Creator email | Auto-populated |
-
-### 7. Invoice Entity
-Description: Invoice and billing management.
-
-| Field Name | Type | Description | Validation |
-| :--------- | :-------- | :---------------------- | :---------------------------------------------------------------------- |
-| `id` | `string` | Unique invoice identifier| Auto-generated |
-| `invoice_number`| `string`| Unique invoice number | Required |
-| `event_name`| `string` | Name of the event | Optional |
-| `event_id` | `string` | Related event ID | Optional |
-| `po_reference`| `string`| Purchase order reference| Optional |
-| `event_date`| `date` | Event date | Optional |
-| `from_company`| `object`| Vendor company information| Optional |
-| `to_company`| `object` | Client company information| Optional |
-| `business_name`| `string`| Client/Business name | Required |
-| `manager_name`| `string`| Manager/client name | Optional |
-| `vendor_name`| `string`| Vendor providing services| Optional |
-| `vendor_id`| `string` | Vendor ID | Optional |
-| `hub` | `string` | Hub location | Optional |
-| `cost_center`| `string` | Cost center or department| Optional |
-| `roles` | `array` | Grouped by role with staff details| Optional |
-| `subtotal` | `number` | Subtotal amount | Optional |
-| `other_charges`| `number`| Additional charges | Optional |
-| `amount` | `number` | Grand total invoice amount| Required, Min: 0 |
-| `tax_amount`| `number` | Tax amount | Optional |
-| `tax_rate` | `number` | Tax rate percentage | Optional |
-| `status` | `string` | Current invoice status | Enum: "Draft", "Pending Review", "Approved", "Disputed", "Under Review", "Resolved", "Overdue", "Paid", "Reconciled", "Cancelled" |
-| `issue_date`| `date` | Invoice issue date | Required |
-| `due_date` | `date` | Payment due date | Required |
-| `paid_date`| `date` | Date payment was received| Optional |
-| `payment_method`| `string`| Payment method used | Enum: "Credit Card", "ACH", "Wire Transfer", "Check", "Cash" |
-| `payment_reference`| `string`| Payment reference/transaction ID| Optional |
-| `dispute_reason`| `string`| Reason for dispute | Optional |
-| `dispute_details`| `string`| Detailed dispute information| Optional |
-| `disputed_items`| `array`| List of disputed staff entry indices| Optional |
-| `disputed_by`| `string`| User who disputed the invoice| Optional |
-| `disputed_date`| `timestamp`| When dispute was raised | Optional |
-| `resolution_notes`| `string`| Notes about dispute resolution| Optional |
-| `approved_by`| `string`| User who approved the invoice| Optional |
-| `approved_date`| `timestamp`| When invoice was approved| Optional |
-| `is_auto_generated`| `boolean`| Whether invoice was auto-generated from event| Default: false |
-| `pdf_url` | `string` | URL to PDF version of invoice| Optional |
-| `notes` | `string` | Additional notes about the invoice| Optional |
-| `internal_notes`| `string`| Internal notes not visible to client| Optional |
-| `created_date`| `timestamp`| Creation date | Auto-generated |
-| `updated_date`| `timestamp`| Last update | Auto-updated |
-| `created_by`| `string` | Creator email | Auto-populated |
-
-### 8. Business Entity
-Description: Client business/company management.
-
-| Field Name | Type | Description | Validation |
-| :--------- | :-------- | :---------------------- | :---------------------------------------------------------------------- |
-| `id` | `string` | Unique business identifier| Auto-generated |
-| `business_name`| `string`| Business/client company name| Required |
-| `company_logo`| `string`| URL to company logo | Optional |
-| `contact_name`| `string`| Primary contact person | Required |
-| `email` | `string` | Business email | Email format |
-| `phone` | `string` | Business phone | Optional |
-| `hub_building`| `string`| Hub/building name | Optional |
-| `address` | `string` | Street address | Optional |
-| `city` | `string` | City | Optional |
-| `area` | `string` | Geographic area | Enum: "Bay Area", "Southern California", "Northern California", "Central Valley", "Other" |
-| `sector` | `string` | Sector/industry | Enum: "Bon Appétit", "Eurest", "Aramark", "Epicurean Group", "Chartwells", "Other" |
-| `rate_group`| `string` | Pricing tier | Required, Enum: "Standard", "Premium", "Enterprise", "Custom" |
-| `status` | `string` | Business status | Enum: "Active", "Inactive", "Pending" |
-| `notes` | `string` | Additional notes | Optional |
-| `created_date`| `timestamp`| Creation date | Auto-generated |
-| `updated_date`| `timestamp`| Last update | Auto-updated |
-| `created_by`| `string` | Creator email | Auto-populated |
-
-### 9. Certification Entity
-Description: Employee certification and compliance tracking.
-
-| Field Name | Type | Description | Validation |
-| :--------- | :-------- | :---------------------- | :---------------------------------------------------------------------- |
-| `id` | `string` | Unique certification ID | Auto-generated |
-| `employee_id`| `string`| Staff member ID | Optional |
-| `employee_name`| `string`| Staff member name | Required |
-| `vendor_id`| `string` | Vendor ID | Optional |
-| `vendor_name`| `string`| Vendor name | Optional |
-| `certification_name`| `string`| Certification name | Required |
-| `certification_type`| `string`| Type of certification | Enum: "Legal", "Operational", "Safety", "Training", "License", "Other" |
-| `status` | `string` | Current status | Enum: "current", "expiring_soon", "expired", "pending_validation" |
-| `issue_date`| `date` | Issue date | Optional |
-| `expiry_date`| `date` | Expiration date | Required |
-| `issuer` | `string` | Issuing authority | Optional |
-| `certificate_number`| `string`| Certificate ID | Optional |
-| `document_url`| `string`| Uploaded certificate URL| Optional |
-| `validation_status`| `string`| Validation status | Enum: "approved", "pending_expert_review", "rejected", "ai_verified", "ai_flagged", "manual_review_needed" |
-| `ai_validation_result`| `object`| AI validation results | Optional |
-| `validated_by`| `string`| Validator | Optional |
-| `validated_date`| `date`| Validation date | Optional |
-| `is_required_for_role`| `boolean`| Required for role | Default: false |
-| `days_until_expiry`| `number`| Auto-calculated days | Optional |
-| `alert_sent`| `boolean` | Expiry alert sent | Default: false |
-| `notes` | `string` | Additional notes | Optional |
-| `created_date`| `timestamp`| Creation date | Auto-generated |
-| `updated_date`| `timestamp`| Last update | Auto-updated |
-| `created_by`| `string` | Creator email | Auto-populated |
-
-### 10. Team Entity
-Description: Team and organization management.
-
-| Field Name | Type | Description | Validation |
-| :--------- | :-------- | :---------------------- | :---------------------------------------------------------------------- |
-| `id` | `string` | Unique team identifier | Auto-generated |
-| `team_name`| `string` | Name of the team | Required |
-| `owner_id` | `string` | Team owner user ID | Required |
-| `owner_name`| `string` | Team owner name | Required |
-| `owner_role`| `string` | Role of team owner | Required, Enum: "admin", "procurement", "operator", "sector", "client", "vendor", "workforce" |
-| `company_logo`| `string`| URL to company logo | Optional |
-| `full_name`| `string` | Primary contact name | Optional |
-| `email` | `string` | Contact email | Email format |
-| `phone` | `string` | Contact phone | Optional |
-| `address` | `string` | Company address | Optional |
-| `city` | `string` | City | Optional |
-| `zip_code` | `string` | ZIP code | Optional |
-| `vendor_id`| `string` | Vendor ID if applicable | Optional |
-| `departments`| `array` | Available departments | Array of strings |
-| `total_members`| `number`| Total team members | Default: 0 |
-| `active_members`| `number`| Active members | Default: 0 |
-| `total_hubs`| `number` | Total hubs | Default: 0 |
-| `favorite_staff`| `array`| Array of favorite staff | Array of objects with staff_id, staff_name, position, added_date |
-| `blocked_staff`| `array`| Array of blocked staff | Array of objects with staff_id, staff_name, reason, blocked_date |
-| `favorite_staff_count`| `number`| Favorite staff count | Default: 0 |
-| `blocked_staff_count`| `number`| Blocked staff count | Default: 0 |
-| `created_date`| `timestamp`| Creation date | Auto-generated |
-| `updated_date`| `timestamp`| Last update | Auto-updated |
-| `created_by`| `string` | Creator email | Auto-populated |
-
-### 11. TeamMember Entity
-Description: Team member management within teams.
-
-| Field Name | Type | Description | Validation |
-| :--------- | :-------- | :---------------------- | :---------------------------------------------------------------------- |
-| `id` | `string` | Unique member identifier| Auto-generated |
-| `team_id` | `string` | Team ID | Required |
-| `member_name`| `string`| Member name | Required |
-| `email` | `string` | Member email | Required, Email format |
-| `phone` | `string` | Member phone | Optional |
-| `title` | `string` | Job title | Optional |
-| `role` | `string` | Team role | Enum: "admin", "manager", "member", "viewer" |
-| `department`| `string` | Department | Optional |
-| `hub` | `string` | Assigned hub | Optional |
-| `is_active`| `boolean` | Active status | Default: true |
-| `permissions`| `array` | Permissions | Array of strings |
-| `avatar_url`| `string` | URL to member avatar | Optional |
-| `created_date`| `timestamp`| Creation date | Auto-generated |
-| `updated_date`| `timestamp`| Last update | Auto-updated |
-| `created_by`| `string` | Creator email | Auto-populated |
-
-### 12. TeamHub Entity
-Description: Team hub/location management.
-
-| Field Name | Type | Description | Validation |
-| :--------- | :-------- | :---------------------- | :---------------------------------------------------------------------- |
-| `id` | `string` | Unique hub identifier | Auto-generated |
-| `team_id` | `string` | Team ID | Required |
-| `hub_name` | `string` | Name of the hub/location| Required |
-| `address` | `string` | Hub address | Optional |
-| `city` | `string` | City | Optional |
-| `state` | `string` | State | Optional |
-| `zip_code` | `string` | ZIP code | Optional |
-| `manager_name`| `string`| Hub manager name | Optional |
-| `manager_email`| `string`| Hub manager email | Email format |
-| `departments`| `array` | Departments within this hub| Array of objects with department_name, cost_center |
-| `is_active`| `boolean` | Whether the hub is active| Default: true |
-| `created_date`| `timestamp`| Creation date | Auto-generated |
-| `updated_date`| `timestamp`| Last update | Auto-updated |
-| `created_by`| `string` | Creator email | Auto-populated |
-
-Departments Structure:
-```json
-{
- "department_name": "string",
- "cost_center": "string"
-}
-```
-
-### 13. TeamMemberInvite Entity
-Description: Team member invitation management.
-
-| Field Name | Type | Description | Validation |
-| :--------- | :-------- | :---------------------- | :---------------------------------------------------------------------- |
-| `id` | `string` | Unique invite identifier| Auto-generated |
-| `team_id` | `string` | Team ID | Required |
-| `team_name`| `string` | Team name | Optional |
-| `invite_code`| `string`| Unique invite code | Required |
-| `email` | `string` | Invitee email | Required, Email format |
-| `full_name`| `string` | Invitee full name | Optional |
-| `phone` | `string` | Invitee phone | Optional |
-| `role` | `string` | Assigned role | Optional |
-| `title` | `string` | Job title | Optional |
-| `hub` | `string` | Assigned hub | Optional |
-| `department`| `string` | Assigned department | Optional |
-| `invited_by`| `string` | Inviter email/name | Optional |
-| `invite_status`| `string`| Invite status | Enum: "pending", "accepted", "expired", "cancelled" |
-| `invited_date`| `timestamp`| Invitation date | Optional |
-| `accepted_date`| `timestamp`| Acceptance date | Optional |
-| `expires_at`| `timestamp`| Expiration date | Optional |
-| `created_date`| `timestamp`| Creation date | Auto-generated |
-| `updated_date`| `timestamp`| Last update | Auto-updated |
-| `created_by`| `string` | Creator email | Auto-populated |
-
-### 14. Conversation Entity
-Description: Messaging and communication management.
-
-| Field Name | Type | Description | Validation |
-| :--------- | :-------- | :---------------------- | :---------------------------------------------------------------------- |
-| `id` | `string` | Unique conversation ID | Auto-generated |
-| `participants`| `array` | Array of participant objects| Required |
-| `conversation_type`| `string`| Type of conversation | Required, Enum: "client-vendor", "staff-client", "staff-admin", "vendor-admin", "client-admin", "group-staff", "group-event-staff" |
-| `is_group` | `boolean` | Is group conversation | Default: false |
-| `group_name`| `string` | Group name | Optional |
-| `related_to`| `string` | Related entity ID | Optional |
-| `related_type`| `string`| Related entity type | Enum: "event", "staff", "business", "general" |
-| `subject` | `string` | Conversation subject | Optional |
-| `last_message`| `string`| Preview of last message | Optional |
-| `last_message_at`| `timestamp`| Last message timestamp | Optional |
-| `unread_count`| `number`| Unread message count | Default: 0 |
-| `status` | `string` | Conversation status | Enum: "active", "archived", "closed" |
-| `created_date`| `timestamp`| Creation date | Auto-generated |
-| `updated_date`| `timestamp`| Last update | Auto-updated |
-| `created_by`| `string` | Creator email | Auto-populated |
-
-### 15. Message Entity
-Description: Individual messages within conversations.
-
-| Field Name | Type | Description | Validation |
-| :--------- | :-------- | :---------------------- | :---------------------------------------------------------------------- |
-| `id` | `string` | Unique message identifier| Auto-generated |
-| `conversation_id`| `string`| Conversation ID | Required |
-| `sender_id`| `string` | Sender ID | Optional |
-| `sender_name`| `string`| Sender name | Required |
-| `sender_role`| `string`| Sender role | Enum: "client", "vendor", "staff", "admin" |
-| `content` | `string` | Message content | Required |
-| `read_by` | `array` | User IDs who read | Array of strings |
-| `attachments`| `array` | Attached files | Array of objects |
-| `created_date`| `timestamp`| Creation date | Auto-generated |
-| `updated_date`| `timestamp`| Last update | Auto-updated |
-| `created_by`| `string` | Creator email | Auto-populated |
-
-### 16. ActivityLog Entity
-Description: Activity and notification tracking.
-
-| Field Name | Type | Description | Validation |
-| :--------- | :-------- | :---------------------- | :---------------------------------------------------------------------- |
-| `id` | `string` | Unique activity identifier| Auto-generated |
-| `title` | `string` | Notification title | Required |
-| `description`| `string`| Detailed description | Required |
-| `activity_type`| `string`| Type of activity | Required, Enum: "event_created", "event_updated", "event_rescheduled", "event_canceled", "staff_assigned", "staff_removed", "invoice_paid", "invoice_created", "message_received", "order_created", "order_updated" |
-| `related_entity_type`| `string`| Related entity type | Enum: "event", "staff", "invoice", "message", "order", "user" |
-| `related_entity_id`| `string`| Related entity ID | Optional |
-| `action_link`| `string`| Link to related item | Optional |
-| `action_label`| `string`| Action button label | Optional |
-| `user_id` | `string` | User this is for | Required |
-| `is_read` | `boolean` | Read status | Default: false |
-| `icon_type`| `string` | Icon to display | Enum: "calendar", "user", "invoice", "message", "alert", "check" |
-| `icon_color`| `string` | Icon color theme | Enum: "blue", "red", "green", "yellow", "purple" |
-| `created_date`| `timestamp`| Creation date | Auto-generated |
-| `updated_date`| `timestamp`| Last update | Auto-updated |
-| `created_by`| `string` | Creator email | Auto-populated |
-
-### 17. Enterprise Entity
-Description: Enterprise organization management.
-
-| Field Name | Type | Description | Validation |
-| :--------- | :-------- | :---------------------- | :---------------------------------------------------------------------- |
-| `id` | `string` | Unique enterprise ID | Auto-generated |
-| `enterprise_number`| `string`| Enterprise Number (EN-####)| Required, Pattern: `^EN-[0-9]{4}$` |
-| `enterprise_name`| `string`| Enterprise name | Required |
-| `enterprise_code`| `string`| Short code identifier | Required |
-| `brand_family`| `array` | Brands under enterprise | Array of strings |
-| `headquarters_address`| `string`| HQ address | Optional |
-| `global_policies`| `object`| Global policies | Optional |
-| `sector_registry`| `array`| Sector IDs | Array of strings |
-| `rate_guardrails`| `object`| Rate limits | Optional |
-| `primary_contact_name`| `string`| Contact name | Optional |
-| `primary_contact_email`| `string`| Contact email | Email format |
-| `is_active`| `boolean` | Active status | Default: true |
-| `created_date`| `timestamp`| Creation date | Auto-generated |
-| `updated_date`| `timestamp`| Last update | Auto-updated |
-| `created_by`| `string` | Creator email | Auto-populated |
-
-### 18. Sector Entity
-Description: Sector/branch management.
-
-| Field Name | Type | Description | Validation |
-| :--------- | :-------- | :---------------------- | :---------------------------------------------------------------------- |
-| `id` | `string` | Unique sector identifier| Auto-generated |
-| `sector_number`| `string`| Sector Number (SN-####) | Required, Pattern: `^SN-[0-9]{4}$` |
-| `sector_name`| `string` | Sector/brand name | Required |
-| `sector_code`| `string` | Short code identifier | Required |
-| `parent_enterprise_id`| `string`| Parent enterprise ID | Optional |
-| `parent_enterprise_name`| `string`| Parent enterprise name | Optional |
-| `sector_type`| `string` | Sector business type | Enum: "Food Service", "Facilities", "Healthcare", "Education", "Corporate", "Sports & Entertainment" |
-| `client_portfolio`| `array`| Partner/client IDs | Array of strings |
-| `sector_policies`| `object`| Sector-specific policies| Optional |
-| `approved_vendors`| `array`| Approved vendor IDs | Array of strings |
-| `is_active`| `boolean` | Active status | Default: true |
-| `created_date`| `timestamp`| Creation date | Auto-generated |
-| `updated_date`| `timestamp`| Last update | Auto-updated |
-| `created_by`| `string` | Creator email | Auto-populated |
-
-### 19. Partner Entity
-Description: Partner/client organization management.
-
-| Field Name | Type | Description | Validation |
-| :--------- | :-------- | :---------------------- | :---------------------------------------------------------------------- |
-| `id` | `string` | Unique partner identifier| Auto-generated |
-| `partner_name`| `string`| Partner/client name | Required |
-| `partner_number`| `string`| Partner Number (PN-####)| Required, Pattern: `^PN-[0-9]{4}$` |
-| `partner_type`| `string`| Partner type | Enum: "Corporate", "Education", "Healthcare", "Sports & Entertainment", "Government" |
-| `sector_id`| `string` | Sector ID | Optional |
-| `sector_name`| `string`| Sector name | Optional |
-| `primary_contact_name`| `string`| Primary contact | Optional |
-| `primary_contact_email`| `string`| Primary email | Email format |
-| `primary_contact_phone`| `string`| Primary phone | Optional |
-| `billing_address`| `string`| Billing address | Optional |
-| `sites` | `array` | Partner sites/locations | Array of objects |
-| `allowed_vendors`| `array`| Allowed vendor IDs | Array of strings |
-| `rate_exceptions`| `array`| Rate exceptions | Array of objects |
-| `cost_centers`| `array` | Cost centers/PO numbers | Array of strings |
-| `payment_terms`| `string`| Payment terms | Default: "Net 30" |
-| `is_active`| `boolean` | Active status | Default: true |
-| `created_date`| `timestamp`| Creation date | Auto-generated |
-| `updated_date`| `timestamp`| Last update | Auto-updated |
-| `created_by`| `string` | Creator email | Auto-populated |
-
-### 20. Order Entity
-Description: Order management system.
-
-| Field Name | Type | Description | Validation |
-| :--------- | :-------- | :---------------------- | :---------------------------------------------------------------------- |
-| `id` | `string` | Unique order identifier | Auto-generated |
-| `order_number`| `string`| Order Number (ORD-####) | Required, Pattern: `^ORD-[0-9]{4,6}$` |
-| `partner_id`| `string` | Partner/Client ID | Required |
-| `partner_name`| `string`| Partner/Client name | Optional |
-| `site_id` | `string` | Site/location ID | Optional |
-| `site_name`| `string` | Site/location name | Optional |
-| `site_address`| `string`| Event/site address | Optional |
-| `sector_id`| `string` | Sector ID | Optional |
-| `enterprise_id`| `string`| Enterprise ID | Optional |
-| `order_type`| `string` | Type of order | Enum: "Standard", "Last Minute", "Emergency", "Recurring" |
-| `cost_center`| `string`| Cost center | Optional |
-| `po_number`| `string` | Purchase order number | Optional |
-| `roles_requested`| `array`| Roles and headcount | Array of objects |
-| `tags` | `array` | Order tags/labels | Array of strings |
-| `point_of_contact`| `object`| On-site contact | Optional |
-| `sla_targets`| `object`| SLA targets | Optional |
-| `order_status`| `string`| Order status | Enum: "Draft", "Submitted", "Confirmed", "In Progress", "Completed", "Cancelled" |
-| `submitted_date`| `timestamp`| Submission date | Optional |
-| `confirmed_date`| `timestamp`| Confirmation date | Optional |
-| `special_instructions`| `string`| Special instructions | Optional |
-| `total_estimated_cost`| `number`| Estimated total cost | Optional |
-| `created_date`| `timestamp`| Creation date | Auto-generated |
-| `updated_date`| `timestamp`| Last update | Auto-updated |
-| `created_by`| `string` | Creator email | Auto-populated |
-
-### 21. Shift Entity
-Description: Shift scheduling and management.
-
-| Field Name | Type | Description | Validation |
-| :--------- | :-------- | :---------------------- | :---------------------------------------------------------------------- |
-| `id` | `string` | Unique shift identifier | Auto-generated |
-| `event_id` | `string` | Associated event ID | Optional |
-| `shift_name`| `string` | Name of the shift | Required |
-| `manager_id`| `string` | Manager staff ID | Optional |
-| `manager_name`| `string`| Manager name | Optional |
-| `location` | `string` | Shift location | Optional |
-| `start_date`| `timestamp`| Shift start date/time | Required |
-| `end_date` | `timestamp`| Shift end date/time | Optional |
-| `unpaid_break`| `number`| Unpaid break in minutes | Optional |
-| `count` | `number` | Number of staff needed | Optional |
-| `assigned` | `number` | Number of staff assigned| Optional |
-| `uniform_type`| `string`| Required uniform type | Optional |
-| `price` | `number` | Price per staff member | Optional |
-| `amount` | `number` | Total amount for shift | Optional |
-| `assigned_staff`| `array`| List of assigned staff | Array of objects |
-| `role` | `string` | Role for this shift | Optional |
-| `department`| `string` | Department | Optional |
-| `created_date`| `timestamp`| Creation date | Auto-generated |
-| `updated_date`| `timestamp`| Last update | Auto-updated |
-| `created_by`| `string` | Creator email | Auto-populated |
-
-### 22. Assignment Entity
-Description: Worker assignment and tracking.
-
-| Field Name | Type | Description | Validation |
-| :--------- | :-------- | :---------------------- | :---------------------------------------------------------------------- |
-| `id` | `string` | Unique assignment identifier| Auto-generated |
-| `assignment_number`| `string`| Assignment Number (ASN-####)| Pattern: `^ASN-[0-9]{4,6}$` |
-| `order_id` | `string` | Associated order ID | Required |
-| `order_number`| `string`| Order number | Optional |
-| `workforce_id`| `string`| Assigned worker ID | Required |
-| `workforce_name`| `string`| Assigned worker name | Optional |
-| `vendor_id`| `string` | Vendor providing the worker| Required |
-| `vendor_name`| `string`| Vendor name | Optional |
-| `partner_id`| `string` | Client/partner ID | Optional |
-| `role` | `string` | Role assigned | Required |
-| `department`| `string` | Department | Optional |
-| `assignment_status`| `string`| Assignment status | Enum: "Pending", "Confirmed", "Checked In", "In Progress", "Completed", "Cancelled", "No Show" |
-| `scheduled_start`| `timestamp`| Scheduled start time | Required |
-| `scheduled_end`| `timestamp`| Scheduled end time | Optional |
-| `actual_start`| `timestamp`| Actual start time | Optional |
-| `actual_end`| `timestamp`| Actual end time | Optional |
-| `timesheet`| `object` | Timesheet data | Optional |
-| `ratings` | `object` | Performance ratings | Optional |
-| `pay_rate` | `number` | Worker pay rate | Optional |
-| `bill_rate`| `number` | Client bill rate | Optional |
-| `total_pay`| `number` | Total worker pay | Optional |
-| `total_bill`| `number` | Total client bill | Optional |
-| `notes` | `string` | Assignment notes | Optional |
-| `created_date`| `timestamp`| Creation date | Auto-generated |
-| `updated_date`| `timestamp`| Last update | Auto-updated |
-| `created_by`| `string` | Creator email | Auto-populated |
-
-Timesheet Structure:
-```json
-{
- "clock_in": "timestamp",
- "clock_out": "timestamp",
- "break_minutes": "number",
- "total_hours": "number",
- "regular_hours": "number",
- "overtime_hours": "number",
- "approved_by": "string",
- "approved_date": "timestamp"
-}
-```
-
-Ratings Structure:
-```json
-{
- "punctuality": "number (1-5)",
- "quality_of_work": "number (1-5)",
- "professionalism": "number (1-5)",
- "would_hire_again": "boolean",
- "comments": "string",
- "rated_by": "string",
- "rated_date": "timestamp"
-}
-```
-
-### 23. Workforce Entity
-Description: Worker/contractor management.
-
-| Field Name | Type | Description | Validation |
-| :--------- | :-------- | :---------------------- | :---------------------------------------------------------------------- |
-| `id` | `string` | Unique workforce identifier| Auto-generated |
-| `workforce_number`| `string`| Worker Number (WF-####) | Required, Pattern: `^WF-[0-9]{4,6}$` |
-| `vendor_id`| `string` | Vendor who manages this worker| Required |
-| `vendor_name`| `string`| Vendor name | Optional |
-| `first_name`| `string` | Worker first name | Required |
-| `last_name`| `string` | Worker last name | Required |
-| `email` | `string` | Worker email | Email format |
-| `phone` | `string` | Worker phone | Optional |
-| `address` | `string` | Worker address | Optional |
-| `city` | `string` | City | Optional |
-| `state` | `string` | State | Optional |
-| `zip_code` | `string` | ZIP code | Optional |
-| `date_of_birth`| `date` | Date of birth | Optional |
-| `ssn_last_four`| `string`| Last 4 digits of SSN | Pattern: `^[0-9]{4}$` |
-| `employment_type`| `string`| Employment classification| Enum: "W2", "1099", "Temporary", "Contract" |
-| `skills` | `array` | Worker skills | Array of strings |
-| `roles_qualified`| `array`| Roles worker is qualified for| Array of strings |
-| `certifications`| `array`| Certifications | Array of cert objects |
-| `background_check_status`| `string`| Background check status | Enum: "Pending", "Cleared", "Failed", "Expired" |
-| `background_check_date`| `date`| Background check date | Optional |
-| `drug_test_status`| `string`| Drug test status | Enum: "Pending", "Passed", "Failed", "Expired" |
-| `drug_test_date`| `date`| Drug test date | Optional |
-| `reliability_index`| `number`| Reliability score | Min: 0, Max: 100 |
-| `total_assignments`| `number`| Total assignments completed| Default: 0 |
-| `cancelled_assignments`| `number`| Cancelled assignments | Default: 0 |
-| `no_shows` | `number` | No-show count | Default: 0 |
-| `average_rating`| `number`| Average performance rating| Min: 0, Max: 5 |
-| `languages`| `array` | Languages spoken | Array of strings |
-| `availability`| `object`| Worker availability | Optional |
-| `is_active`| `boolean`| Is worker active | Default: true |
-| `hire_date`| `date` | Date worker was hired | Optional |
-| `termination_date`| `date`| Termination date if applicable| Optional |
-| `notes` | `string` | Internal notes | Optional |
-| `created_date`| `timestamp`| Creation date | Auto-generated |
-| `updated_date`| `timestamp`| Last update | Auto-updated |
-| `created_by`| `string` | Creator email | Auto-populated |
-
-Availability Structure:
-```json
-{
- "monday": "boolean",
- "tuesday": "boolean",
- "wednesday": "boolean",
- "thursday": "boolean",
- "friday": "boolean",
- "saturday": "boolean",
- "sunday": "boolean",
- "shift_preferences": ["Morning", "Day", "Evening", "Night", "Overnight"]
-}
-```
-
----
-
-## SDK Operations
-
-### Standard Entity Operations
-All entities support the following base operations:
-
-#### List All Records
-```javascript
-// List all records (default limit: 50)
-const records = await base44.entities.EntityName.list();
-
-// List with sorting (descending by created_date)
-const records = await base44.entities.EntityName.list('-created_date');
-
-// List with sorting and limit
-const records = await base44.entities.EntityName.list('-created_date', 20);
-```
-
-#### Filter Records
-```javascript
-// Filter by single field
-const records = await base44.entities.EntityName.filter({
- status: 'Active'
-});
-
-// Filter with multiple conditions
-const records = await base44.entities.EntityName.filter({
- status: 'Active',
- created_by: user.email
-});
-
-// Filter with sorting and limit
-const records = await base44.entities.EntityName.filter(
- { status: 'Active' },
- '-created_date',
- 10
-);
-
-// Filter with operators
-const records = await base44.entities.EntityName.filter({
- rating: { $gte: 4.5 },
- total: { $lte: 1000 }
-});
-```
-
-#### Create Record
-```javascript
-// Create single record
-const newRecord = await base44.entities.EntityName.create({
- field1: 'value1',
- field2: 'value2'
-});
-
-// Returns created record with id
-```
-
-#### Bulk Create Records
-```javascript
-// Create multiple records
-const newRecords = await base44.entities.EntityName.bulkCreate([
- { field1: 'value1' },
- { field1: 'value2' },
- { field1: 'value3' }
-]);
-
-// Returns array of created records
-```
-
-#### Update Record
-```javascript
-// Update by ID
-const updatedRecord = await base44.entities.EntityName.update(recordId, {
- field1: 'new value'
-});
-
-// Returns updated record
-```
-
-#### Delete Record
-```javascript
-// Delete by ID
-await base44.entities.EntityName.delete(recordId);
-```
-
-#### Get Entity Schema
-```javascript
-// Get JSON schema (without built-in fields)
-const schema = await base44.entities.EntityName.schema();
-
-// Useful for dynamic form generation
-```
-
-### Entity-Specific Examples
-
-#### Event Operations
-```javascript
-// List recent events
-const events = await base44.entities.Event.list('-date', 50);
-
-// Filter vendor's events
-const myEvents = await base44.entities.Event.filter({
- vendor_id: user.id,
- status: 'Active'
-}, '-date', 20);
-
-// Create new event
-const newEvent = await base44.entities.Event.create({
- event_name: 'Corporate Luncheon',
- business_name: 'Acme Corp',
- date: '2025-12-01',
- status: 'Draft',
- requested: 15,
- is_rapid: false,
- conflict_detection_enabled: true
-});
-
-// Update event status
-await base44.entities.Event.update(eventId, {
- status: 'Confirmed'
-});
-```
-
-#### Staff Operations
-```javascript
-// List all active staff
-const staff = await base44.entities.Staff.list('-created_date');
-
-// Filter by vendor
-const vendorStaff = await base44.entities.Staff.filter({
- vendor_id: vendorId
-});
-
-// Filter by rating
-const topStaff = await base44.entities.Staff.filter({
- rating: { $gte: 4.5 }
-}, '-rating', 10);
-
-// Create staff member
-const newStaff = await base44.entities.Staff.create({
- employee_name: 'John Doe',
- vendor_name: 'ABC Staffing',
- position: 'Server',
- employment_type: 'Part Time'
-});
-
-// Update staff rating
-await base44.entities.Staff.update(staffId, {
- rating: 4.8,
- reliability_score: 95
-});
-```
-
-#### Invoice Operations
-```javascript
-// List unpaid invoices
-const unpaid = await base44.entities.Invoice.filter({
- status: 'Open'
-}, '-due_date');
-
-// Get client's invoices
-const clientInvoices = await base44.entities.Invoice.filter({
- business_name: clientName
-});
-
-// Create invoice
-const invoice = await base44.entities.Invoice.create({
- invoice_number: 'INV-2025-001',
- business_name: 'Client Corp',
- amount: 5000,
- status: 'Draft',
- issue_date: '2025-01-01',
- due_date: '2025-01-31'
-});
-
-// Mark as paid
-await base44.entities.Invoice.update(invoiceId, {
- status: 'Paid',
- paid_date: new Date().toISOString()
-});
-```
-
-#### Team Operations
-```javascript
-// Get user's team
-const myTeam = await base44.entities.Team.filter({
- owner_id: user.id
-});
-
-// Create team
-const team = await base44.entities.Team.create({
- team_name: 'Operations Team',
- owner_id: user.id,
- owner_name: user.full_name,
- owner_role: user.user_role,
- departments: ['Operations', 'HR', 'Finance']
-});
-
-// Add favorite staff
-await base44.entities.Team.update(teamId, {
- favorite_staff: [
- ...existingFavorites,
- {
- staff_id: staffId,
- staff_name: 'John Doe',
- position: 'Server',
- added_date: new Date().toISOString()
- }
- ],
- favorite_staff_count: existingFavorites.length + 1
-});
-```
-
-#### TeamMember Operations
-```javascript
-// List team members
-const members = await base44.entities.TeamMember.filter({
- team_id: teamId,
- is_active: true
-});
-
-// Create team member
-const member = await base44.entities.TeamMember.create({
- team_id: teamId,
- member_name: 'Jane Smith',
- email: 'jane@example.com',
- role: 'member',
- department: 'Operations',
- hub: 'BVG 300'
-});
-
-// Deactivate member
-await base44.entities.TeamMember.update(memberId, {
- is_active: false
-});
-```
-
-#### Conversation & Message Operations
-```javascript
-// List active conversations
-const conversations = await base44.entities.Conversation.filter({
- status: 'active',
- participants: { $contains: userId }
-}, '-last_message_at');
-
-// Create conversation
-const conversation = await base44.entities.Conversation.create({
- participants: [
- { id: user1Id, name: user1Name, role: 'client' },
- { id: user2Id, name: user2Name, role: 'vendor' }
- ],
- conversation_type: 'client-vendor',
- subject: 'Event #123 Discussion',
- status: 'active'
-});
-
-// Send message
-const message = await base44.entities.Message.create({
- conversation_id: conversationId,
- sender_id: userId,
- sender_name: userName,
- sender_role: 'client',
- content: 'Hello, can we discuss the event details?'
-});
-
-// Mark as read
-await base44.entities.Message.update(messageId, {
- read_by: [...existingReadBy, userId]
-});
-```
-
----
-
-## Core Integrations
-
-### Integration: InvokeLLM
-Description: Generate responses from an LLM with optional web context or file attachments.
-
-| Parameter | Type | Required | Description |
-| :------------------------ | :-------- | :------- | :----------------------------------------------------- |
-| `prompt` | `string` | Yes | The prompt to send to the LLM |
-| `add_context_from_internet`| `boolean` | No | Fetch context from Google Search, Maps, News (default: false) |
-| `response_json_schema` | `object` | No | JSON schema for structured output (root must be "object") |
-| `file_urls` | `string[]`| No | Array of file URLs for additional context |
-
-Returns:
-- If `response_json_schema` specified: `object` (parsed JSON)
-- Otherwise: `string`
-
-Examples:
-```javascript
-// Simple text response
-const response = await base44.integrations.Core.InvokeLLM({
- prompt: "Summarize the top 3 benefits of workforce automation"
-});
-
-// Structured JSON response
-const data = await base44.integrations.Core.InvokeLLM({
- prompt: "Extract key information about Apple (the company)",
- add_context_from_internet: true,
- response_json_schema: {
- type: "object",
- properties: {
- stock_price: { type: "number" },
- ceo: { type: "string" },
- headquarters: { type: "string" },
- recent_news: {
- type: "array",
- items: { type: "string" }
- }
- }
- }
-});
-
-// With file context
-const analysis = await base44.integrations.Core.InvokeLLM({
- prompt: "Analyze this invoice and extract line items",
- file_urls: [invoiceFileUrl],
- response_json_schema: {
- type: "object",
- properties: {
- line_items: {
- type: "array",
- items: {
- type: "object",
- properties: {
- description: { type: "string" },
- quantity: { type: "number" },
- rate: { type: "number" },
- amount: { type: "number" }
- }
- }
- },
- total: { type: "number" }
- }
- }
-});
-```
-
-### Integration: SendEmail
-Description: Send an email to a user.
-
-| Parameter | Type | Required | Description |
-| :-------- | :-------- | :------- | :----------------------------------------------------- |
-| `to` | `string` | Yes | Recipient email address |
-| `subject` | `string` | Yes | Email subject line |
-| `body` | `string` | Yes | Email body (supports HTML) |
-| `from_name`| `string` | No | Sender name (defaults to app name) |
-
-Returns: `void`
-
-Example:
-```javascript
-await base44.integrations.Core.SendEmail({
- to: 'client@example.com',
- subject: 'Your Event Has Been Confirmed',
- body: `
-
Event Confirmation
-
Hello ${clientName},
-
Your event "${eventName}" has been confirmed for ${eventDate}.
-
Staff assigned: ${staffCount}
-
Thank you for using KROW Workforce!
- `,
- from_name: 'KROW Workforce Team'
-});
-```
-
-### Integration: UploadFile
-Description: Upload a file to public storage.
-
-| Parameter | Type | Required | Description |
-| :-------- | :----- | :------- | :---------------------- |
-| `file` | `File` | Yes | File object to upload |
-
-Returns:
-```json
-{
- "file_url": "string"
-}
-```
-
-Example:
-```javascript
-// From file input
-const fileInput = document.querySelector('input[type="file"]');
-const file = fileInput.files[0];
-
-const { file_url } = await base44.integrations.Core.UploadFile({
- file: file
-});
-
-// Use the URL
-await base44.entities.Staff.update(staffId, {
- profile_picture: file_url
-});
-```
-
-### Integration: UploadPrivateFile
-Description: Upload a file to private storage (requires signed URL for access).
-
-| Parameter | Type | Required | Description |
-| :-------- | :----- | :------- | :---------------------- |
-| `file` | `File` | Yes | File object to upload |
-
-Returns:
-```json
-{
- "file_uri": "string"
-}
-```
-
-Example:
-```javascript
-// Upload private document
-const { file_uri } = await base44.integrations.Core.UploadPrivateFile({
- file: sensitiveDocument
-});
-
-// Store the URI
-await base44.entities.Vendor.update(vendorId, {
- w9_document: file_uri
-});
-
-// Later, create signed URL for access
-const { signed_url } = await base44.integrations.Core.CreateFileSignedUrl({
- file_uri: file_uri,
- expires_in: 3600 // 1 hour
-});
-```
-
-### Integration: CreateFileSignedUrl
-Description: Create a temporary signed URL for accessing a private file.
-
-| Parameter | Type | Required | Description |
-| :--------- | :-------- | :------- | :----------------------------------------------------- |
-| `file_uri` | `string` | Yes | Private file URI |
-| `expires_in`| `number` | No | Expiration time in seconds (default: 300) |
-
-Returns:
-```json
-{
- "signed_url": "string"
-}
-```
-
-Example:
-```javascript
-// Create 1-hour signed URL
-const { signed_url } = await base44.integrations.Core.CreateFileSignedUrl({
- file_uri: vendor.w9_document,
- expires_in: 3600
-});
-
-// Use signed URL
-window.open(signed_url, '_blank');
-```
-
-### Integration: ExtractDataFromUploadedFile
-Description: Extract structured data from uploaded files (CSV, PDF, images).
-
-| Parameter | Type | Required | Description |
-| :---------- | :-------- | :------- | :----------------------------------------------------- |
-| `file_url` | `string` | Yes | URL to uploaded file |
-| `json_schema`| `object` | Yes | JSON schema defining expected data structure |
-
-Returns:
-```json
-{
- "status": "success" | "error",
- "details": "string | null",
- "output": "object[] | object | null"
-}
-```
-
-Example:
-```javascript
-// Upload CSV of staff members
-const { file_url } = await base44.integrations.Core.UploadFile({
- file: csvFile
-});
-
-// Extract data
-const result = await base44.integrations.Core.ExtractDataFromUploadedFile({
- file_url: file_url,
- json_schema: {
- type: "array",
- items: {
- type: "object",
- properties: {
- employee_name: { type: "string" },
- email: { type: "string" },
- position: { type: "string" },
- department: { type: "string" },
- phone: { type: "string" }
- }
- }
- }
-});
-
-if (result.status === "success") {
- // Bulk create staff from extracted data
- await base44.entities.Staff.bulkCreate(result.output);
-}
-```
-
-### Integration: GenerateImage
-Description: Generate an AI image from a text prompt.
-
-| Parameter | Type | Required | Description |
-| :-------- | :-------- | :------- | :----------------------------------------------------- |
-| `prompt` | `string` | Yes | Detailed image description |
-
-Returns:
-```json
-{
- "url": "string"
-}
-```
-
-Example:
-```javascript
-// Generate event banner
-const { url } = await base44.integrations.Core.GenerateImage({
- prompt: "Professional corporate event banner with elegant food service theme, blue and white color scheme, modern minimalist design"
-});
-
-// Use the generated image
-await base44.entities.Event.update(eventId, {
- banner_image: url
-});
-```
-
----
-
-## Data Models Reference
-
-### Complete Event Object Example
-```json
-{
- "id": "evt_1234567890",
- "event_name": "Google Campus Lunch Service",
- "is_recurring": true,
- "is_multi_day": false,
- "is_rapid": false,
- "recurrence_type": "date_range",
- "recurrence_start_date": "2025-01-01",
- "recurrence_end_date": "2025-12-31",
- "buffer_time_before": 15,
- "buffer_time_after": 15,
- "conflict_detection_enabled": true,
- "detected_conflicts": [],
- "business_id": "bus_0987654321",
- "business_name": "Google",
- "vendor_id": "vnd_1122334455",
- "vendor_name": "Elite Staffing Solutions",
- "hub": "Mountain View Campus",
- "contract_type": "W2",
- "po_reference": "PO-2025-001",
- "status": "Active",
- "date": "2025-01-15",
- "shifts": [
- {
- "shift_name": "Lunch Shift",
- "shift_contact": "John Manager",
- "location_address": "1600 Amphitheatre Parkway",
- "roles": [
- {
- "role": "Server",
- "department": "Food Service",
- "count": 10,
- "start_time": "11:00",
- "end_time": "15:00",
- "hours": 4,
- "uniform": "White shirt, black pants",
- "break_minutes": 30,
- "cost_per_hour": 25,
- "total_value": 1000,
- "vendor_name": "Elite Staffing Solutions",
- "vendor_id": "vnd_1122334455"
- }
- ]
- }
- ],
- "addons": {
- "goal": {
- "enabled": true,
- "text": "Maintain 95% customer satisfaction"
- },
- "portal_access": true,
- "meal_provided": true,
- "travel_time": false,
- "tips": {
- "enabled": true,
- "amount": "pooled"
- }
- },
- "total": 1900,
- "requested": 15,
- "assigned_staff": [
- {
- "staff_id": "stf_111",
- "staff_name": "Maria Garcia",
- "role": "Server",
- "confirmed": true
- }
- ],
- "client_name": "Sarah Johnson",
- "client_email": "sarah.johnson@google.com",
- "client_phone": "(650) 555-0123",
- "notes": "Ensure all staff arrive 15 minutes early",
- "created_date": "2025-01-01T10:00:00Z",
- "updated_date": "2025-01-10T14:30:00Z",
- "created_by": "admin@krow.com"
-}
-```
-
-### Complete Staff Object Example
-```json
-{
- "id": "stf_9876543210",
- "employee_name": "Maria Garcia",
- "vendor_id": "vnd_1122334455",
- "vendor_name": "Elite Staffing Solutions",
- "manager": "Fernando Lopez",
- "contact_number": "(415) 555-0199",
- "phone": "(415) 555-0200",
- "email": "maria.garcia@email.com",
- "department": "Operations",
- "hub_location": "San Francisco Bay Area",
- "event_location": "Various",
- "address": "123 Main St, Apt 4B",
- "city": "San Francisco",
- "position": "Server",
- "position_2": "Bartender",
- "initial": "MG",
- "profile_type": "Skilled",
- "employment_type": "Part Time",
- "english": "Fluent",
- "english_required": true,
- "check_in": "2025-01-15",
- "rating": 4.8,
- "shift_coverage_percentage": 95,
- "cancellation_count": 2,
- "no_show_count": 0,
- "total_shifts": 47,
- "reliability_score": 96,
- "background_check_status": "cleared",
- "background_check_date": "2024-06-15",
- "certifications": [
- {
- "name": "Food Handler Certificate",
- "issued_date": "2024-06-01",
- "expiry_date": "2026-06-01",
- "issuer": "ServSafe"
- }
- ],
- "notes": "Excellent customer service skills",
- "created_date": "2024-01-10T09:00:00Z",
- "updated_date": "2025-01-15T16:45:00Z",
- "created_by": "vendor@elitestaffing.com"
-}
-```
-
-### Complete Team Object Example
-```json
-{
- "id": "team_123456",
- "team_name": "Operations Team",
- "owner_id": "user_789",
- "owner_name": "John Manager",
- "owner_role": "vendor",
- "email": "john@example.com",
- "phone": "(555) 123-4567",
- "departments": ["Operations", "HR", "Finance"],
- "total_members": 15,
- "active_members": 12,
- "total_hubs": 3,
- "favorite_staff": [
- {
- "staff_id": "stf_111",
- "staff_name": "Maria Garcia",
- "position": "Server",
- "added_date": "2025-01-15T10:00:00Z"
- }
- ],
- "blocked_staff": [
- {
- "staff_id": "stf_222",
- "staff_name": "John Smith",
- "reason": "Performance issues",
- "blocked_date": "2025-01-10T14:30:00Z"
- }
- ],
- "favorite_staff_count": 1,
- "blocked_staff_count": 1,
- "created_date": "2025-01-01T08:00:00Z",
- "updated_date": "2025-01-15T16:00:00Z"
-}
-```
-
----
-
-## Code Examples
-
-### Example 1: Create Event with Staff Assignment
-```javascript
-import { base44 } from "@/api/base44Client";
-
-async function createEventAndAssignStaff() {
- const user = await base44.auth.me();
-
- const event = await base44.entities.Event.create({
- event_name: "Corporate Holiday Party",
- business_name: "Acme Corporation",
- date: "2025-12-20",
- hub: "Downtown Office",
- status: "Draft",
- requested: 20,
- is_rapid: false,
- conflict_detection_enabled: true,
- shifts: [
- {
- shift_name: "Evening Service",
- location_address: "123 Corporate Plaza",
- roles: [
- {
- role: "Server",
- department: "Food Service",
- count: 15,
- start_time: "18:00",
- end_time: "23:00",
- hours: 5,
- cost_per_hour: 28,
- total_value: 2100
- }
- ]
- }
- ],
- total: 3060,
- client_name: user.full_name,
- client_email: user.email
- });
-
- const availableStaff = await base44.entities.Staff.filter({
- position: "Server",
- rating: { $gte: 4.5 },
- employment_type: { $in: ["Part Time", "Full Time"] }
- }, '-rating', 15);
-
- const assignedStaff = availableStaff.map(staff => ({
- staff_id: staff.id,
- staff_name: staff.employee_name,
- role: "Server",
- confirmed: false
- }));
-
- await base44.entities.Event.update(event.id, {
- assigned_staff: assignedStaff,
- status: "Pending"
- });
-
- await base44.entities.ActivityLog.create({
- title: "Event Created",
- description: `New event "${event.event_name}" created and staff assigned`,
- activity_type: "event_created",
- related_entity_type: "event",
- related_entity_id: event.id,
- user_id: user.id,
- is_read: false,
- icon_type: "calendar",
- icon_color: "blue"
- });
-
- return event;
-}
-```
-
-### Example 2: Send Invoice Reminder Emails
-```javascript
-import { base44 } from "@/api/base44Client";
-
-async function sendInvoiceReminders() {
- const today = new Date();
- const overdueInvoices = await base44.entities.Invoice.filter({
- status: { $in: ["Open", "Overdue"] },
- due_date: { $lt: today.toISOString().split('T')[0] }
- });
-
- for (const invoice of overdueInvoices) {
- await base44.entities.Invoice.update(invoice.id, {
- status: "Overdue"
- });
-
- const business = await base44.entities.Business.filter({
- business_name: invoice.business_name
- });
-
- if (business.length > 0) {
- const contact = business[0];
-
- await base44.integrations.Core.SendEmail({
- to: contact.email,
- subject: `Payment Reminder: Invoice ${invoice.invoice_number}`,
- body: `
-
Payment Reminder
-
Dear ${contact.contact_name},
-
Invoice ${invoice.invoice_number}
- for $${invoice.amount.toLocaleString()} is now overdue.
-
Due Date: ${invoice.due_date}
-
Please process payment at your earliest convenience.
-
Thank you,
KROW Workforce Team
- `,
- from_name: "KROW Accounts Receivable"
- });
-
- await base44.entities.ActivityLog.create({
- title: "Invoice Reminder Sent",
- description: `Reminder sent for invoice ${invoice.invoice_number}`,
- activity_type: "invoice_created",
- related_entity_type: "invoice",
- related_entity_id: invoice.id,
- user_id: contact.id || "system",
- icon_type: "invoice",
- icon_color: "yellow"
- });
- }
- }
-
- return overdueInvoices.length;
-}
-```
-
-### Example 3: AI-Powered Staff Recommendation
-```javascript
-import { base44 } from "@/api/base44Client";
-
-async function getStaffRecommendations(eventId) {
- const events = await base44.entities.Event.filter({ id: eventId });
- const event = events[0];
-
- const allStaff = await base44.entities.Staff.list();
-
- const recommendations = await base44.integrations.Core.InvokeLLM({
- prompt: `
- Analyze this event and recommend the best staff members.
-
- Event Details:
- - Name: ${event.event_name}
- - Date: ${event.date}
- - Location: ${event.hub}
- - Roles Needed: ${JSON.stringify(event.shifts)}
-
- Available Staff:
- ${JSON.stringify(allStaff.map(s => ({
- id: s.id,
- name: s.employee_name,
- position: s.position,
- rating: s.rating,
- reliability: s.reliability_score,
- experience: s.total_shifts
- })))}
-
- Recommend the top staff for each role based on:
- 1. Position match
- 2. Rating and reliability
- 3. Experience level
-
- Provide reasoning for each recommendation.
- `,
- response_json_schema: {
- type: "object",
- properties: {
- recommendations: {
- type: "array",
- items: {
- type: "object",
- properties: {
- staff_id: { type: "string" },
- staff_name: { type: "string" },
- role: { type: "string" },
- score: { type: "number" },
- reasoning: { type: "string" }
- }
- }
- },
- overall_analysis: { type: "string" }
- }
- }
- });
-
- return recommendations;
-}
-```
-
-### Example 4: Bulk Import Staff from CSV
-```javascript
-import { base44 } from "@/api/base44Client";
-
-async function importStaffFromCSV(file) {
- const { file_url } = await base44.integrations.Core.UploadFile({
- file: file
- });
-
- const result = await base44.integrations.Core.ExtractDataFromUploadedFile({
- file_url: file_url,
- json_schema: {
- type: "array",
- items: {
- type: "object",
- properties: {
- employee_name: { type: "string" },
- email: { type: "string" },
- phone: { type: "string" },
- position: { type: "string" },
- department: { type: "string" },
- employment_type: { type: "string" },
- vendor_name: { type: "string" }
- },
- required: ["employee_name"]
- }
- }
- });
-
- if (result.status === "error") {
- throw new Error(result.details);
- }
-
- const createdStaff = await base44.entities.Staff.bulkCreate(
- result.output.map(staff => ({
- ...staff,
- rating: 0,
- reliability_score: 0,
- total_shifts: 0,
- background_check_status: "pending"
- }))
- );
-
- await base44.entities.ActivityLog.create({
- title: "Bulk Staff Import",
- description: `${createdStaff.length} staff members imported from CSV`,
- activity_type: "staff_assigned",
- user_id: (await base44.auth.me()).id,
- icon_type: "user",
- icon_color: "green"
- });
-
- return createdStaff;
-}
-```
-
-### Example 5: Team Management with Invitations
-```javascript
-import { base44 } from "@/api/base44Client";
-
-async function createTeamAndInviteMembers() {
- const user = await base44.auth.me();
-
- // Create team
- const team = await base44.entities.Team.create({
- team_name: "Operations Team",
- owner_id: user.id,
- owner_name: user.full_name,
- owner_role: user.user_role,
- email: user.email,
- departments: ["Operations", "HR", "Finance"]
- });
-
- // Create hub
- const hub = await base44.entities.TeamHub.create({
- team_id: team.id,
- hub_name: "BVG 300",
- address: "300 Bayview Dr, Mountain View, CA",
- manager_name: "John Manager",
- manager_email: "john@example.com",
- departments: [
- {
- department_name: "Catering FOH",
- cost_center: "CC-001"
- }
- ]
- });
-
- // Create invitation
- const inviteCode = `TEAM-${Math.floor(10000 + Math.random() * 90000)}`;
- const invite = await base44.entities.TeamMemberInvite.create({
- team_id: team.id,
- team_name: team.team_name,
- invite_code: inviteCode,
- email: "newmember@example.com",
- full_name: "New Member",
- role: "member",
- hub: hub.hub_name,
- department: "Catering FOH",
- invited_by: user.email,
- invite_status: "pending",
- invited_date: new Date().toISOString(),
- expires_at: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString()
- });
-
- // Send invitation email
- await base44.integrations.Core.SendEmail({
- to: "newmember@example.com",
- subject: `You're invited to join ${team.team_name}`,
- body: `
-
Join ${team.team_name}
-
You've been invited to join ${hub.hub_name}.
-
Register here: ${window.location.origin}/Onboarding?invite=${inviteCode}
- `,
- from_name: team.team_name
- });
-
- return { team, hub, invite };
-}
-```
-
----
-
-## Best Practices
-
-### 1. Error Handling
-```javascript
-try {
- const event = await base44.entities.Event.create(eventData);
-} catch (error) {
- console.error("Failed to create event:", error);
- toast({
- title: "⌠Error",
- description: "Failed to create event. Please try again.",
- variant: "destructive"
- });
-}
-```
-
-### 2. Query Optimization
-```javascript
-// ⌠Bad: Fetch all then filter in memory
-const allEvents = await base44.entities.Event.list();
-const vendorEvents = allEvents.filter(e => e.vendor_id === vendorId);
-
-// ✅ Good: Filter at database level
-const vendorEvents = await base44.entities.Event.filter({
- vendor_id: vendorId
-});
-```
-
-### 3. Pagination
-```javascript
-// Fetch in batches
-const pageSize = 50;
-let page = 0;
-let allRecords = [];
-
-while (true) {
- const batch = await base44.entities.Event.list(
- '-created_date',
- pageSize,
- page * pageSize
- );
-
- if (batch.length === 0) break;
-
- allRecords = [...allRecords, ...batch];
- page++;
-}
-```
-
-### 4. Caching with React Query
-```javascript
-import { useQuery } from "@tanstack/react-query";
-
-function useEvents() {
- return useQuery({
- queryKey: ['events'],
- queryFn: () => base44.entities.Event.list('-date'),
- initialData: [],
- staleTime: 5 * 60 * 1000,
- cacheTime: 10 * 60 * 1000
- });
-}
-```
-
-### 5. Batch Operations
-```javascript
-// ⌠Bad: Multiple sequential creates
-for (const staff of staffList) {
- await base44.entities.Staff.create(staff);
-}
-
-// ✅ Good: Single bulk create
-await base44.entities.Staff.bulkCreate(staffList);
-```
-
-### 6. Team Isolation
-```javascript
-// Teams are automatically isolated by owner_id
-const myTeam = await base44.entities.Team.filter({
- owner_id: user.id
-});
-
-// Each role can only see their own team
-// Vendors cannot see Procurement teams
-// Procurement cannot see Vendor teams
-```
-
----
-
-## Security Considerations
-
-### 1. User Entity Access Control
-- Only admin users can access other users' data
-- Regular users can only view/update their own records
-- Built-in security rules are automatically enforced
-
-### 2. Team Isolation
-- Teams are isolated by `owner_id`
-- Each user role (vendor, procurement, operator, sector, client, workforce) can only see and manage their own team
-- Vendors CANNOT see Procurement teams
-- Procurement CANNOT see Vendor teams
-- NO cross-layer visibility is allowed
-
-### 3. Private Files
-- Use `UploadPrivateFile` for sensitive documents
-- Always use signed URLs with appropriate expiration
-- Never expose private file URIs directly
-
-### 4. Email Validation
-- Always validate email formats before sending
-- Use proper HTML escaping in email bodies
-- Consider rate limiting for bulk emails
-
-### 5. Data Validation
-- Validate all input data before entity operations
-- Use enum constraints where applicable
-- Implement client-side validation before API calls
-
----
-
-## Rate Limits & Quotas
-
-### Standard Limits
-- Entity Operations: 1000 requests/minute
-- LLM Invocations: 100 requests/minute
-- File Uploads: 100 MB per file
-- Email Sending: 1000 emails/day
-
-### Best Practices for Limits
-- Implement exponential backoff for retries
-- Cache frequently accessed data
-- Use bulk operations when possible
-- Monitor usage via activity logs
-
----
-
-## Changelog
-
-### Version 3.0 (2025-11-20)
-- Added Team, TeamMember, TeamHub, TeamMemberInvite entities
-- Added Assignment and Workforce entities
-- Added VendorDefaultSettings entity
-- Updated Event entity with conflict detection, multi-day support, and RAPID flag
-- Enhanced Invoice entity with comprehensive dispute tracking
-- Updated Team entity with favorite_staff and blocked_staff arrays
-- Added team isolation security documentation
-- Updated all entity schemas with current validation rules
-- Enhanced integration specifications
-- Added complete code examples for team management
-
-### Version 2.0 (2025-01-11)
-- Complete entity schema documentation
-- Added 17 entity schemas with full field specifications
-- Comprehensive SDK operation examples
-- Core integration specifications
-- Advanced code examples
-- Best practices and security guidelines
-
-### Version 1.0 (2024-12-01)
-- Initial API documentation
-- Basic entity schemas
-- Core integration endpoints
-
----
-
-## Support & Resources
-
-- **Documentation**
- - Platform Docs: `https://docs.base44.com`
- - API Reference: `https://api.base44.com/docs`
- - Community Forum: `https://community.base44.com`
-
-- **Contact**
- - Technical Support: `support@krow.com`
- - Sales Inquiries: `sales@krow.com`
- - General Questions: `info@krow.com`
-
-© 2025 KROW Workforce. All rights reserved.
-*/
\ No newline at end of file
diff --git a/frontend-web/src/pages/index.jsx b/frontend-web/src/pages/index.jsx
deleted file mode 100644
index 6943c60e..00000000
--- a/frontend-web/src/pages/index.jsx
+++ /dev/null
@@ -1,489 +0,0 @@
-import Layout from "./Layout.jsx";
-
-import Dashboard from "./Dashboard";
-
-import StaffDirectory from "./StaffDirectory";
-
-import AddStaff from "./AddStaff";
-
-import EditStaff from "./EditStaff";
-
-import Events from "./Events";
-
-import CreateEvent from "./CreateEvent";
-
-import EditEvent from "./EditEvent";
-
-import EventDetail from "./EventDetail";
-
-import Business from "./Business";
-
-import Invoices from "./Invoices";
-
-import Payroll from "./Payroll";
-
-import Certification from "./Certification";
-
-import Support from "./Support";
-
-import Reports from "./Reports";
-
-import Settings from "./Settings";
-
-import ActivityLog from "./ActivityLog";
-
-import AddBusiness from "./AddBusiness";
-
-import EditBusiness from "./EditBusiness";
-
-import ProcurementDashboard from "./ProcurementDashboard";
-
-import OperatorDashboard from "./OperatorDashboard";
-
-import VendorDashboard from "./VendorDashboard";
-
-import WorkforceDashboard from "./WorkforceDashboard";
-
-import Messages from "./Messages";
-
-import ClientDashboard from "./ClientDashboard";
-
-import Onboarding from "./Onboarding";
-
-import ClientOrders from "./ClientOrders";
-
-import ClientInvoices from "./ClientInvoices";
-
-import VendorOrders from "./VendorOrders";
-
-import VendorStaff from "./VendorStaff";
-
-import VendorInvoices from "./VendorInvoices";
-
-import VendorPerformance from "./VendorPerformance";
-
-import WorkforceShifts from "./WorkforceShifts";
-
-import WorkforceEarnings from "./WorkforceEarnings";
-
-import WorkforceProfile from "./WorkforceProfile";
-
-import UserManagement from "./UserManagement";
-
-import Home from "./Home";
-
-import VendorRateCard from "./VendorRateCard";
-
-import Permissions from "./Permissions";
-
-import WorkforceCompliance from "./WorkforceCompliance";
-
-import Teams from "./Teams";
-
-import CreateTeam from "./CreateTeam";
-
-import TeamDetails from "./TeamDetails";
-
-import VendorManagement from "./VendorManagement";
-
-import PartnerManagement from "./PartnerManagement";
-
-import EnterpriseManagement from "./EnterpriseManagement";
-
-import VendorOnboarding from "./VendorOnboarding";
-
-import SectorManagement from "./SectorManagement";
-
-import AddEnterprise from "./AddEnterprise";
-
-import AddSector from "./AddSector";
-
-import AddPartner from "./AddPartner";
-
-import EditVendor from "./EditVendor";
-
-import SmartVendorOnboarding from "./SmartVendorOnboarding";
-
-import InviteVendor from "./InviteVendor";
-
-import VendorCompliance from "./VendorCompliance";
-
-import EditPartner from "./EditPartner";
-
-import EditSector from "./EditSector";
-
-import EditEnterprise from "./EditEnterprise";
-
-import VendorRates from "./VendorRates";
-
-import VendorDocumentReview from "./VendorDocumentReview";
-
-import VendorMarketplace from "./VendorMarketplace";
-
-import RapidOrder from "./RapidOrder";
-
-import SmartScheduler from "./SmartScheduler";
-
-import StaffOnboarding from "./StaffOnboarding";
-
-import NotificationSettings from "./NotificationSettings";
-
-import TaskBoard from "./TaskBoard";
-
-import InvoiceDetail from "./InvoiceDetail";
-
-import InvoiceEditor from "./InvoiceEditor";
-
-import apiDocsRaw from "./api-docs-raw";
-
-import Tutorials from "./Tutorials";
-
-import Schedule from "./Schedule";
-
-import StaffAvailability from "./StaffAvailability";
-
-import WorkerShiftProposals from "./WorkerShiftProposals";
-
-import SavingsEngine from "./SavingsEngine";
-
-import EmployeeDocuments from "./EmployeeDocuments";
-
-import { BrowserRouter as Router, Route, Routes, useLocation } from 'react-router-dom';
-
-const PAGES = {
-
- Dashboard: Dashboard,
-
- StaffDirectory: StaffDirectory,
-
- AddStaff: AddStaff,
-
- EditStaff: EditStaff,
-
- Events: Events,
-
- CreateEvent: CreateEvent,
-
- EditEvent: EditEvent,
-
- EventDetail: EventDetail,
-
- Business: Business,
-
- Invoices: Invoices,
-
- Payroll: Payroll,
-
- Certification: Certification,
-
- Support: Support,
-
- Reports: Reports,
-
- Settings: Settings,
-
- ActivityLog: ActivityLog,
-
- AddBusiness: AddBusiness,
-
- EditBusiness: EditBusiness,
-
- ProcurementDashboard: ProcurementDashboard,
-
- OperatorDashboard: OperatorDashboard,
-
- VendorDashboard: VendorDashboard,
-
- WorkforceDashboard: WorkforceDashboard,
-
- Messages: Messages,
-
- ClientDashboard: ClientDashboard,
-
- Onboarding: Onboarding,
-
- ClientOrders: ClientOrders,
-
- ClientInvoices: ClientInvoices,
-
- VendorOrders: VendorOrders,
-
- VendorStaff: VendorStaff,
-
- VendorInvoices: VendorInvoices,
-
- VendorPerformance: VendorPerformance,
-
- WorkforceShifts: WorkforceShifts,
-
- WorkforceEarnings: WorkforceEarnings,
-
- WorkforceProfile: WorkforceProfile,
-
- UserManagement: UserManagement,
-
- Home: Home,
-
- VendorRateCard: VendorRateCard,
-
- Permissions: Permissions,
-
- WorkforceCompliance: WorkforceCompliance,
-
- Teams: Teams,
-
- CreateTeam: CreateTeam,
-
- TeamDetails: TeamDetails,
-
- VendorManagement: VendorManagement,
-
- PartnerManagement: PartnerManagement,
-
- EnterpriseManagement: EnterpriseManagement,
-
- VendorOnboarding: VendorOnboarding,
-
- SectorManagement: SectorManagement,
-
- AddEnterprise: AddEnterprise,
-
- AddSector: AddSector,
-
- AddPartner: AddPartner,
-
- EditVendor: EditVendor,
-
- SmartVendorOnboarding: SmartVendorOnboarding,
-
- InviteVendor: InviteVendor,
-
- VendorCompliance: VendorCompliance,
-
- EditPartner: EditPartner,
-
- EditSector: EditSector,
-
- EditEnterprise: EditEnterprise,
-
- VendorRates: VendorRates,
-
- VendorDocumentReview: VendorDocumentReview,
-
- VendorMarketplace: VendorMarketplace,
-
- RapidOrder: RapidOrder,
-
- SmartScheduler: SmartScheduler,
-
- StaffOnboarding: StaffOnboarding,
-
- NotificationSettings: NotificationSettings,
-
- TaskBoard: TaskBoard,
-
- InvoiceDetail: InvoiceDetail,
-
- InvoiceEditor: InvoiceEditor,
-
- apiDocsRaw: apiDocsRaw,
-
- Tutorials: Tutorials,
-
- Schedule: Schedule,
-
- StaffAvailability: StaffAvailability,
-
- WorkerShiftProposals: WorkerShiftProposals,
-
- SavingsEngine: SavingsEngine,
-
- EmployeeDocuments: EmployeeDocuments,
-
-}
-
-function _getCurrentPage(url) {
- if (url.endsWith('/')) {
- url = url.slice(0, -1);
- }
- let urlLastPart = url.split('/').pop();
- if (urlLastPart.includes('?')) {
- urlLastPart = urlLastPart.split('?')[0];
- }
-
- const pageName = Object.keys(PAGES).find(page => page.toLowerCase() === urlLastPart.toLowerCase());
- return pageName || Object.keys(PAGES)[0];
-}
-
-// Create a wrapper component that uses useLocation inside the Router context
-function PagesContent() {
- const location = useLocation();
- const currentPage = _getCurrentPage(location.pathname);
-
- return (
-
-
-
- } />
-
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
- } />
-
-
-
- );
-}
-
-export default function Pages() {
- return (
-
-
-
- );
-}
\ No newline at end of file
diff --git a/frontend-web/src/utils/index.ts b/frontend-web/src/utils/index.ts
deleted file mode 100644
index 8fc65c3b..00000000
--- a/frontend-web/src/utils/index.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-export function createPageUrl(pageName: string) {
- return '/' + pageName.toLowerCase().replace(/ /g, '-');
-}
\ No newline at end of file
diff --git a/frontend-web/tailwind.config.js b/frontend-web/tailwind.config.js
deleted file mode 100644
index 7ee3f053..00000000
--- a/frontend-web/tailwind.config.js
+++ /dev/null
@@ -1,89 +0,0 @@
-/** @type {import('tailwindcss').Config} */
-module.exports = {
- darkMode: ["class"],
- content: ["./index.html", "./src/**/*.{ts,tsx,js,jsx}"],
- theme: {
- extend: {
- borderRadius: {
- lg: 'var(--radius)',
- md: 'calc(var(--radius) - 2px)',
- sm: 'calc(var(--radius) - 4px)'
- },
- colors: {
- background: 'hsl(var(--background))',
- foreground: 'hsl(var(--foreground))',
- card: {
- DEFAULT: 'hsl(var(--card))',
- foreground: 'hsl(var(--card-foreground))'
- },
- popover: {
- DEFAULT: 'hsl(var(--popover))',
- foreground: 'hsl(var(--popover-foreground))'
- },
- primary: {
- DEFAULT: 'hsl(var(--primary))',
- foreground: 'hsl(var(--primary-foreground))'
- },
- secondary: {
- DEFAULT: 'hsl(var(--secondary))',
- foreground: 'hsl(var(--secondary-foreground))'
- },
- muted: {
- DEFAULT: 'hsl(var(--muted))',
- foreground: 'hsl(var(--muted-foreground))'
- },
- accent: {
- DEFAULT: 'hsl(var(--accent))',
- foreground: 'hsl(var(--accent-foreground))'
- },
- destructive: {
- DEFAULT: 'hsl(var(--destructive))',
- foreground: 'hsl(var(--destructive-foreground))'
- },
- border: 'hsl(var(--border))',
- input: 'hsl(var(--input))',
- ring: 'hsl(var(--ring))',
- chart: {
- '1': 'hsl(var(--chart-1))',
- '2': 'hsl(var(--chart-2))',
- '3': 'hsl(var(--chart-3))',
- '4': 'hsl(var(--chart-4))',
- '5': 'hsl(var(--chart-5))'
- },
- sidebar: {
- DEFAULT: 'hsl(var(--sidebar-background))',
- foreground: 'hsl(var(--sidebar-foreground))',
- primary: 'hsl(var(--sidebar-primary))',
- 'primary-foreground': 'hsl(var(--sidebar-primary-foreground))',
- accent: 'hsl(var(--sidebar-accent))',
- 'accent-foreground': 'hsl(var(--sidebar-accent-foreground))',
- border: 'hsl(var(--sidebar-border))',
- ring: 'hsl(var(--sidebar-ring))'
- }
- },
- keyframes: {
- 'accordion-down': {
- from: {
- height: '0'
- },
- to: {
- height: 'var(--radix-accordion-content-height)'
- }
- },
- 'accordion-up': {
- from: {
- height: 'var(--radix-accordion-content-height)'
- },
- to: {
- height: '0'
- }
- }
- },
- animation: {
- 'accordion-down': 'accordion-down 0.2s ease-out',
- 'accordion-up': 'accordion-up 0.2s ease-out'
- }
- }
- },
- plugins: [require("tailwindcss-animate")],
-}
\ No newline at end of file
diff --git a/frontend-web/vite.config.js b/frontend-web/vite.config.js
deleted file mode 100644
index 4492aa60..00000000
--- a/frontend-web/vite.config.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import { defineConfig } from 'vite'
-import react from '@vitejs/plugin-react'
-import path from 'path'
-
-// https://vite.dev/config/
-export default defineConfig({
- plugins: [react()],
- server: {
- allowedHosts: true
- },
- resolve: {
- alias: {
- '@': path.resolve(__dirname, './src'),
- },
- extensions: ['.mjs', '.js', '.jsx', '.ts', '.tsx', '.json']
- },
- optimizeDeps: {
- esbuildOptions: {
- loader: {
- '.js': 'jsx',
- },
- },
- },
-})
\ No newline at end of file
diff --git a/internal-api-harness/.gitignore b/internal-api-harness/.gitignore
deleted file mode 100644
index a547bf36..00000000
--- a/internal-api-harness/.gitignore
+++ /dev/null
@@ -1,24 +0,0 @@
-# Logs
-logs
-*.log
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-pnpm-debug.log*
-lerna-debug.log*
-
-node_modules
-dist
-dist-ssr
-*.local
-
-# Editor directories and files
-.vscode/*
-!.vscode/extensions.json
-.idea
-.DS_Store
-*.suo
-*.ntvs*
-*.njsproj
-*.sln
-*.sw?
diff --git a/internal-api-harness/eslint.config.js b/internal-api-harness/eslint.config.js
deleted file mode 100644
index 4fa125da..00000000
--- a/internal-api-harness/eslint.config.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import js from '@eslint/js'
-import globals from 'globals'
-import reactHooks from 'eslint-plugin-react-hooks'
-import reactRefresh from 'eslint-plugin-react-refresh'
-import { defineConfig, globalIgnores } from 'eslint/config'
-
-export default defineConfig([
- globalIgnores(['dist']),
- {
- files: ['**/*.{js,jsx}'],
- extends: [
- js.configs.recommended,
- reactHooks.configs.flat.recommended,
- reactRefresh.configs.vite,
- ],
- languageOptions: {
- ecmaVersion: 2020,
- globals: globals.browser,
- parserOptions: {
- ecmaVersion: 'latest',
- ecmaFeatures: { jsx: true },
- sourceType: 'module',
- },
- },
- rules: {
- 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
- },
- },
-])
diff --git a/internal-api-harness/postcss.config.js b/internal-api-harness/postcss.config.js
deleted file mode 100644
index 2e7af2b7..00000000
--- a/internal-api-harness/postcss.config.js
+++ /dev/null
@@ -1,6 +0,0 @@
-export default {
- plugins: {
- tailwindcss: {},
- autoprefixer: {},
- },
-}
diff --git a/internal-api-harness/public/logo.svg b/internal-api-harness/public/logo.svg
deleted file mode 100644
index cbeedbc2..00000000
--- a/internal-api-harness/public/logo.svg
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
diff --git a/internal-api-harness/public/vite.svg b/internal-api-harness/public/vite.svg
deleted file mode 100644
index e7b8dfb1..00000000
--- a/internal-api-harness/public/vite.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/internal-api-harness/src/App.css b/internal-api-harness/src/App.css
deleted file mode 100644
index b9d355df..00000000
--- a/internal-api-harness/src/App.css
+++ /dev/null
@@ -1,42 +0,0 @@
-#root {
- max-width: 1280px;
- margin: 0 auto;
- padding: 2rem;
- text-align: center;
-}
-
-.logo {
- height: 6em;
- padding: 1.5em;
- will-change: filter;
- transition: filter 300ms;
-}
-.logo:hover {
- filter: drop-shadow(0 0 2em #646cffaa);
-}
-.logo.react:hover {
- filter: drop-shadow(0 0 2em #61dafbaa);
-}
-
-@keyframes logo-spin {
- from {
- transform: rotate(0deg);
- }
- to {
- transform: rotate(360deg);
- }
-}
-
-@media (prefers-reduced-motion: no-preference) {
- a:nth-of-type(2) .logo {
- animation: logo-spin infinite 20s linear;
- }
-}
-
-.card {
- padding: 2em;
-}
-
-.read-the-docs {
- color: #888;
-}
diff --git a/internal-api-harness/src/api/client.js b/internal-api-harness/src/api/client.js
deleted file mode 100644
index e63a00f7..00000000
--- a/internal-api-harness/src/api/client.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import axios from "axios";
-import { auth } from "../firebase";
-
-const apiClient = axios.create({
- baseURL: import.meta.env.VITE_API_BASE_URL, // You will need to add this to your .env file
-});
-
-apiClient.interceptors.request.use(
- async (config) => {
- const user = auth.currentUser;
- if (user) {
- const token = await user.getIdToken();
- config.headers.Authorization = `Bearer ${token}`;
- }
- return config;
- },
- (error) => {
- return Promise.reject(error);
- }
-);
-
-export default apiClient;
\ No newline at end of file
diff --git a/internal-api-harness/src/assets/react.svg b/internal-api-harness/src/assets/react.svg
deleted file mode 100644
index 6c87de9b..00000000
--- a/internal-api-harness/src/assets/react.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/internal-api-harness/src/components/ui/card.jsx b/internal-api-harness/src/components/ui/card.jsx
deleted file mode 100644
index 2985cca8..00000000
--- a/internal-api-harness/src/components/ui/card.jsx
+++ /dev/null
@@ -1,50 +0,0 @@
-import * as React from "react"
-
-import { cn } from "@/lib/utils"
-
-const Card = React.forwardRef(({ className, ...props }, ref) => (
-
-))
-Card.displayName = "Card"
-
-const CardHeader = React.forwardRef(({ className, ...props }, ref) => (
-
-))
-CardHeader.displayName = "CardHeader"
-
-const CardTitle = React.forwardRef(({ className, ...props }, ref) => (
-
-))
-CardTitle.displayName = "CardTitle"
-
-const CardDescription = React.forwardRef(({ className, ...props }, ref) => (
-
-))
-CardDescription.displayName = "CardDescription"
-
-const CardContent = React.forwardRef(({ className, ...props }, ref) => (
-
-))
-CardContent.displayName = "CardContent"
-
-const CardFooter = React.forwardRef(({ className, ...props }, ref) => (
-
-))
-CardFooter.displayName = "CardFooter"
-
-export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
diff --git a/internal-api-harness/src/components/ui/collapsible.jsx b/internal-api-harness/src/components/ui/collapsible.jsx
deleted file mode 100644
index 9fa48946..00000000
--- a/internal-api-harness/src/components/ui/collapsible.jsx
+++ /dev/null
@@ -1,11 +0,0 @@
-"use client"
-
-import * as CollapsiblePrimitive from "@radix-ui/react-collapsible"
-
-const Collapsible = CollapsiblePrimitive.Root
-
-const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger
-
-const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent
-
-export { Collapsible, CollapsibleTrigger, CollapsibleContent }
diff --git a/internal-api-harness/src/components/ui/label.jsx b/internal-api-harness/src/components/ui/label.jsx
deleted file mode 100644
index a1f40999..00000000
--- a/internal-api-harness/src/components/ui/label.jsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import * as React from "react"
-import * as LabelPrimitive from "@radix-ui/react-label"
-import { cva } from "class-variance-authority";
-
-import { cn } from "@/lib/utils"
-
-const labelVariants = cva(
- "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
-)
-
-const Label = React.forwardRef(({ className, ...props }, ref) => (
-
-))
-Label.displayName = LabelPrimitive.Root.displayName
-
-export { Label }
diff --git a/internal-api-harness/.env.example b/internal/api-harness/.env.example
similarity index 100%
rename from internal-api-harness/.env.example
rename to internal/api-harness/.env.example
diff --git a/internal/api-harness/.env.staging b/internal/api-harness/.env.staging
new file mode 100644
index 00000000..2945b259
--- /dev/null
+++ b/internal/api-harness/.env.staging
@@ -0,0 +1,8 @@
+VITE_HARNESS_FIREBASE_API_KEY="AIzaSyC43vK-6gwtLcPoDHFAUH4g2vBj6YrRN2A"
+VITE_HARNESS_FIREBASE_AUTH_DOMAIN="krow-workforce-staging.firebaseapp.com"
+VITE_HARNESS_FIREBASE_PROJECT_ID="krow-workforce-staging"
+VITE_HARNESS_FIREBASE_STORAGE_BUCKET="krow-workforce-staging.firebasestorage.app"
+VITE_HARNESS_FIREBASE_MESSAGING_SENDER_ID="1032971403708"
+VITE_HARNESS_FIREBASE_APP_ID="1:1032971403708:web:7f877b82b3f5dbee356bb9"
+VITE_HARNESS_ENVIRONMENT="staging"
+VITE_API_BASE_URL="http://localhost:8080"
diff --git a/internal-api-harness/README.md b/internal/api-harness/README.md
similarity index 100%
rename from internal-api-harness/README.md
rename to internal/api-harness/README.md
diff --git a/internal-api-harness/components.json b/internal/api-harness/components.json
similarity index 100%
rename from internal-api-harness/components.json
rename to internal/api-harness/components.json
diff --git a/admin-web/eslint.config.js b/internal/api-harness/eslint.config.js
similarity index 100%
rename from admin-web/eslint.config.js
rename to internal/api-harness/eslint.config.js
diff --git a/internal-api-harness/index.html b/internal/api-harness/index.html
similarity index 100%
rename from internal-api-harness/index.html
rename to internal/api-harness/index.html
diff --git a/internal-api-harness/jsconfig.json b/internal/api-harness/jsconfig.json
similarity index 100%
rename from internal-api-harness/jsconfig.json
rename to internal/api-harness/jsconfig.json
diff --git a/internal-api-harness/package-lock.json b/internal/api-harness/package-lock.json
similarity index 100%
rename from internal-api-harness/package-lock.json
rename to internal/api-harness/package-lock.json
diff --git a/internal-api-harness/package.json b/internal/api-harness/package.json
similarity index 100%
rename from internal-api-harness/package.json
rename to internal/api-harness/package.json
diff --git a/frontend-web-free/postcss.config.js b/internal/api-harness/postcss.config.js
similarity index 100%
rename from frontend-web-free/postcss.config.js
rename to internal/api-harness/postcss.config.js
diff --git a/admin-web/logo.svg b/internal/api-harness/public/logo.svg
similarity index 100%
rename from admin-web/logo.svg
rename to internal/api-harness/public/logo.svg
diff --git a/admin-web/public/vite.svg b/internal/api-harness/public/vite.svg
similarity index 100%
rename from admin-web/public/vite.svg
rename to internal/api-harness/public/vite.svg
diff --git a/admin-web/src/App.css b/internal/api-harness/src/App.css
similarity index 100%
rename from admin-web/src/App.css
rename to internal/api-harness/src/App.css
diff --git a/internal-api-harness/src/App.jsx b/internal/api-harness/src/App.jsx
similarity index 100%
rename from internal-api-harness/src/App.jsx
rename to internal/api-harness/src/App.jsx
diff --git a/frontend-web-free/src/api/client.js b/internal/api-harness/src/api/client.js
similarity index 100%
rename from frontend-web-free/src/api/client.js
rename to internal/api-harness/src/api/client.js
diff --git a/internal-api-harness/src/api/krowSDK.js b/internal/api-harness/src/api/krowSDK.js
similarity index 100%
rename from internal-api-harness/src/api/krowSDK.js
rename to internal/api-harness/src/api/krowSDK.js
diff --git a/admin-web/src/assets/react.svg b/internal/api-harness/src/assets/react.svg
similarity index 100%
rename from admin-web/src/assets/react.svg
rename to internal/api-harness/src/assets/react.svg
diff --git a/internal-api-harness/src/components/ApiResponse.jsx b/internal/api-harness/src/components/ApiResponse.jsx
similarity index 100%
rename from internal-api-harness/src/components/ApiResponse.jsx
rename to internal/api-harness/src/components/ApiResponse.jsx
diff --git a/internal-api-harness/src/components/Layout.jsx b/internal/api-harness/src/components/Layout.jsx
similarity index 100%
rename from internal-api-harness/src/components/Layout.jsx
rename to internal/api-harness/src/components/Layout.jsx
diff --git a/internal-api-harness/src/components/ServiceTester.jsx b/internal/api-harness/src/components/ServiceTester.jsx
similarity index 100%
rename from internal-api-harness/src/components/ServiceTester.jsx
rename to internal/api-harness/src/components/ServiceTester.jsx
diff --git a/internal-api-harness/src/components/ui/button.jsx b/internal/api-harness/src/components/ui/button.jsx
similarity index 100%
rename from internal-api-harness/src/components/ui/button.jsx
rename to internal/api-harness/src/components/ui/button.jsx
diff --git a/frontend-web-free/src/components/ui/card.jsx b/internal/api-harness/src/components/ui/card.jsx
similarity index 100%
rename from frontend-web-free/src/components/ui/card.jsx
rename to internal/api-harness/src/components/ui/card.jsx
diff --git a/frontend-web-free/src/components/ui/collapsible.jsx b/internal/api-harness/src/components/ui/collapsible.jsx
similarity index 100%
rename from frontend-web-free/src/components/ui/collapsible.jsx
rename to internal/api-harness/src/components/ui/collapsible.jsx
diff --git a/internal-api-harness/src/components/ui/input.jsx b/internal/api-harness/src/components/ui/input.jsx
similarity index 100%
rename from internal-api-harness/src/components/ui/input.jsx
rename to internal/api-harness/src/components/ui/input.jsx
diff --git a/frontend-web-free/src/components/ui/label.jsx b/internal/api-harness/src/components/ui/label.jsx
similarity index 100%
rename from frontend-web-free/src/components/ui/label.jsx
rename to internal/api-harness/src/components/ui/label.jsx
diff --git a/internal-api-harness/src/components/ui/select.jsx b/internal/api-harness/src/components/ui/select.jsx
similarity index 100%
rename from internal-api-harness/src/components/ui/select.jsx
rename to internal/api-harness/src/components/ui/select.jsx
diff --git a/internal-api-harness/src/components/ui/textarea.jsx b/internal/api-harness/src/components/ui/textarea.jsx
similarity index 100%
rename from internal-api-harness/src/components/ui/textarea.jsx
rename to internal/api-harness/src/components/ui/textarea.jsx
diff --git a/internal/api-harness/src/dataconnect-generated/.guides/config.json b/internal/api-harness/src/dataconnect-generated/.guides/config.json
new file mode 100644
index 00000000..e37ed06f
--- /dev/null
+++ b/internal/api-harness/src/dataconnect-generated/.guides/config.json
@@ -0,0 +1,9 @@
+{
+ "description": "A set of guides for interacting with the generated firebase dataconnect sdk",
+ "mcpServers": {
+ "firebase": {
+ "command": "npx",
+ "args": ["-y", "firebase-tools@latest", "experimental:mcp"]
+ }
+ }
+}
diff --git a/internal/api-harness/src/dataconnect-generated/.guides/setup.md b/internal/api-harness/src/dataconnect-generated/.guides/setup.md
new file mode 100644
index 00000000..64a49286
--- /dev/null
+++ b/internal/api-harness/src/dataconnect-generated/.guides/setup.md
@@ -0,0 +1,62 @@
+# Setup
+
+If the user hasn't already installed the SDK, always run the user's node package manager of choice, and install the package in the directory ../package.json.
+For more information on where the library is located, look at the connector.yaml file.
+
+```ts
+import { initializeApp } from 'firebase/app';
+
+initializeApp({
+ // fill in your project config here using the values from your Firebase project or from the `firebase_get_sdk_config` tool from the Firebase MCP server.
+});
+```
+
+Then, you can run the SDK as needed.
+```ts
+import { ... } from '@dataconnect/generated';
+```
+
+
+
+
+## React
+### Setup
+
+The user should make sure to install the `@tanstack/react-query` package, along with `@tanstack-query-firebase/react` and `firebase`.
+
+Then, they should initialize Firebase:
+```ts
+import { initializeApp } from 'firebase/app';
+initializeApp(firebaseConfig); /* your config here. To generate this, you can use the `firebase_sdk_config` MCP tool */
+```
+
+Then, they should add a `QueryClientProvider` to their root of their application.
+
+Here's an example:
+
+```ts
+import { initializeApp } from 'firebase/app';
+import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
+
+const firebaseConfig = {
+ /* your config here. To generate this, you can use the `firebase_sdk_config` MCP tool */
+};
+
+// Initialize Firebase
+const app = initializeApp(firebaseConfig);
+
+// Create a TanStack Query client instance
+const queryClient = new QueryClient();
+
+function App() {
+ return (
+ // Provide the client to your App
+
+
+
+ )
+}
+
+render(
, document.getElementById('root'));
+```
+
diff --git a/internal/api-harness/src/dataconnect-generated/.guides/usage.md b/internal/api-harness/src/dataconnect-generated/.guides/usage.md
new file mode 100644
index 00000000..a16cce22
--- /dev/null
+++ b/internal/api-harness/src/dataconnect-generated/.guides/usage.md
@@ -0,0 +1,109 @@
+# Basic Usage
+
+Always prioritize using a supported framework over using the generated SDK
+directly. Supported frameworks simplify the developer experience and help ensure
+best practices are followed.
+
+
+
+
+### React
+For each operation, there is a wrapper hook that can be used to call the operation.
+
+Here are all of the hooks that get generated:
+```ts
+import { useCreateMessage, useUpdateMessage, useDeleteMessage, useCreateStaff, useUpdateStaff, useDeleteStaff, useListTeamMemberInvite, useGetTeamMemberInviteById, useFilterTeamMemberInvite, useCreateVendor } from '@dataconnect/generated/react';
+// The types of these hooks are available in react/index.d.ts
+
+const { data, isPending, isSuccess, isError, error } = useCreateMessage(createMessageVars);
+
+const { data, isPending, isSuccess, isError, error } = useUpdateMessage(updateMessageVars);
+
+const { data, isPending, isSuccess, isError, error } = useDeleteMessage(deleteMessageVars);
+
+const { data, isPending, isSuccess, isError, error } = useCreateStaff(createStaffVars);
+
+const { data, isPending, isSuccess, isError, error } = useUpdateStaff(updateStaffVars);
+
+const { data, isPending, isSuccess, isError, error } = useDeleteStaff(deleteStaffVars);
+
+const { data, isPending, isSuccess, isError, error } = useListTeamMemberInvite();
+
+const { data, isPending, isSuccess, isError, error } = useGetTeamMemberInviteById(getTeamMemberInviteByIdVars);
+
+const { data, isPending, isSuccess, isError, error } = useFilterTeamMemberInvite(filterTeamMemberInviteVars);
+
+const { data, isPending, isSuccess, isError, error } = useCreateVendor(createVendorVars);
+
+```
+
+Here's an example from a different generated SDK:
+
+```ts
+import { useListAllMovies } from '@dataconnect/generated/react';
+
+function MyComponent() {
+ const { isLoading, data, error } = useListAllMovies();
+ if(isLoading) {
+ return
Loading...
+ }
+ if(error) {
+ return
An Error Occurred: {error}
+ }
+}
+
+// App.tsx
+import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
+import MyComponent from './my-component';
+
+function App() {
+ const queryClient = new QueryClient();
+ return
+
+
+}
+```
+
+
+
+## Advanced Usage
+If a user is not using a supported framework, they can use the generated SDK directly.
+
+Here's an example of how to use it with the first 5 operations:
+
+```js
+import { createMessage, updateMessage, deleteMessage, createStaff, updateStaff, deleteStaff, listTeamMemberInvite, getTeamMemberInviteById, filterTeamMemberInvite, createVendor } from '@dataconnect/generated';
+
+
+// Operation CreateMessage: For variables, look at type CreateMessageVars in ../index.d.ts
+const { data } = await CreateMessage(dataConnect, createMessageVars);
+
+// Operation UpdateMessage: For variables, look at type UpdateMessageVars in ../index.d.ts
+const { data } = await UpdateMessage(dataConnect, updateMessageVars);
+
+// Operation DeleteMessage: For variables, look at type DeleteMessageVars in ../index.d.ts
+const { data } = await DeleteMessage(dataConnect, deleteMessageVars);
+
+// Operation CreateStaff: For variables, look at type CreateStaffVars in ../index.d.ts
+const { data } = await CreateStaff(dataConnect, createStaffVars);
+
+// Operation UpdateStaff: For variables, look at type UpdateStaffVars in ../index.d.ts
+const { data } = await UpdateStaff(dataConnect, updateStaffVars);
+
+// Operation DeleteStaff: For variables, look at type DeleteStaffVars in ../index.d.ts
+const { data } = await DeleteStaff(dataConnect, deleteStaffVars);
+
+// Operation listTeamMemberInvite:
+const { data } = await ListTeamMemberInvite(dataConnect);
+
+// Operation getTeamMemberInviteById: For variables, look at type GetTeamMemberInviteByIdVars in ../index.d.ts
+const { data } = await GetTeamMemberInviteById(dataConnect, getTeamMemberInviteByIdVars);
+
+// Operation filterTeamMemberInvite: For variables, look at type FilterTeamMemberInviteVars in ../index.d.ts
+const { data } = await FilterTeamMemberInvite(dataConnect, filterTeamMemberInviteVars);
+
+// Operation CreateVendor: For variables, look at type CreateVendorVars in ../index.d.ts
+const { data } = await CreateVendor(dataConnect, createVendorVars);
+
+
+```
\ No newline at end of file
diff --git a/internal/api-harness/src/dataconnect-generated/README.md b/internal/api-harness/src/dataconnect-generated/README.md
new file mode 100644
index 00000000..f57526db
--- /dev/null
+++ b/internal/api-harness/src/dataconnect-generated/README.md
@@ -0,0 +1,16929 @@
+# Generated TypeScript README
+This README will guide you through the process of using the generated JavaScript SDK package for the connector `krow-connector`. It will also provide examples on how to use your generated SDK to call your Data Connect queries and mutations.
+
+**If you're looking for the `React README`, you can find it at [`dataconnect-generated/react/README.md`](./react/README.md)**
+
+***NOTE:** This README is generated alongside the generated SDK. If you make changes to this file, they will be overwritten when the SDK is regenerated.*
+
+# Table of Contents
+- [**Overview**](#generated-javascript-readme)
+- [**Accessing the connector**](#accessing-the-connector)
+ - [*Connecting to the local Emulator*](#connecting-to-the-local-emulator)
+- [**Queries**](#queries)
+ - [*listTeamMemberInvite*](#listteammemberinvite)
+ - [*getTeamMemberInviteById*](#getteammemberinvitebyid)
+ - [*filterTeamMemberInvite*](#filterteammemberinvite)
+ - [*listCertification*](#listcertification)
+ - [*getCertificationById*](#getcertificationbyid)
+ - [*filterCertification*](#filtercertification)
+ - [*listConversation*](#listconversation)
+ - [*getConversationById*](#getconversationbyid)
+ - [*filterConversation*](#filterconversation)
+ - [*listShift*](#listshift)
+ - [*getShiftById*](#getshiftbyid)
+ - [*filterShift*](#filtershift)
+ - [*listEnterprise*](#listenterprise)
+ - [*getEnterpriseById*](#getenterprisebyid)
+ - [*filterEnterprise*](#filterenterprise)
+ - [*listInvoice*](#listinvoice)
+ - [*getInvoiceById*](#getinvoicebyid)
+ - [*filterInvoices*](#filterinvoices)
+ - [*listTeamMember*](#listteammember)
+ - [*getTeamMemberById*](#getteammemberbyid)
+ - [*filterTeamMember*](#filterteammember)
+ - [*listUsers*](#listusers)
+ - [*getUserById*](#getuserbyid)
+ - [*filterUsers*](#filterusers)
+ - [*listVendorDefaultSettings*](#listvendordefaultsettings)
+ - [*getVendorDefaultSettingById*](#getvendordefaultsettingbyid)
+ - [*filterVendorDefaultSettings*](#filtervendordefaultsettings)
+ - [*listAssignment*](#listassignment)
+ - [*getAssignmentById*](#getassignmentbyid)
+ - [*filterAssignment*](#filterassignment)
+ - [*listEvents*](#listevents)
+ - [*getEventById*](#geteventbyid)
+ - [*filterEvents*](#filterevents)
+ - [*listMessage*](#listmessage)
+ - [*getMessageById*](#getmessagebyid)
+ - [*filterMessage*](#filtermessage)
+ - [*listSector*](#listsector)
+ - [*getSectorById*](#getsectorbyid)
+ - [*filterSector*](#filtersector)
+ - [*listStaff*](#liststaff)
+ - [*getStaffById*](#getstaffbyid)
+ - [*filterStaff*](#filterstaff)
+ - [*listOrder*](#listorder)
+ - [*getOrderById*](#getorderbyid)
+ - [*filterOrder*](#filterorder)
+ - [*listPartner*](#listpartner)
+ - [*getPartnerById*](#getpartnerbyid)
+ - [*filterPartner*](#filterpartner)
+ - [*listVendor*](#listvendor)
+ - [*getVendorById*](#getvendorbyid)
+ - [*filterVendors*](#filtervendors)
+ - [*listWorkforce*](#listworkforce)
+ - [*getWorkforceById*](#getworkforcebyid)
+ - [*filterWorkforce*](#filterworkforce)
+ - [*listActivityLog*](#listactivitylog)
+ - [*getActivityLogById*](#getactivitylogbyid)
+ - [*filterActivityLog*](#filteractivitylog)
+ - [*listTeam*](#listteam)
+ - [*getTeamById*](#getteambyid)
+ - [*filterTeam*](#filterteam)
+ - [*listVendorRate*](#listvendorrate)
+ - [*getVendorRateById*](#getvendorratebyid)
+ - [*filterVendorRates*](#filtervendorrates)
+ - [*listTeamHub*](#listteamhub)
+ - [*getTeamHubById*](#getteamhubbyid)
+ - [*filterTeamHub*](#filterteamhub)
+ - [*listBusiness*](#listbusiness)
+ - [*getBusinessById*](#getbusinessbyid)
+ - [*filterBusiness*](#filterbusiness)
+- [**Mutations**](#mutations)
+ - [*CreateMessage*](#createmessage)
+ - [*UpdateMessage*](#updatemessage)
+ - [*DeleteMessage*](#deletemessage)
+ - [*CreateStaff*](#createstaff)
+ - [*UpdateStaff*](#updatestaff)
+ - [*DeleteStaff*](#deletestaff)
+ - [*CreateVendor*](#createvendor)
+ - [*UpdateVendor*](#updatevendor)
+ - [*DeleteVendor*](#deletevendor)
+ - [*CreateActivityLog*](#createactivitylog)
+ - [*UpdateActivityLog*](#updateactivitylog)
+ - [*DeleteActivityLog*](#deleteactivitylog)
+ - [*CreateAssignment*](#createassignment)
+ - [*UpdateAssignment*](#updateassignment)
+ - [*DeleteAssignment*](#deleteassignment)
+ - [*CreateCertification*](#createcertification)
+ - [*UpdateCertification*](#updatecertification)
+ - [*DeleteCertification*](#deletecertification)
+ - [*CreateShift*](#createshift)
+ - [*UpdateShift*](#updateshift)
+ - [*DeleteShift*](#deleteshift)
+ - [*CreateTeamHub*](#createteamhub)
+ - [*UpdateTeamHub*](#updateteamhub)
+ - [*DeleteTeamHub*](#deleteteamhub)
+ - [*CreateOrder*](#createorder)
+ - [*UpdateOrder*](#updateorder)
+ - [*DeleteOrder*](#deleteorder)
+ - [*CreateSector*](#createsector)
+ - [*UpdateSector*](#updatesector)
+ - [*DeleteSector*](#deletesector)
+ - [*CreateUser*](#createuser)
+ - [*UpdateUser*](#updateuser)
+ - [*DeleteUser*](#deleteuser)
+ - [*CreateTeamMemberInvite*](#createteammemberinvite)
+ - [*UpdateTeamMemberInvite*](#updateteammemberinvite)
+ - [*DeleteTeamMemberInvite*](#deleteteammemberinvite)
+ - [*CreateVendorDefaultSetting*](#createvendordefaultsetting)
+ - [*UpdateVendorDefaultSetting*](#updatevendordefaultsetting)
+ - [*DeleteVendorDefaultSetting*](#deletevendordefaultsetting)
+ - [*CreateVendorRate*](#createvendorrate)
+ - [*UpdateVendorRate*](#updatevendorrate)
+ - [*DeleteVendorRate*](#deletevendorrate)
+ - [*CreateEnterprise*](#createenterprise)
+ - [*UpdateEnterprise*](#updateenterprise)
+ - [*DeleteEnterprise*](#deleteenterprise)
+ - [*CreatePartner*](#createpartner)
+ - [*UpdatePartner*](#updatepartner)
+ - [*DeletePartner*](#deletepartner)
+ - [*CreateTeamMember*](#createteammember)
+ - [*UpdateTeamMember*](#updateteammember)
+ - [*DeleteTeamMember*](#deleteteammember)
+ - [*CreateConversation*](#createconversation)
+ - [*UpdateConversation*](#updateconversation)
+ - [*DeleteConversation*](#deleteconversation)
+ - [*CreateInvoice*](#createinvoice)
+ - [*UpdateInvoice*](#updateinvoice)
+ - [*DeleteInvoice*](#deleteinvoice)
+ - [*CreateBusiness*](#createbusiness)
+ - [*UpdateBusiness*](#updatebusiness)
+ - [*DeleteBusiness*](#deletebusiness)
+ - [*CreateEvent*](#createevent)
+ - [*UpdateEvent*](#updateevent)
+ - [*DeleteEvent*](#deleteevent)
+ - [*CreateTeam*](#createteam)
+ - [*UpdateTeam*](#updateteam)
+ - [*DeleteTeam*](#deleteteam)
+ - [*CreateWorkforce*](#createworkforce)
+ - [*UpdateWorkforce*](#updateworkforce)
+ - [*DeleteWorkforce*](#deleteworkforce)
+
+# Accessing the connector
+A connector is a collection of Queries and Mutations. One SDK is generated for each connector - this SDK is generated for the connector `krow-connector`. You can find more information about connectors in the [Data Connect documentation](https://firebase.google.com/docs/data-connect#how-does).
+
+You can use this generated SDK by importing from the package `@dataconnect/generated` as shown below. Both CommonJS and ESM imports are supported.
+
+You can also follow the instructions from the [Data Connect documentation](https://firebase.google.com/docs/data-connect/web-sdk#set-client).
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig } from '@dataconnect/generated';
+
+const dataConnect = getDataConnect(connectorConfig);
+```
+
+## Connecting to the local Emulator
+By default, the connector will connect to the production service.
+
+To connect to the emulator, you can use the following code.
+You can also follow the emulator instructions from the [Data Connect documentation](https://firebase.google.com/docs/data-connect/web-sdk#instrument-clients).
+
+```typescript
+import { connectDataConnectEmulator, getDataConnect } from 'firebase/data-connect';
+import { connectorConfig } from '@dataconnect/generated';
+
+const dataConnect = getDataConnect(connectorConfig);
+connectDataConnectEmulator(dataConnect, 'localhost', 9399);
+```
+
+After it's initialized, you can call your Data Connect [queries](#queries) and [mutations](#mutations) from your generated SDK.
+
+# Queries
+
+There are two ways to execute a Data Connect Query using the generated Web SDK:
+- Using a Query Reference function, which returns a `QueryRef`
+ - The `QueryRef` can be used as an argument to `executeQuery()`, which will execute the Query and return a `QueryPromise`
+- Using an action shortcut function, which returns a `QueryPromise`
+ - Calling the action shortcut function will execute the Query and return a `QueryPromise`
+
+The following is true for both the action shortcut function and the `QueryRef` function:
+- The `QueryPromise` returned will resolve to the result of the Query once it has finished executing
+- If the Query accepts arguments, both the action shortcut function and the `QueryRef` function accept a single argument: an object that contains all the required variables (and the optional variables) for the Query
+- Both functions can be called with or without passing in a `DataConnect` instance as an argument. If no `DataConnect` argument is passed in, then the generated SDK will call `getDataConnect(connectorConfig)` behind the scenes for you.
+
+Below are examples of how to use the `krow-connector` connector's generated functions to execute each query. You can also follow the examples from the [Data Connect documentation](https://firebase.google.com/docs/data-connect/web-sdk#using-queries).
+
+## listTeamMemberInvite
+You can execute the `listTeamMemberInvite` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+listTeamMemberInvite(): QueryPromise
;
+
+interface ListTeamMemberInviteRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (): QueryRef;
+}
+export const listTeamMemberInviteRef: ListTeamMemberInviteRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+listTeamMemberInvite(dc: DataConnect): QueryPromise;
+
+interface ListTeamMemberInviteRef {
+ ...
+ (dc: DataConnect): QueryRef;
+}
+export const listTeamMemberInviteRef: ListTeamMemberInviteRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the listTeamMemberInviteRef:
+```typescript
+const name = listTeamMemberInviteRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `listTeamMemberInvite` query has no variables.
+### Return Type
+Recall that executing the `listTeamMemberInvite` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `ListTeamMemberInviteData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface ListTeamMemberInviteData {
+ teamMemberInvites: ({
+ id: UUIDString;
+ teamId: UUIDString;
+ inviteCode: string;
+ email: string;
+ inviteStatus: TeamMemberInviteStatus;
+ } & TeamMemberInvite_Key)[];
+}
+```
+### Using `listTeamMemberInvite`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, listTeamMemberInvite } from '@dataconnect/generated';
+
+
+// Call the `listTeamMemberInvite()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await listTeamMemberInvite();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await listTeamMemberInvite(dataConnect);
+
+console.log(data.teamMemberInvites);
+
+// Or, you can use the `Promise` API.
+listTeamMemberInvite().then((response) => {
+ const data = response.data;
+ console.log(data.teamMemberInvites);
+});
+```
+
+### Using `listTeamMemberInvite`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, listTeamMemberInviteRef } from '@dataconnect/generated';
+
+
+// Call the `listTeamMemberInviteRef()` function to get a reference to the query.
+const ref = listTeamMemberInviteRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = listTeamMemberInviteRef(dataConnect);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.teamMemberInvites);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.teamMemberInvites);
+});
+```
+
+## getTeamMemberInviteById
+You can execute the `getTeamMemberInviteById` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+getTeamMemberInviteById(vars: GetTeamMemberInviteByIdVariables): QueryPromise;
+
+interface GetTeamMemberInviteByIdRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars: GetTeamMemberInviteByIdVariables): QueryRef;
+}
+export const getTeamMemberInviteByIdRef: GetTeamMemberInviteByIdRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+getTeamMemberInviteById(dc: DataConnect, vars: GetTeamMemberInviteByIdVariables): QueryPromise;
+
+interface GetTeamMemberInviteByIdRef {
+ ...
+ (dc: DataConnect, vars: GetTeamMemberInviteByIdVariables): QueryRef;
+}
+export const getTeamMemberInviteByIdRef: GetTeamMemberInviteByIdRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the getTeamMemberInviteByIdRef:
+```typescript
+const name = getTeamMemberInviteByIdRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `getTeamMemberInviteById` query requires an argument of type `GetTeamMemberInviteByIdVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface GetTeamMemberInviteByIdVariables {
+ id: UUIDString;
+}
+```
+### Return Type
+Recall that executing the `getTeamMemberInviteById` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `GetTeamMemberInviteByIdData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface GetTeamMemberInviteByIdData {
+ teamMemberInvite?: {
+ id: UUIDString;
+ teamId: UUIDString;
+ inviteCode: string;
+ email: string;
+ inviteStatus: TeamMemberInviteStatus;
+ } & TeamMemberInvite_Key;
+}
+```
+### Using `getTeamMemberInviteById`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, getTeamMemberInviteById, GetTeamMemberInviteByIdVariables } from '@dataconnect/generated';
+
+// The `getTeamMemberInviteById` query requires an argument of type `GetTeamMemberInviteByIdVariables`:
+const getTeamMemberInviteByIdVars: GetTeamMemberInviteByIdVariables = {
+ id: ...,
+};
+
+// Call the `getTeamMemberInviteById()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await getTeamMemberInviteById(getTeamMemberInviteByIdVars);
+// Variables can be defined inline as well.
+const { data } = await getTeamMemberInviteById({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await getTeamMemberInviteById(dataConnect, getTeamMemberInviteByIdVars);
+
+console.log(data.teamMemberInvite);
+
+// Or, you can use the `Promise` API.
+getTeamMemberInviteById(getTeamMemberInviteByIdVars).then((response) => {
+ const data = response.data;
+ console.log(data.teamMemberInvite);
+});
+```
+
+### Using `getTeamMemberInviteById`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, getTeamMemberInviteByIdRef, GetTeamMemberInviteByIdVariables } from '@dataconnect/generated';
+
+// The `getTeamMemberInviteById` query requires an argument of type `GetTeamMemberInviteByIdVariables`:
+const getTeamMemberInviteByIdVars: GetTeamMemberInviteByIdVariables = {
+ id: ...,
+};
+
+// Call the `getTeamMemberInviteByIdRef()` function to get a reference to the query.
+const ref = getTeamMemberInviteByIdRef(getTeamMemberInviteByIdVars);
+// Variables can be defined inline as well.
+const ref = getTeamMemberInviteByIdRef({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = getTeamMemberInviteByIdRef(dataConnect, getTeamMemberInviteByIdVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.teamMemberInvite);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.teamMemberInvite);
+});
+```
+
+## filterTeamMemberInvite
+You can execute the `filterTeamMemberInvite` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+filterTeamMemberInvite(vars?: FilterTeamMemberInviteVariables): QueryPromise;
+
+interface FilterTeamMemberInviteRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars?: FilterTeamMemberInviteVariables): QueryRef;
+}
+export const filterTeamMemberInviteRef: FilterTeamMemberInviteRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+filterTeamMemberInvite(dc: DataConnect, vars?: FilterTeamMemberInviteVariables): QueryPromise;
+
+interface FilterTeamMemberInviteRef {
+ ...
+ (dc: DataConnect, vars?: FilterTeamMemberInviteVariables): QueryRef;
+}
+export const filterTeamMemberInviteRef: FilterTeamMemberInviteRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the filterTeamMemberInviteRef:
+```typescript
+const name = filterTeamMemberInviteRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `filterTeamMemberInvite` query has an optional argument of type `FilterTeamMemberInviteVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface FilterTeamMemberInviteVariables {
+ teamId?: UUIDString | null;
+ email?: string | null;
+ inviteStatus?: TeamMemberInviteStatus | null;
+}
+```
+### Return Type
+Recall that executing the `filterTeamMemberInvite` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `FilterTeamMemberInviteData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface FilterTeamMemberInviteData {
+ teamMemberInvites: ({
+ id: UUIDString;
+ teamId: UUIDString;
+ inviteCode: string;
+ email: string;
+ inviteStatus: TeamMemberInviteStatus;
+ } & TeamMemberInvite_Key)[];
+}
+```
+### Using `filterTeamMemberInvite`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, filterTeamMemberInvite, FilterTeamMemberInviteVariables } from '@dataconnect/generated';
+
+// The `filterTeamMemberInvite` query has an optional argument of type `FilterTeamMemberInviteVariables`:
+const filterTeamMemberInviteVars: FilterTeamMemberInviteVariables = {
+ teamId: ..., // optional
+ email: ..., // optional
+ inviteStatus: ..., // optional
+};
+
+// Call the `filterTeamMemberInvite()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await filterTeamMemberInvite(filterTeamMemberInviteVars);
+// Variables can be defined inline as well.
+const { data } = await filterTeamMemberInvite({ teamId: ..., email: ..., inviteStatus: ..., });
+// Since all variables are optional for this query, you can omit the `FilterTeamMemberInviteVariables` argument.
+const { data } = await filterTeamMemberInvite();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await filterTeamMemberInvite(dataConnect, filterTeamMemberInviteVars);
+
+console.log(data.teamMemberInvites);
+
+// Or, you can use the `Promise` API.
+filterTeamMemberInvite(filterTeamMemberInviteVars).then((response) => {
+ const data = response.data;
+ console.log(data.teamMemberInvites);
+});
+```
+
+### Using `filterTeamMemberInvite`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, filterTeamMemberInviteRef, FilterTeamMemberInviteVariables } from '@dataconnect/generated';
+
+// The `filterTeamMemberInvite` query has an optional argument of type `FilterTeamMemberInviteVariables`:
+const filterTeamMemberInviteVars: FilterTeamMemberInviteVariables = {
+ teamId: ..., // optional
+ email: ..., // optional
+ inviteStatus: ..., // optional
+};
+
+// Call the `filterTeamMemberInviteRef()` function to get a reference to the query.
+const ref = filterTeamMemberInviteRef(filterTeamMemberInviteVars);
+// Variables can be defined inline as well.
+const ref = filterTeamMemberInviteRef({ teamId: ..., email: ..., inviteStatus: ..., });
+// Since all variables are optional for this query, you can omit the `FilterTeamMemberInviteVariables` argument.
+const ref = filterTeamMemberInviteRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = filterTeamMemberInviteRef(dataConnect, filterTeamMemberInviteVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.teamMemberInvites);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.teamMemberInvites);
+});
+```
+
+## listCertification
+You can execute the `listCertification` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+listCertification(): QueryPromise;
+
+interface ListCertificationRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (): QueryRef;
+}
+export const listCertificationRef: ListCertificationRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+listCertification(dc: DataConnect): QueryPromise;
+
+interface ListCertificationRef {
+ ...
+ (dc: DataConnect): QueryRef;
+}
+export const listCertificationRef: ListCertificationRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the listCertificationRef:
+```typescript
+const name = listCertificationRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `listCertification` query has no variables.
+### Return Type
+Recall that executing the `listCertification` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `ListCertificationData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface ListCertificationData {
+ certifications: ({
+ id: UUIDString;
+ employeeName: string;
+ certificationName: string;
+ certificationType?: CertificationType | null;
+ status?: CertificationStatus | null;
+ expiryDate: string;
+ validationStatus?: CertificationValidationStatus | null;
+ } & Certification_Key)[];
+}
+```
+### Using `listCertification`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, listCertification } from '@dataconnect/generated';
+
+
+// Call the `listCertification()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await listCertification();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await listCertification(dataConnect);
+
+console.log(data.certifications);
+
+// Or, you can use the `Promise` API.
+listCertification().then((response) => {
+ const data = response.data;
+ console.log(data.certifications);
+});
+```
+
+### Using `listCertification`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, listCertificationRef } from '@dataconnect/generated';
+
+
+// Call the `listCertificationRef()` function to get a reference to the query.
+const ref = listCertificationRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = listCertificationRef(dataConnect);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.certifications);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.certifications);
+});
+```
+
+## getCertificationById
+You can execute the `getCertificationById` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+getCertificationById(vars: GetCertificationByIdVariables): QueryPromise;
+
+interface GetCertificationByIdRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars: GetCertificationByIdVariables): QueryRef;
+}
+export const getCertificationByIdRef: GetCertificationByIdRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+getCertificationById(dc: DataConnect, vars: GetCertificationByIdVariables): QueryPromise;
+
+interface GetCertificationByIdRef {
+ ...
+ (dc: DataConnect, vars: GetCertificationByIdVariables): QueryRef;
+}
+export const getCertificationByIdRef: GetCertificationByIdRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the getCertificationByIdRef:
+```typescript
+const name = getCertificationByIdRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `getCertificationById` query requires an argument of type `GetCertificationByIdVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface GetCertificationByIdVariables {
+ id: UUIDString;
+}
+```
+### Return Type
+Recall that executing the `getCertificationById` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `GetCertificationByIdData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface GetCertificationByIdData {
+ certification?: {
+ id: UUIDString;
+ employeeName: string;
+ certificationName: string;
+ certificationType?: CertificationType | null;
+ status?: CertificationStatus | null;
+ expiryDate: string;
+ validationStatus?: CertificationValidationStatus | null;
+ createdDate?: TimestampString | null;
+ updatedDate?: TimestampString | null;
+ createdBy?: string | null;
+ } & Certification_Key;
+}
+```
+### Using `getCertificationById`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, getCertificationById, GetCertificationByIdVariables } from '@dataconnect/generated';
+
+// The `getCertificationById` query requires an argument of type `GetCertificationByIdVariables`:
+const getCertificationByIdVars: GetCertificationByIdVariables = {
+ id: ...,
+};
+
+// Call the `getCertificationById()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await getCertificationById(getCertificationByIdVars);
+// Variables can be defined inline as well.
+const { data } = await getCertificationById({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await getCertificationById(dataConnect, getCertificationByIdVars);
+
+console.log(data.certification);
+
+// Or, you can use the `Promise` API.
+getCertificationById(getCertificationByIdVars).then((response) => {
+ const data = response.data;
+ console.log(data.certification);
+});
+```
+
+### Using `getCertificationById`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, getCertificationByIdRef, GetCertificationByIdVariables } from '@dataconnect/generated';
+
+// The `getCertificationById` query requires an argument of type `GetCertificationByIdVariables`:
+const getCertificationByIdVars: GetCertificationByIdVariables = {
+ id: ...,
+};
+
+// Call the `getCertificationByIdRef()` function to get a reference to the query.
+const ref = getCertificationByIdRef(getCertificationByIdVars);
+// Variables can be defined inline as well.
+const ref = getCertificationByIdRef({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = getCertificationByIdRef(dataConnect, getCertificationByIdVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.certification);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.certification);
+});
+```
+
+## filterCertification
+You can execute the `filterCertification` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+filterCertification(vars?: FilterCertificationVariables): QueryPromise;
+
+interface FilterCertificationRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars?: FilterCertificationVariables): QueryRef;
+}
+export const filterCertificationRef: FilterCertificationRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+filterCertification(dc: DataConnect, vars?: FilterCertificationVariables): QueryPromise;
+
+interface FilterCertificationRef {
+ ...
+ (dc: DataConnect, vars?: FilterCertificationVariables): QueryRef;
+}
+export const filterCertificationRef: FilterCertificationRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the filterCertificationRef:
+```typescript
+const name = filterCertificationRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `filterCertification` query has an optional argument of type `FilterCertificationVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface FilterCertificationVariables {
+ employeeName?: string | null;
+ certificationName?: string | null;
+ certificationType?: CertificationType | null;
+ status?: CertificationStatus | null;
+ validationStatus?: CertificationValidationStatus | null;
+}
+```
+### Return Type
+Recall that executing the `filterCertification` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `FilterCertificationData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface FilterCertificationData {
+ certifications: ({
+ id: UUIDString;
+ employeeName: string;
+ certificationName: string;
+ certificationType?: CertificationType | null;
+ status?: CertificationStatus | null;
+ expiryDate: string;
+ validationStatus?: CertificationValidationStatus | null;
+ } & Certification_Key)[];
+}
+```
+### Using `filterCertification`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, filterCertification, FilterCertificationVariables } from '@dataconnect/generated';
+
+// The `filterCertification` query has an optional argument of type `FilterCertificationVariables`:
+const filterCertificationVars: FilterCertificationVariables = {
+ employeeName: ..., // optional
+ certificationName: ..., // optional
+ certificationType: ..., // optional
+ status: ..., // optional
+ validationStatus: ..., // optional
+};
+
+// Call the `filterCertification()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await filterCertification(filterCertificationVars);
+// Variables can be defined inline as well.
+const { data } = await filterCertification({ employeeName: ..., certificationName: ..., certificationType: ..., status: ..., validationStatus: ..., });
+// Since all variables are optional for this query, you can omit the `FilterCertificationVariables` argument.
+const { data } = await filterCertification();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await filterCertification(dataConnect, filterCertificationVars);
+
+console.log(data.certifications);
+
+// Or, you can use the `Promise` API.
+filterCertification(filterCertificationVars).then((response) => {
+ const data = response.data;
+ console.log(data.certifications);
+});
+```
+
+### Using `filterCertification`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, filterCertificationRef, FilterCertificationVariables } from '@dataconnect/generated';
+
+// The `filterCertification` query has an optional argument of type `FilterCertificationVariables`:
+const filterCertificationVars: FilterCertificationVariables = {
+ employeeName: ..., // optional
+ certificationName: ..., // optional
+ certificationType: ..., // optional
+ status: ..., // optional
+ validationStatus: ..., // optional
+};
+
+// Call the `filterCertificationRef()` function to get a reference to the query.
+const ref = filterCertificationRef(filterCertificationVars);
+// Variables can be defined inline as well.
+const ref = filterCertificationRef({ employeeName: ..., certificationName: ..., certificationType: ..., status: ..., validationStatus: ..., });
+// Since all variables are optional for this query, you can omit the `FilterCertificationVariables` argument.
+const ref = filterCertificationRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = filterCertificationRef(dataConnect, filterCertificationVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.certifications);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.certifications);
+});
+```
+
+## listConversation
+You can execute the `listConversation` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+listConversation(): QueryPromise;
+
+interface ListConversationRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (): QueryRef;
+}
+export const listConversationRef: ListConversationRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+listConversation(dc: DataConnect): QueryPromise;
+
+interface ListConversationRef {
+ ...
+ (dc: DataConnect): QueryRef;
+}
+export const listConversationRef: ListConversationRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the listConversationRef:
+```typescript
+const name = listConversationRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `listConversation` query has no variables.
+### Return Type
+Recall that executing the `listConversation` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `ListConversationData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface ListConversationData {
+ conversations: ({
+ id: UUIDString;
+ participants: string;
+ conversationType: ConversationType;
+ relatedTo: UUIDString;
+ status?: ConversationStatus | null;
+ } & Conversation_Key)[];
+}
+```
+### Using `listConversation`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, listConversation } from '@dataconnect/generated';
+
+
+// Call the `listConversation()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await listConversation();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await listConversation(dataConnect);
+
+console.log(data.conversations);
+
+// Or, you can use the `Promise` API.
+listConversation().then((response) => {
+ const data = response.data;
+ console.log(data.conversations);
+});
+```
+
+### Using `listConversation`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, listConversationRef } from '@dataconnect/generated';
+
+
+// Call the `listConversationRef()` function to get a reference to the query.
+const ref = listConversationRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = listConversationRef(dataConnect);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.conversations);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.conversations);
+});
+```
+
+## getConversationById
+You can execute the `getConversationById` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+getConversationById(vars: GetConversationByIdVariables): QueryPromise;
+
+interface GetConversationByIdRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars: GetConversationByIdVariables): QueryRef;
+}
+export const getConversationByIdRef: GetConversationByIdRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+getConversationById(dc: DataConnect, vars: GetConversationByIdVariables): QueryPromise;
+
+interface GetConversationByIdRef {
+ ...
+ (dc: DataConnect, vars: GetConversationByIdVariables): QueryRef;
+}
+export const getConversationByIdRef: GetConversationByIdRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the getConversationByIdRef:
+```typescript
+const name = getConversationByIdRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `getConversationById` query requires an argument of type `GetConversationByIdVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface GetConversationByIdVariables {
+ id: UUIDString;
+}
+```
+### Return Type
+Recall that executing the `getConversationById` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `GetConversationByIdData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface GetConversationByIdData {
+ conversation?: {
+ id: UUIDString;
+ participants: string;
+ conversationType: ConversationType;
+ relatedTo: UUIDString;
+ status?: ConversationStatus | null;
+ } & Conversation_Key;
+}
+```
+### Using `getConversationById`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, getConversationById, GetConversationByIdVariables } from '@dataconnect/generated';
+
+// The `getConversationById` query requires an argument of type `GetConversationByIdVariables`:
+const getConversationByIdVars: GetConversationByIdVariables = {
+ id: ...,
+};
+
+// Call the `getConversationById()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await getConversationById(getConversationByIdVars);
+// Variables can be defined inline as well.
+const { data } = await getConversationById({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await getConversationById(dataConnect, getConversationByIdVars);
+
+console.log(data.conversation);
+
+// Or, you can use the `Promise` API.
+getConversationById(getConversationByIdVars).then((response) => {
+ const data = response.data;
+ console.log(data.conversation);
+});
+```
+
+### Using `getConversationById`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, getConversationByIdRef, GetConversationByIdVariables } from '@dataconnect/generated';
+
+// The `getConversationById` query requires an argument of type `GetConversationByIdVariables`:
+const getConversationByIdVars: GetConversationByIdVariables = {
+ id: ...,
+};
+
+// Call the `getConversationByIdRef()` function to get a reference to the query.
+const ref = getConversationByIdRef(getConversationByIdVars);
+// Variables can be defined inline as well.
+const ref = getConversationByIdRef({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = getConversationByIdRef(dataConnect, getConversationByIdVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.conversation);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.conversation);
+});
+```
+
+## filterConversation
+You can execute the `filterConversation` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+filterConversation(vars?: FilterConversationVariables): QueryPromise;
+
+interface FilterConversationRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars?: FilterConversationVariables): QueryRef;
+}
+export const filterConversationRef: FilterConversationRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+filterConversation(dc: DataConnect, vars?: FilterConversationVariables): QueryPromise;
+
+interface FilterConversationRef {
+ ...
+ (dc: DataConnect, vars?: FilterConversationVariables): QueryRef;
+}
+export const filterConversationRef: FilterConversationRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the filterConversationRef:
+```typescript
+const name = filterConversationRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `filterConversation` query has an optional argument of type `FilterConversationVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface FilterConversationVariables {
+ conversationType?: ConversationType | null;
+ status?: ConversationStatus | null;
+ relatedTo?: UUIDString | null;
+}
+```
+### Return Type
+Recall that executing the `filterConversation` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `FilterConversationData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface FilterConversationData {
+ conversations: ({
+ id: UUIDString;
+ participants: string;
+ conversationType: ConversationType;
+ relatedTo: UUIDString;
+ status?: ConversationStatus | null;
+ } & Conversation_Key)[];
+}
+```
+### Using `filterConversation`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, filterConversation, FilterConversationVariables } from '@dataconnect/generated';
+
+// The `filterConversation` query has an optional argument of type `FilterConversationVariables`:
+const filterConversationVars: FilterConversationVariables = {
+ conversationType: ..., // optional
+ status: ..., // optional
+ relatedTo: ..., // optional
+};
+
+// Call the `filterConversation()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await filterConversation(filterConversationVars);
+// Variables can be defined inline as well.
+const { data } = await filterConversation({ conversationType: ..., status: ..., relatedTo: ..., });
+// Since all variables are optional for this query, you can omit the `FilterConversationVariables` argument.
+const { data } = await filterConversation();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await filterConversation(dataConnect, filterConversationVars);
+
+console.log(data.conversations);
+
+// Or, you can use the `Promise` API.
+filterConversation(filterConversationVars).then((response) => {
+ const data = response.data;
+ console.log(data.conversations);
+});
+```
+
+### Using `filterConversation`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, filterConversationRef, FilterConversationVariables } from '@dataconnect/generated';
+
+// The `filterConversation` query has an optional argument of type `FilterConversationVariables`:
+const filterConversationVars: FilterConversationVariables = {
+ conversationType: ..., // optional
+ status: ..., // optional
+ relatedTo: ..., // optional
+};
+
+// Call the `filterConversationRef()` function to get a reference to the query.
+const ref = filterConversationRef(filterConversationVars);
+// Variables can be defined inline as well.
+const ref = filterConversationRef({ conversationType: ..., status: ..., relatedTo: ..., });
+// Since all variables are optional for this query, you can omit the `FilterConversationVariables` argument.
+const ref = filterConversationRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = filterConversationRef(dataConnect, filterConversationVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.conversations);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.conversations);
+});
+```
+
+## listShift
+You can execute the `listShift` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+listShift(): QueryPromise;
+
+interface ListShiftRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (): QueryRef;
+}
+export const listShiftRef: ListShiftRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+listShift(dc: DataConnect): QueryPromise;
+
+interface ListShiftRef {
+ ...
+ (dc: DataConnect): QueryRef;
+}
+export const listShiftRef: ListShiftRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the listShiftRef:
+```typescript
+const name = listShiftRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `listShift` query has no variables.
+### Return Type
+Recall that executing the `listShift` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `ListShiftData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface ListShiftData {
+ shifts: ({
+ id: UUIDString;
+ shiftName: string;
+ startDate: TimestampString;
+ endDate?: TimestampString | null;
+ assignedStaff?: string | null;
+ } & Shift_Key)[];
+}
+```
+### Using `listShift`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, listShift } from '@dataconnect/generated';
+
+
+// Call the `listShift()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await listShift();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await listShift(dataConnect);
+
+console.log(data.shifts);
+
+// Or, you can use the `Promise` API.
+listShift().then((response) => {
+ const data = response.data;
+ console.log(data.shifts);
+});
+```
+
+### Using `listShift`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, listShiftRef } from '@dataconnect/generated';
+
+
+// Call the `listShiftRef()` function to get a reference to the query.
+const ref = listShiftRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = listShiftRef(dataConnect);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.shifts);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.shifts);
+});
+```
+
+## getShiftById
+You can execute the `getShiftById` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+getShiftById(vars: GetShiftByIdVariables): QueryPromise;
+
+interface GetShiftByIdRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars: GetShiftByIdVariables): QueryRef;
+}
+export const getShiftByIdRef: GetShiftByIdRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+getShiftById(dc: DataConnect, vars: GetShiftByIdVariables): QueryPromise;
+
+interface GetShiftByIdRef {
+ ...
+ (dc: DataConnect, vars: GetShiftByIdVariables): QueryRef;
+}
+export const getShiftByIdRef: GetShiftByIdRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the getShiftByIdRef:
+```typescript
+const name = getShiftByIdRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `getShiftById` query requires an argument of type `GetShiftByIdVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface GetShiftByIdVariables {
+ id: UUIDString;
+}
+```
+### Return Type
+Recall that executing the `getShiftById` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `GetShiftByIdData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface GetShiftByIdData {
+ shift?: {
+ id: UUIDString;
+ shiftName: string;
+ startDate: TimestampString;
+ endDate?: TimestampString | null;
+ assignedStaff?: string | null;
+ createdDate?: TimestampString | null;
+ updatedDate?: TimestampString | null;
+ createdBy?: string | null;
+ } & Shift_Key;
+}
+```
+### Using `getShiftById`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, getShiftById, GetShiftByIdVariables } from '@dataconnect/generated';
+
+// The `getShiftById` query requires an argument of type `GetShiftByIdVariables`:
+const getShiftByIdVars: GetShiftByIdVariables = {
+ id: ...,
+};
+
+// Call the `getShiftById()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await getShiftById(getShiftByIdVars);
+// Variables can be defined inline as well.
+const { data } = await getShiftById({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await getShiftById(dataConnect, getShiftByIdVars);
+
+console.log(data.shift);
+
+// Or, you can use the `Promise` API.
+getShiftById(getShiftByIdVars).then((response) => {
+ const data = response.data;
+ console.log(data.shift);
+});
+```
+
+### Using `getShiftById`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, getShiftByIdRef, GetShiftByIdVariables } from '@dataconnect/generated';
+
+// The `getShiftById` query requires an argument of type `GetShiftByIdVariables`:
+const getShiftByIdVars: GetShiftByIdVariables = {
+ id: ...,
+};
+
+// Call the `getShiftByIdRef()` function to get a reference to the query.
+const ref = getShiftByIdRef(getShiftByIdVars);
+// Variables can be defined inline as well.
+const ref = getShiftByIdRef({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = getShiftByIdRef(dataConnect, getShiftByIdVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.shift);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.shift);
+});
+```
+
+## filterShift
+You can execute the `filterShift` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+filterShift(vars?: FilterShiftVariables): QueryPromise;
+
+interface FilterShiftRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars?: FilterShiftVariables): QueryRef;
+}
+export const filterShiftRef: FilterShiftRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+filterShift(dc: DataConnect, vars?: FilterShiftVariables): QueryPromise;
+
+interface FilterShiftRef {
+ ...
+ (dc: DataConnect, vars?: FilterShiftVariables): QueryRef;
+}
+export const filterShiftRef: FilterShiftRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the filterShiftRef:
+```typescript
+const name = filterShiftRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `filterShift` query has an optional argument of type `FilterShiftVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface FilterShiftVariables {
+ shiftName?: string | null;
+ startDate?: TimestampString | null;
+ endDate?: TimestampString | null;
+}
+```
+### Return Type
+Recall that executing the `filterShift` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `FilterShiftData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface FilterShiftData {
+ shifts: ({
+ id: UUIDString;
+ shiftName: string;
+ startDate: TimestampString;
+ endDate?: TimestampString | null;
+ assignedStaff?: string | null;
+ } & Shift_Key)[];
+}
+```
+### Using `filterShift`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, filterShift, FilterShiftVariables } from '@dataconnect/generated';
+
+// The `filterShift` query has an optional argument of type `FilterShiftVariables`:
+const filterShiftVars: FilterShiftVariables = {
+ shiftName: ..., // optional
+ startDate: ..., // optional
+ endDate: ..., // optional
+};
+
+// Call the `filterShift()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await filterShift(filterShiftVars);
+// Variables can be defined inline as well.
+const { data } = await filterShift({ shiftName: ..., startDate: ..., endDate: ..., });
+// Since all variables are optional for this query, you can omit the `FilterShiftVariables` argument.
+const { data } = await filterShift();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await filterShift(dataConnect, filterShiftVars);
+
+console.log(data.shifts);
+
+// Or, you can use the `Promise` API.
+filterShift(filterShiftVars).then((response) => {
+ const data = response.data;
+ console.log(data.shifts);
+});
+```
+
+### Using `filterShift`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, filterShiftRef, FilterShiftVariables } from '@dataconnect/generated';
+
+// The `filterShift` query has an optional argument of type `FilterShiftVariables`:
+const filterShiftVars: FilterShiftVariables = {
+ shiftName: ..., // optional
+ startDate: ..., // optional
+ endDate: ..., // optional
+};
+
+// Call the `filterShiftRef()` function to get a reference to the query.
+const ref = filterShiftRef(filterShiftVars);
+// Variables can be defined inline as well.
+const ref = filterShiftRef({ shiftName: ..., startDate: ..., endDate: ..., });
+// Since all variables are optional for this query, you can omit the `FilterShiftVariables` argument.
+const ref = filterShiftRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = filterShiftRef(dataConnect, filterShiftVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.shifts);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.shifts);
+});
+```
+
+## listEnterprise
+You can execute the `listEnterprise` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+listEnterprise(): QueryPromise;
+
+interface ListEnterpriseRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (): QueryRef;
+}
+export const listEnterpriseRef: ListEnterpriseRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+listEnterprise(dc: DataConnect): QueryPromise;
+
+interface ListEnterpriseRef {
+ ...
+ (dc: DataConnect): QueryRef;
+}
+export const listEnterpriseRef: ListEnterpriseRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the listEnterpriseRef:
+```typescript
+const name = listEnterpriseRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `listEnterprise` query has no variables.
+### Return Type
+Recall that executing the `listEnterprise` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `ListEnterpriseData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface ListEnterpriseData {
+ enterprises: ({
+ id: UUIDString;
+ enterpriseNumber: string;
+ enterpriseName: string;
+ enterpriseCode: string;
+ } & Enterprise_Key)[];
+}
+```
+### Using `listEnterprise`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, listEnterprise } from '@dataconnect/generated';
+
+
+// Call the `listEnterprise()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await listEnterprise();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await listEnterprise(dataConnect);
+
+console.log(data.enterprises);
+
+// Or, you can use the `Promise` API.
+listEnterprise().then((response) => {
+ const data = response.data;
+ console.log(data.enterprises);
+});
+```
+
+### Using `listEnterprise`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, listEnterpriseRef } from '@dataconnect/generated';
+
+
+// Call the `listEnterpriseRef()` function to get a reference to the query.
+const ref = listEnterpriseRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = listEnterpriseRef(dataConnect);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.enterprises);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.enterprises);
+});
+```
+
+## getEnterpriseById
+You can execute the `getEnterpriseById` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+getEnterpriseById(vars: GetEnterpriseByIdVariables): QueryPromise;
+
+interface GetEnterpriseByIdRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars: GetEnterpriseByIdVariables): QueryRef;
+}
+export const getEnterpriseByIdRef: GetEnterpriseByIdRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+getEnterpriseById(dc: DataConnect, vars: GetEnterpriseByIdVariables): QueryPromise;
+
+interface GetEnterpriseByIdRef {
+ ...
+ (dc: DataConnect, vars: GetEnterpriseByIdVariables): QueryRef;
+}
+export const getEnterpriseByIdRef: GetEnterpriseByIdRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the getEnterpriseByIdRef:
+```typescript
+const name = getEnterpriseByIdRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `getEnterpriseById` query requires an argument of type `GetEnterpriseByIdVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface GetEnterpriseByIdVariables {
+ id: UUIDString;
+}
+```
+### Return Type
+Recall that executing the `getEnterpriseById` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `GetEnterpriseByIdData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface GetEnterpriseByIdData {
+ enterprise?: {
+ id: UUIDString;
+ enterpriseNumber: string;
+ enterpriseName: string;
+ enterpriseCode: string;
+ } & Enterprise_Key;
+}
+```
+### Using `getEnterpriseById`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, getEnterpriseById, GetEnterpriseByIdVariables } from '@dataconnect/generated';
+
+// The `getEnterpriseById` query requires an argument of type `GetEnterpriseByIdVariables`:
+const getEnterpriseByIdVars: GetEnterpriseByIdVariables = {
+ id: ...,
+};
+
+// Call the `getEnterpriseById()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await getEnterpriseById(getEnterpriseByIdVars);
+// Variables can be defined inline as well.
+const { data } = await getEnterpriseById({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await getEnterpriseById(dataConnect, getEnterpriseByIdVars);
+
+console.log(data.enterprise);
+
+// Or, you can use the `Promise` API.
+getEnterpriseById(getEnterpriseByIdVars).then((response) => {
+ const data = response.data;
+ console.log(data.enterprise);
+});
+```
+
+### Using `getEnterpriseById`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, getEnterpriseByIdRef, GetEnterpriseByIdVariables } from '@dataconnect/generated';
+
+// The `getEnterpriseById` query requires an argument of type `GetEnterpriseByIdVariables`:
+const getEnterpriseByIdVars: GetEnterpriseByIdVariables = {
+ id: ...,
+};
+
+// Call the `getEnterpriseByIdRef()` function to get a reference to the query.
+const ref = getEnterpriseByIdRef(getEnterpriseByIdVars);
+// Variables can be defined inline as well.
+const ref = getEnterpriseByIdRef({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = getEnterpriseByIdRef(dataConnect, getEnterpriseByIdVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.enterprise);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.enterprise);
+});
+```
+
+## filterEnterprise
+You can execute the `filterEnterprise` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+filterEnterprise(vars?: FilterEnterpriseVariables): QueryPromise;
+
+interface FilterEnterpriseRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars?: FilterEnterpriseVariables): QueryRef;
+}
+export const filterEnterpriseRef: FilterEnterpriseRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+filterEnterprise(dc: DataConnect, vars?: FilterEnterpriseVariables): QueryPromise;
+
+interface FilterEnterpriseRef {
+ ...
+ (dc: DataConnect, vars?: FilterEnterpriseVariables): QueryRef;
+}
+export const filterEnterpriseRef: FilterEnterpriseRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the filterEnterpriseRef:
+```typescript
+const name = filterEnterpriseRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `filterEnterprise` query has an optional argument of type `FilterEnterpriseVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface FilterEnterpriseVariables {
+ enterpriseNumber?: string | null;
+ enterpriseName?: string | null;
+ enterpriseCode?: string | null;
+}
+```
+### Return Type
+Recall that executing the `filterEnterprise` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `FilterEnterpriseData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface FilterEnterpriseData {
+ enterprises: ({
+ id: UUIDString;
+ enterpriseNumber: string;
+ enterpriseName: string;
+ enterpriseCode: string;
+ } & Enterprise_Key)[];
+}
+```
+### Using `filterEnterprise`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, filterEnterprise, FilterEnterpriseVariables } from '@dataconnect/generated';
+
+// The `filterEnterprise` query has an optional argument of type `FilterEnterpriseVariables`:
+const filterEnterpriseVars: FilterEnterpriseVariables = {
+ enterpriseNumber: ..., // optional
+ enterpriseName: ..., // optional
+ enterpriseCode: ..., // optional
+};
+
+// Call the `filterEnterprise()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await filterEnterprise(filterEnterpriseVars);
+// Variables can be defined inline as well.
+const { data } = await filterEnterprise({ enterpriseNumber: ..., enterpriseName: ..., enterpriseCode: ..., });
+// Since all variables are optional for this query, you can omit the `FilterEnterpriseVariables` argument.
+const { data } = await filterEnterprise();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await filterEnterprise(dataConnect, filterEnterpriseVars);
+
+console.log(data.enterprises);
+
+// Or, you can use the `Promise` API.
+filterEnterprise(filterEnterpriseVars).then((response) => {
+ const data = response.data;
+ console.log(data.enterprises);
+});
+```
+
+### Using `filterEnterprise`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, filterEnterpriseRef, FilterEnterpriseVariables } from '@dataconnect/generated';
+
+// The `filterEnterprise` query has an optional argument of type `FilterEnterpriseVariables`:
+const filterEnterpriseVars: FilterEnterpriseVariables = {
+ enterpriseNumber: ..., // optional
+ enterpriseName: ..., // optional
+ enterpriseCode: ..., // optional
+};
+
+// Call the `filterEnterpriseRef()` function to get a reference to the query.
+const ref = filterEnterpriseRef(filterEnterpriseVars);
+// Variables can be defined inline as well.
+const ref = filterEnterpriseRef({ enterpriseNumber: ..., enterpriseName: ..., enterpriseCode: ..., });
+// Since all variables are optional for this query, you can omit the `FilterEnterpriseVariables` argument.
+const ref = filterEnterpriseRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = filterEnterpriseRef(dataConnect, filterEnterpriseVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.enterprises);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.enterprises);
+});
+```
+
+## listInvoice
+You can execute the `listInvoice` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+listInvoice(): QueryPromise;
+
+interface ListInvoiceRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (): QueryRef;
+}
+export const listInvoiceRef: ListInvoiceRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+listInvoice(dc: DataConnect): QueryPromise;
+
+interface ListInvoiceRef {
+ ...
+ (dc: DataConnect): QueryRef;
+}
+export const listInvoiceRef: ListInvoiceRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the listInvoiceRef:
+```typescript
+const name = listInvoiceRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `listInvoice` query has no variables.
+### Return Type
+Recall that executing the `listInvoice` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `ListInvoiceData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface ListInvoiceData {
+ invoices: ({
+ id: UUIDString;
+ invoiceNumber: string;
+ amount: number;
+ status: InvoiceStatus;
+ issueDate: TimestampString;
+ dueDate: TimestampString;
+ disputedItems?: string | null;
+ isAutoGenerated?: boolean | null;
+ } & Invoice_Key)[];
+}
+```
+### Using `listInvoice`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, listInvoice } from '@dataconnect/generated';
+
+
+// Call the `listInvoice()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await listInvoice();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await listInvoice(dataConnect);
+
+console.log(data.invoices);
+
+// Or, you can use the `Promise` API.
+listInvoice().then((response) => {
+ const data = response.data;
+ console.log(data.invoices);
+});
+```
+
+### Using `listInvoice`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, listInvoiceRef } from '@dataconnect/generated';
+
+
+// Call the `listInvoiceRef()` function to get a reference to the query.
+const ref = listInvoiceRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = listInvoiceRef(dataConnect);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.invoices);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.invoices);
+});
+```
+
+## getInvoiceById
+You can execute the `getInvoiceById` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+getInvoiceById(vars: GetInvoiceByIdVariables): QueryPromise;
+
+interface GetInvoiceByIdRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars: GetInvoiceByIdVariables): QueryRef;
+}
+export const getInvoiceByIdRef: GetInvoiceByIdRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+getInvoiceById(dc: DataConnect, vars: GetInvoiceByIdVariables): QueryPromise;
+
+interface GetInvoiceByIdRef {
+ ...
+ (dc: DataConnect, vars: GetInvoiceByIdVariables): QueryRef;
+}
+export const getInvoiceByIdRef: GetInvoiceByIdRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the getInvoiceByIdRef:
+```typescript
+const name = getInvoiceByIdRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `getInvoiceById` query requires an argument of type `GetInvoiceByIdVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface GetInvoiceByIdVariables {
+ id: UUIDString;
+}
+```
+### Return Type
+Recall that executing the `getInvoiceById` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `GetInvoiceByIdData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface GetInvoiceByIdData {
+ invoice?: {
+ id: UUIDString;
+ invoiceNumber: string;
+ amount: number;
+ status: InvoiceStatus;
+ issueDate: TimestampString;
+ dueDate: TimestampString;
+ disputedItems?: string | null;
+ isAutoGenerated?: boolean | null;
+ } & Invoice_Key;
+}
+```
+### Using `getInvoiceById`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, getInvoiceById, GetInvoiceByIdVariables } from '@dataconnect/generated';
+
+// The `getInvoiceById` query requires an argument of type `GetInvoiceByIdVariables`:
+const getInvoiceByIdVars: GetInvoiceByIdVariables = {
+ id: ...,
+};
+
+// Call the `getInvoiceById()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await getInvoiceById(getInvoiceByIdVars);
+// Variables can be defined inline as well.
+const { data } = await getInvoiceById({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await getInvoiceById(dataConnect, getInvoiceByIdVars);
+
+console.log(data.invoice);
+
+// Or, you can use the `Promise` API.
+getInvoiceById(getInvoiceByIdVars).then((response) => {
+ const data = response.data;
+ console.log(data.invoice);
+});
+```
+
+### Using `getInvoiceById`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, getInvoiceByIdRef, GetInvoiceByIdVariables } from '@dataconnect/generated';
+
+// The `getInvoiceById` query requires an argument of type `GetInvoiceByIdVariables`:
+const getInvoiceByIdVars: GetInvoiceByIdVariables = {
+ id: ...,
+};
+
+// Call the `getInvoiceByIdRef()` function to get a reference to the query.
+const ref = getInvoiceByIdRef(getInvoiceByIdVars);
+// Variables can be defined inline as well.
+const ref = getInvoiceByIdRef({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = getInvoiceByIdRef(dataConnect, getInvoiceByIdVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.invoice);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.invoice);
+});
+```
+
+## filterInvoices
+You can execute the `filterInvoices` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+filterInvoices(vars?: FilterInvoicesVariables): QueryPromise;
+
+interface FilterInvoicesRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars?: FilterInvoicesVariables): QueryRef;
+}
+export const filterInvoicesRef: FilterInvoicesRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+filterInvoices(dc: DataConnect, vars?: FilterInvoicesVariables): QueryPromise;
+
+interface FilterInvoicesRef {
+ ...
+ (dc: DataConnect, vars?: FilterInvoicesVariables): QueryRef;
+}
+export const filterInvoicesRef: FilterInvoicesRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the filterInvoicesRef:
+```typescript
+const name = filterInvoicesRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `filterInvoices` query has an optional argument of type `FilterInvoicesVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface FilterInvoicesVariables {
+ invoiceNumber?: string | null;
+ status?: InvoiceStatus | null;
+ isAutoGenerated?: boolean | null;
+ amount?: number | null;
+}
+```
+### Return Type
+Recall that executing the `filterInvoices` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `FilterInvoicesData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface FilterInvoicesData {
+ invoices: ({
+ id: UUIDString;
+ invoiceNumber: string;
+ amount: number;
+ status: InvoiceStatus;
+ issueDate: TimestampString;
+ dueDate: TimestampString;
+ isAutoGenerated?: boolean | null;
+ } & Invoice_Key)[];
+}
+```
+### Using `filterInvoices`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, filterInvoices, FilterInvoicesVariables } from '@dataconnect/generated';
+
+// The `filterInvoices` query has an optional argument of type `FilterInvoicesVariables`:
+const filterInvoicesVars: FilterInvoicesVariables = {
+ invoiceNumber: ..., // optional
+ status: ..., // optional
+ isAutoGenerated: ..., // optional
+ amount: ..., // optional
+};
+
+// Call the `filterInvoices()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await filterInvoices(filterInvoicesVars);
+// Variables can be defined inline as well.
+const { data } = await filterInvoices({ invoiceNumber: ..., status: ..., isAutoGenerated: ..., amount: ..., });
+// Since all variables are optional for this query, you can omit the `FilterInvoicesVariables` argument.
+const { data } = await filterInvoices();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await filterInvoices(dataConnect, filterInvoicesVars);
+
+console.log(data.invoices);
+
+// Or, you can use the `Promise` API.
+filterInvoices(filterInvoicesVars).then((response) => {
+ const data = response.data;
+ console.log(data.invoices);
+});
+```
+
+### Using `filterInvoices`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, filterInvoicesRef, FilterInvoicesVariables } from '@dataconnect/generated';
+
+// The `filterInvoices` query has an optional argument of type `FilterInvoicesVariables`:
+const filterInvoicesVars: FilterInvoicesVariables = {
+ invoiceNumber: ..., // optional
+ status: ..., // optional
+ isAutoGenerated: ..., // optional
+ amount: ..., // optional
+};
+
+// Call the `filterInvoicesRef()` function to get a reference to the query.
+const ref = filterInvoicesRef(filterInvoicesVars);
+// Variables can be defined inline as well.
+const ref = filterInvoicesRef({ invoiceNumber: ..., status: ..., isAutoGenerated: ..., amount: ..., });
+// Since all variables are optional for this query, you can omit the `FilterInvoicesVariables` argument.
+const ref = filterInvoicesRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = filterInvoicesRef(dataConnect, filterInvoicesVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.invoices);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.invoices);
+});
+```
+
+## listTeamMember
+You can execute the `listTeamMember` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+listTeamMember(): QueryPromise;
+
+interface ListTeamMemberRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (): QueryRef;
+}
+export const listTeamMemberRef: ListTeamMemberRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+listTeamMember(dc: DataConnect): QueryPromise;
+
+interface ListTeamMemberRef {
+ ...
+ (dc: DataConnect): QueryRef;
+}
+export const listTeamMemberRef: ListTeamMemberRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the listTeamMemberRef:
+```typescript
+const name = listTeamMemberRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `listTeamMember` query has no variables.
+### Return Type
+Recall that executing the `listTeamMember` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `ListTeamMemberData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface ListTeamMemberData {
+ teamMembers: ({
+ id: UUIDString;
+ teamId: UUIDString;
+ memberName: string;
+ email: string;
+ role?: TeamMemberRole | null;
+ isActive?: boolean | null;
+ } & TeamMember_Key)[];
+}
+```
+### Using `listTeamMember`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, listTeamMember } from '@dataconnect/generated';
+
+
+// Call the `listTeamMember()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await listTeamMember();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await listTeamMember(dataConnect);
+
+console.log(data.teamMembers);
+
+// Or, you can use the `Promise` API.
+listTeamMember().then((response) => {
+ const data = response.data;
+ console.log(data.teamMembers);
+});
+```
+
+### Using `listTeamMember`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, listTeamMemberRef } from '@dataconnect/generated';
+
+
+// Call the `listTeamMemberRef()` function to get a reference to the query.
+const ref = listTeamMemberRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = listTeamMemberRef(dataConnect);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.teamMembers);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.teamMembers);
+});
+```
+
+## getTeamMemberById
+You can execute the `getTeamMemberById` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+getTeamMemberById(vars: GetTeamMemberByIdVariables): QueryPromise;
+
+interface GetTeamMemberByIdRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars: GetTeamMemberByIdVariables): QueryRef;
+}
+export const getTeamMemberByIdRef: GetTeamMemberByIdRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+getTeamMemberById(dc: DataConnect, vars: GetTeamMemberByIdVariables): QueryPromise;
+
+interface GetTeamMemberByIdRef {
+ ...
+ (dc: DataConnect, vars: GetTeamMemberByIdVariables): QueryRef;
+}
+export const getTeamMemberByIdRef: GetTeamMemberByIdRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the getTeamMemberByIdRef:
+```typescript
+const name = getTeamMemberByIdRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `getTeamMemberById` query requires an argument of type `GetTeamMemberByIdVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface GetTeamMemberByIdVariables {
+ id: UUIDString;
+}
+```
+### Return Type
+Recall that executing the `getTeamMemberById` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `GetTeamMemberByIdData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface GetTeamMemberByIdData {
+ teamMember?: {
+ id: UUIDString;
+ teamId: UUIDString;
+ memberName: string;
+ email: string;
+ role?: TeamMemberRole | null;
+ isActive?: boolean | null;
+ } & TeamMember_Key;
+}
+```
+### Using `getTeamMemberById`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, getTeamMemberById, GetTeamMemberByIdVariables } from '@dataconnect/generated';
+
+// The `getTeamMemberById` query requires an argument of type `GetTeamMemberByIdVariables`:
+const getTeamMemberByIdVars: GetTeamMemberByIdVariables = {
+ id: ...,
+};
+
+// Call the `getTeamMemberById()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await getTeamMemberById(getTeamMemberByIdVars);
+// Variables can be defined inline as well.
+const { data } = await getTeamMemberById({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await getTeamMemberById(dataConnect, getTeamMemberByIdVars);
+
+console.log(data.teamMember);
+
+// Or, you can use the `Promise` API.
+getTeamMemberById(getTeamMemberByIdVars).then((response) => {
+ const data = response.data;
+ console.log(data.teamMember);
+});
+```
+
+### Using `getTeamMemberById`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, getTeamMemberByIdRef, GetTeamMemberByIdVariables } from '@dataconnect/generated';
+
+// The `getTeamMemberById` query requires an argument of type `GetTeamMemberByIdVariables`:
+const getTeamMemberByIdVars: GetTeamMemberByIdVariables = {
+ id: ...,
+};
+
+// Call the `getTeamMemberByIdRef()` function to get a reference to the query.
+const ref = getTeamMemberByIdRef(getTeamMemberByIdVars);
+// Variables can be defined inline as well.
+const ref = getTeamMemberByIdRef({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = getTeamMemberByIdRef(dataConnect, getTeamMemberByIdVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.teamMember);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.teamMember);
+});
+```
+
+## filterTeamMember
+You can execute the `filterTeamMember` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+filterTeamMember(vars?: FilterTeamMemberVariables): QueryPromise;
+
+interface FilterTeamMemberRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars?: FilterTeamMemberVariables): QueryRef;
+}
+export const filterTeamMemberRef: FilterTeamMemberRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+filterTeamMember(dc: DataConnect, vars?: FilterTeamMemberVariables): QueryPromise;
+
+interface FilterTeamMemberRef {
+ ...
+ (dc: DataConnect, vars?: FilterTeamMemberVariables): QueryRef;
+}
+export const filterTeamMemberRef: FilterTeamMemberRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the filterTeamMemberRef:
+```typescript
+const name = filterTeamMemberRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `filterTeamMember` query has an optional argument of type `FilterTeamMemberVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface FilterTeamMemberVariables {
+ teamId?: UUIDString | null;
+ memberName?: string | null;
+ email?: string | null;
+ role?: TeamMemberRole | null;
+ isActive?: boolean | null;
+}
+```
+### Return Type
+Recall that executing the `filterTeamMember` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `FilterTeamMemberData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface FilterTeamMemberData {
+ teamMembers: ({
+ id: UUIDString;
+ teamId: UUIDString;
+ memberName: string;
+ email: string;
+ role?: TeamMemberRole | null;
+ isActive?: boolean | null;
+ } & TeamMember_Key)[];
+}
+```
+### Using `filterTeamMember`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, filterTeamMember, FilterTeamMemberVariables } from '@dataconnect/generated';
+
+// The `filterTeamMember` query has an optional argument of type `FilterTeamMemberVariables`:
+const filterTeamMemberVars: FilterTeamMemberVariables = {
+ teamId: ..., // optional
+ memberName: ..., // optional
+ email: ..., // optional
+ role: ..., // optional
+ isActive: ..., // optional
+};
+
+// Call the `filterTeamMember()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await filterTeamMember(filterTeamMemberVars);
+// Variables can be defined inline as well.
+const { data } = await filterTeamMember({ teamId: ..., memberName: ..., email: ..., role: ..., isActive: ..., });
+// Since all variables are optional for this query, you can omit the `FilterTeamMemberVariables` argument.
+const { data } = await filterTeamMember();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await filterTeamMember(dataConnect, filterTeamMemberVars);
+
+console.log(data.teamMembers);
+
+// Or, you can use the `Promise` API.
+filterTeamMember(filterTeamMemberVars).then((response) => {
+ const data = response.data;
+ console.log(data.teamMembers);
+});
+```
+
+### Using `filterTeamMember`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, filterTeamMemberRef, FilterTeamMemberVariables } from '@dataconnect/generated';
+
+// The `filterTeamMember` query has an optional argument of type `FilterTeamMemberVariables`:
+const filterTeamMemberVars: FilterTeamMemberVariables = {
+ teamId: ..., // optional
+ memberName: ..., // optional
+ email: ..., // optional
+ role: ..., // optional
+ isActive: ..., // optional
+};
+
+// Call the `filterTeamMemberRef()` function to get a reference to the query.
+const ref = filterTeamMemberRef(filterTeamMemberVars);
+// Variables can be defined inline as well.
+const ref = filterTeamMemberRef({ teamId: ..., memberName: ..., email: ..., role: ..., isActive: ..., });
+// Since all variables are optional for this query, you can omit the `FilterTeamMemberVariables` argument.
+const ref = filterTeamMemberRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = filterTeamMemberRef(dataConnect, filterTeamMemberVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.teamMembers);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.teamMembers);
+});
+```
+
+## listUsers
+You can execute the `listUsers` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+listUsers(): QueryPromise;
+
+interface ListUsersRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (): QueryRef;
+}
+export const listUsersRef: ListUsersRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+listUsers(dc: DataConnect): QueryPromise;
+
+interface ListUsersRef {
+ ...
+ (dc: DataConnect): QueryRef;
+}
+export const listUsersRef: ListUsersRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the listUsersRef:
+```typescript
+const name = listUsersRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `listUsers` query has no variables.
+### Return Type
+Recall that executing the `listUsers` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `ListUsersData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface ListUsersData {
+ users: ({
+ id: string;
+ email: string;
+ fullName: string;
+ role: UserBaseRole;
+ userRole?: string | null;
+ createdDate?: TimestampString | null;
+ updatedDate?: TimestampString | null;
+ } & User_Key)[];
+}
+```
+### Using `listUsers`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, listUsers } from '@dataconnect/generated';
+
+
+// Call the `listUsers()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await listUsers();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await listUsers(dataConnect);
+
+console.log(data.users);
+
+// Or, you can use the `Promise` API.
+listUsers().then((response) => {
+ const data = response.data;
+ console.log(data.users);
+});
+```
+
+### Using `listUsers`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, listUsersRef } from '@dataconnect/generated';
+
+
+// Call the `listUsersRef()` function to get a reference to the query.
+const ref = listUsersRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = listUsersRef(dataConnect);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.users);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.users);
+});
+```
+
+## getUserById
+You can execute the `getUserById` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+getUserById(vars: GetUserByIdVariables): QueryPromise;
+
+interface GetUserByIdRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars: GetUserByIdVariables): QueryRef;
+}
+export const getUserByIdRef: GetUserByIdRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+getUserById(dc: DataConnect, vars: GetUserByIdVariables): QueryPromise;
+
+interface GetUserByIdRef {
+ ...
+ (dc: DataConnect, vars: GetUserByIdVariables): QueryRef;
+}
+export const getUserByIdRef: GetUserByIdRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the getUserByIdRef:
+```typescript
+const name = getUserByIdRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `getUserById` query requires an argument of type `GetUserByIdVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface GetUserByIdVariables {
+ id: string;
+}
+```
+### Return Type
+Recall that executing the `getUserById` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `GetUserByIdData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface GetUserByIdData {
+ user?: {
+ id: string;
+ email: string;
+ fullName: string;
+ role: UserBaseRole;
+ userRole?: string | null;
+ } & User_Key;
+}
+```
+### Using `getUserById`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, getUserById, GetUserByIdVariables } from '@dataconnect/generated';
+
+// The `getUserById` query requires an argument of type `GetUserByIdVariables`:
+const getUserByIdVars: GetUserByIdVariables = {
+ id: ...,
+};
+
+// Call the `getUserById()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await getUserById(getUserByIdVars);
+// Variables can be defined inline as well.
+const { data } = await getUserById({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await getUserById(dataConnect, getUserByIdVars);
+
+console.log(data.user);
+
+// Or, you can use the `Promise` API.
+getUserById(getUserByIdVars).then((response) => {
+ const data = response.data;
+ console.log(data.user);
+});
+```
+
+### Using `getUserById`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, getUserByIdRef, GetUserByIdVariables } from '@dataconnect/generated';
+
+// The `getUserById` query requires an argument of type `GetUserByIdVariables`:
+const getUserByIdVars: GetUserByIdVariables = {
+ id: ...,
+};
+
+// Call the `getUserByIdRef()` function to get a reference to the query.
+const ref = getUserByIdRef(getUserByIdVars);
+// Variables can be defined inline as well.
+const ref = getUserByIdRef({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = getUserByIdRef(dataConnect, getUserByIdVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.user);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.user);
+});
+```
+
+## filterUsers
+You can execute the `filterUsers` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+filterUsers(vars?: FilterUsersVariables): QueryPromise;
+
+interface FilterUsersRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars?: FilterUsersVariables): QueryRef;
+}
+export const filterUsersRef: FilterUsersRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+filterUsers(dc: DataConnect, vars?: FilterUsersVariables): QueryPromise;
+
+interface FilterUsersRef {
+ ...
+ (dc: DataConnect, vars?: FilterUsersVariables): QueryRef;
+}
+export const filterUsersRef: FilterUsersRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the filterUsersRef:
+```typescript
+const name = filterUsersRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `filterUsers` query has an optional argument of type `FilterUsersVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface FilterUsersVariables {
+ id?: string | null;
+ email?: string | null;
+ role?: UserBaseRole | null;
+ userRole?: string | null;
+}
+```
+### Return Type
+Recall that executing the `filterUsers` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `FilterUsersData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface FilterUsersData {
+ users: ({
+ id: string;
+ email: string;
+ fullName: string;
+ role: UserBaseRole;
+ userRole?: string | null;
+ } & User_Key)[];
+}
+```
+### Using `filterUsers`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, filterUsers, FilterUsersVariables } from '@dataconnect/generated';
+
+// The `filterUsers` query has an optional argument of type `FilterUsersVariables`:
+const filterUsersVars: FilterUsersVariables = {
+ id: ..., // optional
+ email: ..., // optional
+ role: ..., // optional
+ userRole: ..., // optional
+};
+
+// Call the `filterUsers()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await filterUsers(filterUsersVars);
+// Variables can be defined inline as well.
+const { data } = await filterUsers({ id: ..., email: ..., role: ..., userRole: ..., });
+// Since all variables are optional for this query, you can omit the `FilterUsersVariables` argument.
+const { data } = await filterUsers();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await filterUsers(dataConnect, filterUsersVars);
+
+console.log(data.users);
+
+// Or, you can use the `Promise` API.
+filterUsers(filterUsersVars).then((response) => {
+ const data = response.data;
+ console.log(data.users);
+});
+```
+
+### Using `filterUsers`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, filterUsersRef, FilterUsersVariables } from '@dataconnect/generated';
+
+// The `filterUsers` query has an optional argument of type `FilterUsersVariables`:
+const filterUsersVars: FilterUsersVariables = {
+ id: ..., // optional
+ email: ..., // optional
+ role: ..., // optional
+ userRole: ..., // optional
+};
+
+// Call the `filterUsersRef()` function to get a reference to the query.
+const ref = filterUsersRef(filterUsersVars);
+// Variables can be defined inline as well.
+const ref = filterUsersRef({ id: ..., email: ..., role: ..., userRole: ..., });
+// Since all variables are optional for this query, you can omit the `FilterUsersVariables` argument.
+const ref = filterUsersRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = filterUsersRef(dataConnect, filterUsersVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.users);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.users);
+});
+```
+
+## listVendorDefaultSettings
+You can execute the `listVendorDefaultSettings` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+listVendorDefaultSettings(): QueryPromise;
+
+interface ListVendorDefaultSettingsRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (): QueryRef;
+}
+export const listVendorDefaultSettingsRef: ListVendorDefaultSettingsRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+listVendorDefaultSettings(dc: DataConnect): QueryPromise;
+
+interface ListVendorDefaultSettingsRef {
+ ...
+ (dc: DataConnect): QueryRef;
+}
+export const listVendorDefaultSettingsRef: ListVendorDefaultSettingsRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the listVendorDefaultSettingsRef:
+```typescript
+const name = listVendorDefaultSettingsRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `listVendorDefaultSettings` query has no variables.
+### Return Type
+Recall that executing the `listVendorDefaultSettings` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `ListVendorDefaultSettingsData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface ListVendorDefaultSettingsData {
+ vendorDefaultSettings: ({
+ id: UUIDString;
+ vendorName: string;
+ defaultMarkupPercentage: number;
+ defaultVendorFeePercentage: number;
+ } & VendorDefaultSetting_Key)[];
+}
+```
+### Using `listVendorDefaultSettings`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, listVendorDefaultSettings } from '@dataconnect/generated';
+
+
+// Call the `listVendorDefaultSettings()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await listVendorDefaultSettings();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await listVendorDefaultSettings(dataConnect);
+
+console.log(data.vendorDefaultSettings);
+
+// Or, you can use the `Promise` API.
+listVendorDefaultSettings().then((response) => {
+ const data = response.data;
+ console.log(data.vendorDefaultSettings);
+});
+```
+
+### Using `listVendorDefaultSettings`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, listVendorDefaultSettingsRef } from '@dataconnect/generated';
+
+
+// Call the `listVendorDefaultSettingsRef()` function to get a reference to the query.
+const ref = listVendorDefaultSettingsRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = listVendorDefaultSettingsRef(dataConnect);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.vendorDefaultSettings);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.vendorDefaultSettings);
+});
+```
+
+## getVendorDefaultSettingById
+You can execute the `getVendorDefaultSettingById` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+getVendorDefaultSettingById(vars: GetVendorDefaultSettingByIdVariables): QueryPromise;
+
+interface GetVendorDefaultSettingByIdRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars: GetVendorDefaultSettingByIdVariables): QueryRef;
+}
+export const getVendorDefaultSettingByIdRef: GetVendorDefaultSettingByIdRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+getVendorDefaultSettingById(dc: DataConnect, vars: GetVendorDefaultSettingByIdVariables): QueryPromise;
+
+interface GetVendorDefaultSettingByIdRef {
+ ...
+ (dc: DataConnect, vars: GetVendorDefaultSettingByIdVariables): QueryRef;
+}
+export const getVendorDefaultSettingByIdRef: GetVendorDefaultSettingByIdRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the getVendorDefaultSettingByIdRef:
+```typescript
+const name = getVendorDefaultSettingByIdRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `getVendorDefaultSettingById` query requires an argument of type `GetVendorDefaultSettingByIdVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface GetVendorDefaultSettingByIdVariables {
+ id: UUIDString;
+}
+```
+### Return Type
+Recall that executing the `getVendorDefaultSettingById` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `GetVendorDefaultSettingByIdData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface GetVendorDefaultSettingByIdData {
+ vendorDefaultSetting?: {
+ id: UUIDString;
+ vendorName: string;
+ defaultMarkupPercentage: number;
+ defaultVendorFeePercentage: number;
+ } & VendorDefaultSetting_Key;
+}
+```
+### Using `getVendorDefaultSettingById`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, getVendorDefaultSettingById, GetVendorDefaultSettingByIdVariables } from '@dataconnect/generated';
+
+// The `getVendorDefaultSettingById` query requires an argument of type `GetVendorDefaultSettingByIdVariables`:
+const getVendorDefaultSettingByIdVars: GetVendorDefaultSettingByIdVariables = {
+ id: ...,
+};
+
+// Call the `getVendorDefaultSettingById()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await getVendorDefaultSettingById(getVendorDefaultSettingByIdVars);
+// Variables can be defined inline as well.
+const { data } = await getVendorDefaultSettingById({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await getVendorDefaultSettingById(dataConnect, getVendorDefaultSettingByIdVars);
+
+console.log(data.vendorDefaultSetting);
+
+// Or, you can use the `Promise` API.
+getVendorDefaultSettingById(getVendorDefaultSettingByIdVars).then((response) => {
+ const data = response.data;
+ console.log(data.vendorDefaultSetting);
+});
+```
+
+### Using `getVendorDefaultSettingById`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, getVendorDefaultSettingByIdRef, GetVendorDefaultSettingByIdVariables } from '@dataconnect/generated';
+
+// The `getVendorDefaultSettingById` query requires an argument of type `GetVendorDefaultSettingByIdVariables`:
+const getVendorDefaultSettingByIdVars: GetVendorDefaultSettingByIdVariables = {
+ id: ...,
+};
+
+// Call the `getVendorDefaultSettingByIdRef()` function to get a reference to the query.
+const ref = getVendorDefaultSettingByIdRef(getVendorDefaultSettingByIdVars);
+// Variables can be defined inline as well.
+const ref = getVendorDefaultSettingByIdRef({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = getVendorDefaultSettingByIdRef(dataConnect, getVendorDefaultSettingByIdVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.vendorDefaultSetting);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.vendorDefaultSetting);
+});
+```
+
+## filterVendorDefaultSettings
+You can execute the `filterVendorDefaultSettings` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+filterVendorDefaultSettings(vars?: FilterVendorDefaultSettingsVariables): QueryPromise;
+
+interface FilterVendorDefaultSettingsRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars?: FilterVendorDefaultSettingsVariables): QueryRef;
+}
+export const filterVendorDefaultSettingsRef: FilterVendorDefaultSettingsRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+filterVendorDefaultSettings(dc: DataConnect, vars?: FilterVendorDefaultSettingsVariables): QueryPromise;
+
+interface FilterVendorDefaultSettingsRef {
+ ...
+ (dc: DataConnect, vars?: FilterVendorDefaultSettingsVariables): QueryRef;
+}
+export const filterVendorDefaultSettingsRef: FilterVendorDefaultSettingsRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the filterVendorDefaultSettingsRef:
+```typescript
+const name = filterVendorDefaultSettingsRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `filterVendorDefaultSettings` query has an optional argument of type `FilterVendorDefaultSettingsVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface FilterVendorDefaultSettingsVariables {
+ vendorName?: string | null;
+ defaultMarkupPercentage?: number | null;
+ defaultVendorFeePercentage?: number | null;
+}
+```
+### Return Type
+Recall that executing the `filterVendorDefaultSettings` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `FilterVendorDefaultSettingsData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface FilterVendorDefaultSettingsData {
+ vendorDefaultSettings: ({
+ id: UUIDString;
+ vendorName: string;
+ defaultMarkupPercentage: number;
+ defaultVendorFeePercentage: number;
+ } & VendorDefaultSetting_Key)[];
+}
+```
+### Using `filterVendorDefaultSettings`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, filterVendorDefaultSettings, FilterVendorDefaultSettingsVariables } from '@dataconnect/generated';
+
+// The `filterVendorDefaultSettings` query has an optional argument of type `FilterVendorDefaultSettingsVariables`:
+const filterVendorDefaultSettingsVars: FilterVendorDefaultSettingsVariables = {
+ vendorName: ..., // optional
+ defaultMarkupPercentage: ..., // optional
+ defaultVendorFeePercentage: ..., // optional
+};
+
+// Call the `filterVendorDefaultSettings()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await filterVendorDefaultSettings(filterVendorDefaultSettingsVars);
+// Variables can be defined inline as well.
+const { data } = await filterVendorDefaultSettings({ vendorName: ..., defaultMarkupPercentage: ..., defaultVendorFeePercentage: ..., });
+// Since all variables are optional for this query, you can omit the `FilterVendorDefaultSettingsVariables` argument.
+const { data } = await filterVendorDefaultSettings();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await filterVendorDefaultSettings(dataConnect, filterVendorDefaultSettingsVars);
+
+console.log(data.vendorDefaultSettings);
+
+// Or, you can use the `Promise` API.
+filterVendorDefaultSettings(filterVendorDefaultSettingsVars).then((response) => {
+ const data = response.data;
+ console.log(data.vendorDefaultSettings);
+});
+```
+
+### Using `filterVendorDefaultSettings`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, filterVendorDefaultSettingsRef, FilterVendorDefaultSettingsVariables } from '@dataconnect/generated';
+
+// The `filterVendorDefaultSettings` query has an optional argument of type `FilterVendorDefaultSettingsVariables`:
+const filterVendorDefaultSettingsVars: FilterVendorDefaultSettingsVariables = {
+ vendorName: ..., // optional
+ defaultMarkupPercentage: ..., // optional
+ defaultVendorFeePercentage: ..., // optional
+};
+
+// Call the `filterVendorDefaultSettingsRef()` function to get a reference to the query.
+const ref = filterVendorDefaultSettingsRef(filterVendorDefaultSettingsVars);
+// Variables can be defined inline as well.
+const ref = filterVendorDefaultSettingsRef({ vendorName: ..., defaultMarkupPercentage: ..., defaultVendorFeePercentage: ..., });
+// Since all variables are optional for this query, you can omit the `FilterVendorDefaultSettingsVariables` argument.
+const ref = filterVendorDefaultSettingsRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = filterVendorDefaultSettingsRef(dataConnect, filterVendorDefaultSettingsVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.vendorDefaultSettings);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.vendorDefaultSettings);
+});
+```
+
+## listAssignment
+You can execute the `listAssignment` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+listAssignment(): QueryPromise;
+
+interface ListAssignmentRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (): QueryRef;
+}
+export const listAssignmentRef: ListAssignmentRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+listAssignment(dc: DataConnect): QueryPromise;
+
+interface ListAssignmentRef {
+ ...
+ (dc: DataConnect): QueryRef;
+}
+export const listAssignmentRef: ListAssignmentRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the listAssignmentRef:
+```typescript
+const name = listAssignmentRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `listAssignment` query has no variables.
+### Return Type
+Recall that executing the `listAssignment` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `ListAssignmentData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface ListAssignmentData {
+ assignments: ({
+ id: UUIDString;
+ assignmentNumber?: string | null;
+ orderId: UUIDString;
+ workforceId: UUIDString;
+ vendorId: UUIDString;
+ role: string;
+ assignmentStatus: AssignmentStatus;
+ scheduledStart: TimestampString;
+ } & Assignment_Key)[];
+}
+```
+### Using `listAssignment`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, listAssignment } from '@dataconnect/generated';
+
+
+// Call the `listAssignment()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await listAssignment();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await listAssignment(dataConnect);
+
+console.log(data.assignments);
+
+// Or, you can use the `Promise` API.
+listAssignment().then((response) => {
+ const data = response.data;
+ console.log(data.assignments);
+});
+```
+
+### Using `listAssignment`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, listAssignmentRef } from '@dataconnect/generated';
+
+
+// Call the `listAssignmentRef()` function to get a reference to the query.
+const ref = listAssignmentRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = listAssignmentRef(dataConnect);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.assignments);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.assignments);
+});
+```
+
+## getAssignmentById
+You can execute the `getAssignmentById` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+getAssignmentById(vars: GetAssignmentByIdVariables): QueryPromise;
+
+interface GetAssignmentByIdRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars: GetAssignmentByIdVariables): QueryRef;
+}
+export const getAssignmentByIdRef: GetAssignmentByIdRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+getAssignmentById(dc: DataConnect, vars: GetAssignmentByIdVariables): QueryPromise;
+
+interface GetAssignmentByIdRef {
+ ...
+ (dc: DataConnect, vars: GetAssignmentByIdVariables): QueryRef;
+}
+export const getAssignmentByIdRef: GetAssignmentByIdRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the getAssignmentByIdRef:
+```typescript
+const name = getAssignmentByIdRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `getAssignmentById` query requires an argument of type `GetAssignmentByIdVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface GetAssignmentByIdVariables {
+ id: UUIDString;
+}
+```
+### Return Type
+Recall that executing the `getAssignmentById` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `GetAssignmentByIdData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface GetAssignmentByIdData {
+ assignment?: {
+ id: UUIDString;
+ assignmentNumber?: string | null;
+ orderId: UUIDString;
+ workforceId: UUIDString;
+ vendorId: UUIDString;
+ role: string;
+ assignmentStatus: AssignmentStatus;
+ scheduledStart: TimestampString;
+ } & Assignment_Key;
+}
+```
+### Using `getAssignmentById`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, getAssignmentById, GetAssignmentByIdVariables } from '@dataconnect/generated';
+
+// The `getAssignmentById` query requires an argument of type `GetAssignmentByIdVariables`:
+const getAssignmentByIdVars: GetAssignmentByIdVariables = {
+ id: ...,
+};
+
+// Call the `getAssignmentById()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await getAssignmentById(getAssignmentByIdVars);
+// Variables can be defined inline as well.
+const { data } = await getAssignmentById({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await getAssignmentById(dataConnect, getAssignmentByIdVars);
+
+console.log(data.assignment);
+
+// Or, you can use the `Promise` API.
+getAssignmentById(getAssignmentByIdVars).then((response) => {
+ const data = response.data;
+ console.log(data.assignment);
+});
+```
+
+### Using `getAssignmentById`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, getAssignmentByIdRef, GetAssignmentByIdVariables } from '@dataconnect/generated';
+
+// The `getAssignmentById` query requires an argument of type `GetAssignmentByIdVariables`:
+const getAssignmentByIdVars: GetAssignmentByIdVariables = {
+ id: ...,
+};
+
+// Call the `getAssignmentByIdRef()` function to get a reference to the query.
+const ref = getAssignmentByIdRef(getAssignmentByIdVars);
+// Variables can be defined inline as well.
+const ref = getAssignmentByIdRef({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = getAssignmentByIdRef(dataConnect, getAssignmentByIdVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.assignment);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.assignment);
+});
+```
+
+## filterAssignment
+You can execute the `filterAssignment` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+filterAssignment(vars?: FilterAssignmentVariables): QueryPromise;
+
+interface FilterAssignmentRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars?: FilterAssignmentVariables): QueryRef;
+}
+export const filterAssignmentRef: FilterAssignmentRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+filterAssignment(dc: DataConnect, vars?: FilterAssignmentVariables): QueryPromise;
+
+interface FilterAssignmentRef {
+ ...
+ (dc: DataConnect, vars?: FilterAssignmentVariables): QueryRef;
+}
+export const filterAssignmentRef: FilterAssignmentRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the filterAssignmentRef:
+```typescript
+const name = filterAssignmentRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `filterAssignment` query has an optional argument of type `FilterAssignmentVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface FilterAssignmentVariables {
+ assignmentNumber?: string | null;
+ orderId?: UUIDString | null;
+ workforceId?: UUIDString | null;
+ vendorId?: UUIDString | null;
+ assignmentStatus?: AssignmentStatus | null;
+}
+```
+### Return Type
+Recall that executing the `filterAssignment` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `FilterAssignmentData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface FilterAssignmentData {
+ assignments: ({
+ id: UUIDString;
+ assignmentNumber?: string | null;
+ orderId: UUIDString;
+ workforceId: UUIDString;
+ vendorId: UUIDString;
+ role: string;
+ assignmentStatus: AssignmentStatus;
+ scheduledStart: TimestampString;
+ } & Assignment_Key)[];
+}
+```
+### Using `filterAssignment`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, filterAssignment, FilterAssignmentVariables } from '@dataconnect/generated';
+
+// The `filterAssignment` query has an optional argument of type `FilterAssignmentVariables`:
+const filterAssignmentVars: FilterAssignmentVariables = {
+ assignmentNumber: ..., // optional
+ orderId: ..., // optional
+ workforceId: ..., // optional
+ vendorId: ..., // optional
+ assignmentStatus: ..., // optional
+};
+
+// Call the `filterAssignment()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await filterAssignment(filterAssignmentVars);
+// Variables can be defined inline as well.
+const { data } = await filterAssignment({ assignmentNumber: ..., orderId: ..., workforceId: ..., vendorId: ..., assignmentStatus: ..., });
+// Since all variables are optional for this query, you can omit the `FilterAssignmentVariables` argument.
+const { data } = await filterAssignment();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await filterAssignment(dataConnect, filterAssignmentVars);
+
+console.log(data.assignments);
+
+// Or, you can use the `Promise` API.
+filterAssignment(filterAssignmentVars).then((response) => {
+ const data = response.data;
+ console.log(data.assignments);
+});
+```
+
+### Using `filterAssignment`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, filterAssignmentRef, FilterAssignmentVariables } from '@dataconnect/generated';
+
+// The `filterAssignment` query has an optional argument of type `FilterAssignmentVariables`:
+const filterAssignmentVars: FilterAssignmentVariables = {
+ assignmentNumber: ..., // optional
+ orderId: ..., // optional
+ workforceId: ..., // optional
+ vendorId: ..., // optional
+ assignmentStatus: ..., // optional
+};
+
+// Call the `filterAssignmentRef()` function to get a reference to the query.
+const ref = filterAssignmentRef(filterAssignmentVars);
+// Variables can be defined inline as well.
+const ref = filterAssignmentRef({ assignmentNumber: ..., orderId: ..., workforceId: ..., vendorId: ..., assignmentStatus: ..., });
+// Since all variables are optional for this query, you can omit the `FilterAssignmentVariables` argument.
+const ref = filterAssignmentRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = filterAssignmentRef(dataConnect, filterAssignmentVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.assignments);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.assignments);
+});
+```
+
+## listEvents
+You can execute the `listEvents` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+listEvents(vars?: ListEventsVariables): QueryPromise;
+
+interface ListEventsRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars?: ListEventsVariables): QueryRef;
+}
+export const listEventsRef: ListEventsRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+listEvents(dc: DataConnect, vars?: ListEventsVariables): QueryPromise;
+
+interface ListEventsRef {
+ ...
+ (dc: DataConnect, vars?: ListEventsVariables): QueryRef;
+}
+export const listEventsRef: ListEventsRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the listEventsRef:
+```typescript
+const name = listEventsRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `listEvents` query has an optional argument of type `ListEventsVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface ListEventsVariables {
+ orderByDate?: OrderDirection | null;
+ orderByCreatedDate?: OrderDirection | null;
+ limit?: number | null;
+}
+```
+### Return Type
+Recall that executing the `listEvents` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `ListEventsData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface ListEventsData {
+ events: ({
+ id: UUIDString;
+ eventName: string;
+ status: EventStatus;
+ date: string;
+ isRapid?: boolean | null;
+ isRecurring?: boolean | null;
+ isMultiDay?: boolean | null;
+ recurrenceType?: RecurrenceType | null;
+ recurrenceStartDate?: TimestampString | null;
+ recurrenceEndDate?: TimestampString | null;
+ scatterDates?: unknown | null;
+ multiDayStartDate?: TimestampString | null;
+ multiDayEndDate?: TimestampString | null;
+ bufferTimeBefore?: number | null;
+ bufferTimeAfter?: number | null;
+ conflictDetectionEnabled?: boolean | null;
+ detectedConflicts?: unknown | null;
+ businessId: UUIDString;
+ businessName?: string | null;
+ vendorId?: string | null;
+ vendorName?: string | null;
+ hub?: string | null;
+ eventLocation?: string | null;
+ contractType?: ContractType | null;
+ poReference?: string | null;
+ shifts?: unknown | null;
+ addons?: unknown | null;
+ total?: number | null;
+ clientName?: string | null;
+ clientEmail?: string | null;
+ clientPhone?: string | null;
+ invoiceId?: UUIDString | null;
+ notes?: string | null;
+ requested?: number | null;
+ assignedStaff?: unknown | null;
+ orderType?: string | null;
+ department?: string | null;
+ createdBy?: string | null;
+ recurringStartDate?: string | null;
+ recurringEndDate?: string | null;
+ recurringDays?: unknown | null;
+ permanentStartDate?: string | null;
+ permanentDays?: unknown | null;
+ includeBackup?: boolean | null;
+ backupStaffCount?: number | null;
+ recurringTime?: string | null;
+ permanentTime?: string | null;
+ } & Event_Key)[];
+}
+```
+### Using `listEvents`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, listEvents, ListEventsVariables } from '@dataconnect/generated';
+
+// The `listEvents` query has an optional argument of type `ListEventsVariables`:
+const listEventsVars: ListEventsVariables = {
+ orderByDate: ..., // optional
+ orderByCreatedDate: ..., // optional
+ limit: ..., // optional
+};
+
+// Call the `listEvents()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await listEvents(listEventsVars);
+// Variables can be defined inline as well.
+const { data } = await listEvents({ orderByDate: ..., orderByCreatedDate: ..., limit: ..., });
+// Since all variables are optional for this query, you can omit the `ListEventsVariables` argument.
+const { data } = await listEvents();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await listEvents(dataConnect, listEventsVars);
+
+console.log(data.events);
+
+// Or, you can use the `Promise` API.
+listEvents(listEventsVars).then((response) => {
+ const data = response.data;
+ console.log(data.events);
+});
+```
+
+### Using `listEvents`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, listEventsRef, ListEventsVariables } from '@dataconnect/generated';
+
+// The `listEvents` query has an optional argument of type `ListEventsVariables`:
+const listEventsVars: ListEventsVariables = {
+ orderByDate: ..., // optional
+ orderByCreatedDate: ..., // optional
+ limit: ..., // optional
+};
+
+// Call the `listEventsRef()` function to get a reference to the query.
+const ref = listEventsRef(listEventsVars);
+// Variables can be defined inline as well.
+const ref = listEventsRef({ orderByDate: ..., orderByCreatedDate: ..., limit: ..., });
+// Since all variables are optional for this query, you can omit the `ListEventsVariables` argument.
+const ref = listEventsRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = listEventsRef(dataConnect, listEventsVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.events);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.events);
+});
+```
+
+## getEventById
+You can execute the `getEventById` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+getEventById(vars: GetEventByIdVariables): QueryPromise;
+
+interface GetEventByIdRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars: GetEventByIdVariables): QueryRef;
+}
+export const getEventByIdRef: GetEventByIdRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+getEventById(dc: DataConnect, vars: GetEventByIdVariables): QueryPromise;
+
+interface GetEventByIdRef {
+ ...
+ (dc: DataConnect, vars: GetEventByIdVariables): QueryRef;
+}
+export const getEventByIdRef: GetEventByIdRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the getEventByIdRef:
+```typescript
+const name = getEventByIdRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `getEventById` query requires an argument of type `GetEventByIdVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface GetEventByIdVariables {
+ id: UUIDString;
+}
+```
+### Return Type
+Recall that executing the `getEventById` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `GetEventByIdData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface GetEventByIdData {
+ event?: {
+ id: UUIDString;
+ eventName: string;
+ status: EventStatus;
+ date: string;
+ isRapid?: boolean | null;
+ isRecurring?: boolean | null;
+ isMultiDay?: boolean | null;
+ recurrenceType?: RecurrenceType | null;
+ recurrenceStartDate?: TimestampString | null;
+ recurrenceEndDate?: TimestampString | null;
+ scatterDates?: unknown | null;
+ multiDayStartDate?: TimestampString | null;
+ multiDayEndDate?: TimestampString | null;
+ bufferTimeBefore?: number | null;
+ bufferTimeAfter?: number | null;
+ conflictDetectionEnabled?: boolean | null;
+ detectedConflicts?: unknown | null;
+ businessId: UUIDString;
+ businessName?: string | null;
+ vendorId?: string | null;
+ vendorName?: string | null;
+ hub?: string | null;
+ eventLocation?: string | null;
+ contractType?: ContractType | null;
+ poReference?: string | null;
+ shifts?: unknown | null;
+ addons?: unknown | null;
+ total?: number | null;
+ clientName?: string | null;
+ clientEmail?: string | null;
+ clientPhone?: string | null;
+ invoiceId?: UUIDString | null;
+ notes?: string | null;
+ requested?: number | null;
+ orderType?: string | null;
+ department?: string | null;
+ assignedStaff?: unknown | null;
+ recurringStartDate?: string | null;
+ recurringEndDate?: string | null;
+ recurringDays?: unknown | null;
+ permanentStartDate?: string | null;
+ permanentDays?: unknown | null;
+ includeBackup?: boolean | null;
+ backupStaffCount?: number | null;
+ recurringTime?: string | null;
+ permanentTime?: string | null;
+ } & Event_Key;
+}
+```
+### Using `getEventById`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, getEventById, GetEventByIdVariables } from '@dataconnect/generated';
+
+// The `getEventById` query requires an argument of type `GetEventByIdVariables`:
+const getEventByIdVars: GetEventByIdVariables = {
+ id: ...,
+};
+
+// Call the `getEventById()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await getEventById(getEventByIdVars);
+// Variables can be defined inline as well.
+const { data } = await getEventById({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await getEventById(dataConnect, getEventByIdVars);
+
+console.log(data.event);
+
+// Or, you can use the `Promise` API.
+getEventById(getEventByIdVars).then((response) => {
+ const data = response.data;
+ console.log(data.event);
+});
+```
+
+### Using `getEventById`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, getEventByIdRef, GetEventByIdVariables } from '@dataconnect/generated';
+
+// The `getEventById` query requires an argument of type `GetEventByIdVariables`:
+const getEventByIdVars: GetEventByIdVariables = {
+ id: ...,
+};
+
+// Call the `getEventByIdRef()` function to get a reference to the query.
+const ref = getEventByIdRef(getEventByIdVars);
+// Variables can be defined inline as well.
+const ref = getEventByIdRef({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = getEventByIdRef(dataConnect, getEventByIdVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.event);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.event);
+});
+```
+
+## filterEvents
+You can execute the `filterEvents` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+filterEvents(vars?: FilterEventsVariables): QueryPromise;
+
+interface FilterEventsRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars?: FilterEventsVariables): QueryRef;
+}
+export const filterEventsRef: FilterEventsRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+filterEvents(dc: DataConnect, vars?: FilterEventsVariables): QueryPromise;
+
+interface FilterEventsRef {
+ ...
+ (dc: DataConnect, vars?: FilterEventsVariables): QueryRef;
+}
+export const filterEventsRef: FilterEventsRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the filterEventsRef:
+```typescript
+const name = filterEventsRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `filterEvents` query has an optional argument of type `FilterEventsVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface FilterEventsVariables {
+ status?: EventStatus | null;
+ businessId?: UUIDString | null;
+ vendorId?: string | null;
+ isRecurring?: boolean | null;
+ isRapid?: boolean | null;
+ isMultiDay?: boolean | null;
+ recurrenceType?: RecurrenceType | null;
+ date?: string | null;
+ hub?: string | null;
+ eventLocation?: string | null;
+ contractType?: ContractType | null;
+ clientEmail?: string | null;
+}
+```
+### Return Type
+Recall that executing the `filterEvents` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `FilterEventsData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface FilterEventsData {
+ events: ({
+ id: UUIDString;
+ eventName: string;
+ status: EventStatus;
+ date: string;
+ isRapid?: boolean | null;
+ isRecurring?: boolean | null;
+ isMultiDay?: boolean | null;
+ recurrenceType?: RecurrenceType | null;
+ recurrenceStartDate?: TimestampString | null;
+ recurrenceEndDate?: TimestampString | null;
+ scatterDates?: unknown | null;
+ multiDayStartDate?: TimestampString | null;
+ multiDayEndDate?: TimestampString | null;
+ bufferTimeBefore?: number | null;
+ bufferTimeAfter?: number | null;
+ conflictDetectionEnabled?: boolean | null;
+ detectedConflicts?: unknown | null;
+ businessId: UUIDString;
+ businessName?: string | null;
+ vendorId?: string | null;
+ vendorName?: string | null;
+ hub?: string | null;
+ eventLocation?: string | null;
+ contractType?: ContractType | null;
+ poReference?: string | null;
+ shifts?: unknown | null;
+ addons?: unknown | null;
+ total?: number | null;
+ clientName?: string | null;
+ clientEmail?: string | null;
+ clientPhone?: string | null;
+ invoiceId?: UUIDString | null;
+ notes?: string | null;
+ requested?: number | null;
+ assignedStaff?: unknown | null;
+ orderType?: string | null;
+ department?: string | null;
+ createdBy?: string | null;
+ recurringStartDate?: string | null;
+ recurringEndDate?: string | null;
+ recurringDays?: unknown | null;
+ permanentStartDate?: string | null;
+ permanentDays?: unknown | null;
+ includeBackup?: boolean | null;
+ backupStaffCount?: number | null;
+ recurringTime?: string | null;
+ permanentTime?: string | null;
+ } & Event_Key)[];
+}
+```
+### Using `filterEvents`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, filterEvents, FilterEventsVariables } from '@dataconnect/generated';
+
+// The `filterEvents` query has an optional argument of type `FilterEventsVariables`:
+const filterEventsVars: FilterEventsVariables = {
+ status: ..., // optional
+ businessId: ..., // optional
+ vendorId: ..., // optional
+ isRecurring: ..., // optional
+ isRapid: ..., // optional
+ isMultiDay: ..., // optional
+ recurrenceType: ..., // optional
+ date: ..., // optional
+ hub: ..., // optional
+ eventLocation: ..., // optional
+ contractType: ..., // optional
+ clientEmail: ..., // optional
+};
+
+// Call the `filterEvents()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await filterEvents(filterEventsVars);
+// Variables can be defined inline as well.
+const { data } = await filterEvents({ status: ..., businessId: ..., vendorId: ..., isRecurring: ..., isRapid: ..., isMultiDay: ..., recurrenceType: ..., date: ..., hub: ..., eventLocation: ..., contractType: ..., clientEmail: ..., });
+// Since all variables are optional for this query, you can omit the `FilterEventsVariables` argument.
+const { data } = await filterEvents();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await filterEvents(dataConnect, filterEventsVars);
+
+console.log(data.events);
+
+// Or, you can use the `Promise` API.
+filterEvents(filterEventsVars).then((response) => {
+ const data = response.data;
+ console.log(data.events);
+});
+```
+
+### Using `filterEvents`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, filterEventsRef, FilterEventsVariables } from '@dataconnect/generated';
+
+// The `filterEvents` query has an optional argument of type `FilterEventsVariables`:
+const filterEventsVars: FilterEventsVariables = {
+ status: ..., // optional
+ businessId: ..., // optional
+ vendorId: ..., // optional
+ isRecurring: ..., // optional
+ isRapid: ..., // optional
+ isMultiDay: ..., // optional
+ recurrenceType: ..., // optional
+ date: ..., // optional
+ hub: ..., // optional
+ eventLocation: ..., // optional
+ contractType: ..., // optional
+ clientEmail: ..., // optional
+};
+
+// Call the `filterEventsRef()` function to get a reference to the query.
+const ref = filterEventsRef(filterEventsVars);
+// Variables can be defined inline as well.
+const ref = filterEventsRef({ status: ..., businessId: ..., vendorId: ..., isRecurring: ..., isRapid: ..., isMultiDay: ..., recurrenceType: ..., date: ..., hub: ..., eventLocation: ..., contractType: ..., clientEmail: ..., });
+// Since all variables are optional for this query, you can omit the `FilterEventsVariables` argument.
+const ref = filterEventsRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = filterEventsRef(dataConnect, filterEventsVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.events);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.events);
+});
+```
+
+## listMessage
+You can execute the `listMessage` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+listMessage(): QueryPromise;
+
+interface ListMessageRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (): QueryRef;
+}
+export const listMessageRef: ListMessageRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+listMessage(dc: DataConnect): QueryPromise;
+
+interface ListMessageRef {
+ ...
+ (dc: DataConnect): QueryRef;
+}
+export const listMessageRef: ListMessageRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the listMessageRef:
+```typescript
+const name = listMessageRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `listMessage` query has no variables.
+### Return Type
+Recall that executing the `listMessage` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `ListMessageData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface ListMessageData {
+ messages: ({
+ id: UUIDString;
+ conversationId: UUIDString;
+ senderName: string;
+ content: string;
+ readBy?: string | null;
+ } & Message_Key)[];
+}
+```
+### Using `listMessage`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, listMessage } from '@dataconnect/generated';
+
+
+// Call the `listMessage()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await listMessage();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await listMessage(dataConnect);
+
+console.log(data.messages);
+
+// Or, you can use the `Promise` API.
+listMessage().then((response) => {
+ const data = response.data;
+ console.log(data.messages);
+});
+```
+
+### Using `listMessage`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, listMessageRef } from '@dataconnect/generated';
+
+
+// Call the `listMessageRef()` function to get a reference to the query.
+const ref = listMessageRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = listMessageRef(dataConnect);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.messages);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.messages);
+});
+```
+
+## getMessageById
+You can execute the `getMessageById` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+getMessageById(vars: GetMessageByIdVariables): QueryPromise;
+
+interface GetMessageByIdRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars: GetMessageByIdVariables): QueryRef;
+}
+export const getMessageByIdRef: GetMessageByIdRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+getMessageById(dc: DataConnect, vars: GetMessageByIdVariables): QueryPromise;
+
+interface GetMessageByIdRef {
+ ...
+ (dc: DataConnect, vars: GetMessageByIdVariables): QueryRef;
+}
+export const getMessageByIdRef: GetMessageByIdRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the getMessageByIdRef:
+```typescript
+const name = getMessageByIdRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `getMessageById` query requires an argument of type `GetMessageByIdVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface GetMessageByIdVariables {
+ id: UUIDString;
+}
+```
+### Return Type
+Recall that executing the `getMessageById` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `GetMessageByIdData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface GetMessageByIdData {
+ message?: {
+ id: UUIDString;
+ conversationId: UUIDString;
+ senderName: string;
+ content: string;
+ readBy?: string | null;
+ } & Message_Key;
+}
+```
+### Using `getMessageById`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, getMessageById, GetMessageByIdVariables } from '@dataconnect/generated';
+
+// The `getMessageById` query requires an argument of type `GetMessageByIdVariables`:
+const getMessageByIdVars: GetMessageByIdVariables = {
+ id: ...,
+};
+
+// Call the `getMessageById()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await getMessageById(getMessageByIdVars);
+// Variables can be defined inline as well.
+const { data } = await getMessageById({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await getMessageById(dataConnect, getMessageByIdVars);
+
+console.log(data.message);
+
+// Or, you can use the `Promise` API.
+getMessageById(getMessageByIdVars).then((response) => {
+ const data = response.data;
+ console.log(data.message);
+});
+```
+
+### Using `getMessageById`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, getMessageByIdRef, GetMessageByIdVariables } from '@dataconnect/generated';
+
+// The `getMessageById` query requires an argument of type `GetMessageByIdVariables`:
+const getMessageByIdVars: GetMessageByIdVariables = {
+ id: ...,
+};
+
+// Call the `getMessageByIdRef()` function to get a reference to the query.
+const ref = getMessageByIdRef(getMessageByIdVars);
+// Variables can be defined inline as well.
+const ref = getMessageByIdRef({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = getMessageByIdRef(dataConnect, getMessageByIdVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.message);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.message);
+});
+```
+
+## filterMessage
+You can execute the `filterMessage` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+filterMessage(vars?: FilterMessageVariables): QueryPromise;
+
+interface FilterMessageRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars?: FilterMessageVariables): QueryRef;
+}
+export const filterMessageRef: FilterMessageRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+filterMessage(dc: DataConnect, vars?: FilterMessageVariables): QueryPromise;
+
+interface FilterMessageRef {
+ ...
+ (dc: DataConnect, vars?: FilterMessageVariables): QueryRef;
+}
+export const filterMessageRef: FilterMessageRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the filterMessageRef:
+```typescript
+const name = filterMessageRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `filterMessage` query has an optional argument of type `FilterMessageVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface FilterMessageVariables {
+ conversationId?: UUIDString | null;
+ senderName?: string | null;
+}
+```
+### Return Type
+Recall that executing the `filterMessage` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `FilterMessageData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface FilterMessageData {
+ messages: ({
+ id: UUIDString;
+ conversationId: UUIDString;
+ senderName: string;
+ content: string;
+ readBy?: string | null;
+ } & Message_Key)[];
+}
+```
+### Using `filterMessage`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, filterMessage, FilterMessageVariables } from '@dataconnect/generated';
+
+// The `filterMessage` query has an optional argument of type `FilterMessageVariables`:
+const filterMessageVars: FilterMessageVariables = {
+ conversationId: ..., // optional
+ senderName: ..., // optional
+};
+
+// Call the `filterMessage()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await filterMessage(filterMessageVars);
+// Variables can be defined inline as well.
+const { data } = await filterMessage({ conversationId: ..., senderName: ..., });
+// Since all variables are optional for this query, you can omit the `FilterMessageVariables` argument.
+const { data } = await filterMessage();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await filterMessage(dataConnect, filterMessageVars);
+
+console.log(data.messages);
+
+// Or, you can use the `Promise` API.
+filterMessage(filterMessageVars).then((response) => {
+ const data = response.data;
+ console.log(data.messages);
+});
+```
+
+### Using `filterMessage`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, filterMessageRef, FilterMessageVariables } from '@dataconnect/generated';
+
+// The `filterMessage` query has an optional argument of type `FilterMessageVariables`:
+const filterMessageVars: FilterMessageVariables = {
+ conversationId: ..., // optional
+ senderName: ..., // optional
+};
+
+// Call the `filterMessageRef()` function to get a reference to the query.
+const ref = filterMessageRef(filterMessageVars);
+// Variables can be defined inline as well.
+const ref = filterMessageRef({ conversationId: ..., senderName: ..., });
+// Since all variables are optional for this query, you can omit the `FilterMessageVariables` argument.
+const ref = filterMessageRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = filterMessageRef(dataConnect, filterMessageVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.messages);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.messages);
+});
+```
+
+## listSector
+You can execute the `listSector` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+listSector(): QueryPromise;
+
+interface ListSectorRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (): QueryRef;
+}
+export const listSectorRef: ListSectorRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+listSector(dc: DataConnect): QueryPromise;
+
+interface ListSectorRef {
+ ...
+ (dc: DataConnect): QueryRef;
+}
+export const listSectorRef: ListSectorRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the listSectorRef:
+```typescript
+const name = listSectorRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `listSector` query has no variables.
+### Return Type
+Recall that executing the `listSector` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `ListSectorData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface ListSectorData {
+ sectors: ({
+ id: UUIDString;
+ sectorNumber: string;
+ sectorName: string;
+ sectorType?: SectorType | null;
+ } & Sector_Key)[];
+}
+```
+### Using `listSector`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, listSector } from '@dataconnect/generated';
+
+
+// Call the `listSector()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await listSector();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await listSector(dataConnect);
+
+console.log(data.sectors);
+
+// Or, you can use the `Promise` API.
+listSector().then((response) => {
+ const data = response.data;
+ console.log(data.sectors);
+});
+```
+
+### Using `listSector`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, listSectorRef } from '@dataconnect/generated';
+
+
+// Call the `listSectorRef()` function to get a reference to the query.
+const ref = listSectorRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = listSectorRef(dataConnect);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.sectors);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.sectors);
+});
+```
+
+## getSectorById
+You can execute the `getSectorById` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+getSectorById(vars: GetSectorByIdVariables): QueryPromise;
+
+interface GetSectorByIdRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars: GetSectorByIdVariables): QueryRef;
+}
+export const getSectorByIdRef: GetSectorByIdRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+getSectorById(dc: DataConnect, vars: GetSectorByIdVariables): QueryPromise;
+
+interface GetSectorByIdRef {
+ ...
+ (dc: DataConnect, vars: GetSectorByIdVariables): QueryRef;
+}
+export const getSectorByIdRef: GetSectorByIdRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the getSectorByIdRef:
+```typescript
+const name = getSectorByIdRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `getSectorById` query requires an argument of type `GetSectorByIdVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface GetSectorByIdVariables {
+ id: UUIDString;
+}
+```
+### Return Type
+Recall that executing the `getSectorById` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `GetSectorByIdData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface GetSectorByIdData {
+ sector?: {
+ id: UUIDString;
+ sectorNumber: string;
+ sectorName: string;
+ sectorType?: SectorType | null;
+ } & Sector_Key;
+}
+```
+### Using `getSectorById`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, getSectorById, GetSectorByIdVariables } from '@dataconnect/generated';
+
+// The `getSectorById` query requires an argument of type `GetSectorByIdVariables`:
+const getSectorByIdVars: GetSectorByIdVariables = {
+ id: ...,
+};
+
+// Call the `getSectorById()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await getSectorById(getSectorByIdVars);
+// Variables can be defined inline as well.
+const { data } = await getSectorById({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await getSectorById(dataConnect, getSectorByIdVars);
+
+console.log(data.sector);
+
+// Or, you can use the `Promise` API.
+getSectorById(getSectorByIdVars).then((response) => {
+ const data = response.data;
+ console.log(data.sector);
+});
+```
+
+### Using `getSectorById`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, getSectorByIdRef, GetSectorByIdVariables } from '@dataconnect/generated';
+
+// The `getSectorById` query requires an argument of type `GetSectorByIdVariables`:
+const getSectorByIdVars: GetSectorByIdVariables = {
+ id: ...,
+};
+
+// Call the `getSectorByIdRef()` function to get a reference to the query.
+const ref = getSectorByIdRef(getSectorByIdVars);
+// Variables can be defined inline as well.
+const ref = getSectorByIdRef({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = getSectorByIdRef(dataConnect, getSectorByIdVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.sector);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.sector);
+});
+```
+
+## filterSector
+You can execute the `filterSector` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+filterSector(vars?: FilterSectorVariables): QueryPromise;
+
+interface FilterSectorRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars?: FilterSectorVariables): QueryRef;
+}
+export const filterSectorRef: FilterSectorRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+filterSector(dc: DataConnect, vars?: FilterSectorVariables): QueryPromise;
+
+interface FilterSectorRef {
+ ...
+ (dc: DataConnect, vars?: FilterSectorVariables): QueryRef;
+}
+export const filterSectorRef: FilterSectorRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the filterSectorRef:
+```typescript
+const name = filterSectorRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `filterSector` query has an optional argument of type `FilterSectorVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface FilterSectorVariables {
+ sectorNumber?: string | null;
+ sectorName?: string | null;
+ sectorType?: SectorType | null;
+}
+```
+### Return Type
+Recall that executing the `filterSector` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `FilterSectorData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface FilterSectorData {
+ sectors: ({
+ id: UUIDString;
+ sectorNumber: string;
+ sectorName: string;
+ sectorType?: SectorType | null;
+ } & Sector_Key)[];
+}
+```
+### Using `filterSector`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, filterSector, FilterSectorVariables } from '@dataconnect/generated';
+
+// The `filterSector` query has an optional argument of type `FilterSectorVariables`:
+const filterSectorVars: FilterSectorVariables = {
+ sectorNumber: ..., // optional
+ sectorName: ..., // optional
+ sectorType: ..., // optional
+};
+
+// Call the `filterSector()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await filterSector(filterSectorVars);
+// Variables can be defined inline as well.
+const { data } = await filterSector({ sectorNumber: ..., sectorName: ..., sectorType: ..., });
+// Since all variables are optional for this query, you can omit the `FilterSectorVariables` argument.
+const { data } = await filterSector();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await filterSector(dataConnect, filterSectorVars);
+
+console.log(data.sectors);
+
+// Or, you can use the `Promise` API.
+filterSector(filterSectorVars).then((response) => {
+ const data = response.data;
+ console.log(data.sectors);
+});
+```
+
+### Using `filterSector`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, filterSectorRef, FilterSectorVariables } from '@dataconnect/generated';
+
+// The `filterSector` query has an optional argument of type `FilterSectorVariables`:
+const filterSectorVars: FilterSectorVariables = {
+ sectorNumber: ..., // optional
+ sectorName: ..., // optional
+ sectorType: ..., // optional
+};
+
+// Call the `filterSectorRef()` function to get a reference to the query.
+const ref = filterSectorRef(filterSectorVars);
+// Variables can be defined inline as well.
+const ref = filterSectorRef({ sectorNumber: ..., sectorName: ..., sectorType: ..., });
+// Since all variables are optional for this query, you can omit the `FilterSectorVariables` argument.
+const ref = filterSectorRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = filterSectorRef(dataConnect, filterSectorVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.sectors);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.sectors);
+});
+```
+
+## listStaff
+You can execute the `listStaff` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+listStaff(): QueryPromise;
+
+interface ListStaffRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (): QueryRef;
+}
+export const listStaffRef: ListStaffRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+listStaff(dc: DataConnect): QueryPromise;
+
+interface ListStaffRef {
+ ...
+ (dc: DataConnect): QueryRef;
+}
+export const listStaffRef: ListStaffRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the listStaffRef:
+```typescript
+const name = listStaffRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `listStaff` query has no variables.
+### Return Type
+Recall that executing the `listStaff` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `ListStaffData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface ListStaffData {
+ staffs: ({
+ id: UUIDString;
+ employeeName: string;
+ vendorId?: string | null;
+ vendorName?: string | null;
+ manager?: string | null;
+ contactNumber?: string | null;
+ phone?: string | null;
+ email?: string | null;
+ department?: StaffDepartment | null;
+ hubLocation?: string | null;
+ eventLocation?: string | null;
+ address?: string | null;
+ city?: string | null;
+ track?: string | null;
+ position?: string | null;
+ position2?: string | null;
+ initial?: string | null;
+ profileType?: ProfileType | null;
+ employmentType?: EmploymentType | null;
+ english?: EnglishLevel | null;
+ englishRequired?: boolean | null;
+ rate?: number | null;
+ rating?: number | null;
+ reliabilityScore?: number | null;
+ backgroundCheckStatus?: BackgroundCheckStatus | null;
+ notes?: string | null;
+ accountingComments?: string | null;
+ shiftCoveragePercentage?: number | null;
+ cancellationCount?: number | null;
+ noShowCount?: number | null;
+ totalShifts?: number | null;
+ invoiced?: boolean | null;
+ checkIn?: string | null;
+ scheduleDays?: string | null;
+ replacedBy?: string | null;
+ action?: string | null;
+ ro?: string | null;
+ mon?: string | null;
+ } & Staff_Key)[];
+}
+```
+### Using `listStaff`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, listStaff } from '@dataconnect/generated';
+
+
+// Call the `listStaff()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await listStaff();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await listStaff(dataConnect);
+
+console.log(data.staffs);
+
+// Or, you can use the `Promise` API.
+listStaff().then((response) => {
+ const data = response.data;
+ console.log(data.staffs);
+});
+```
+
+### Using `listStaff`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, listStaffRef } from '@dataconnect/generated';
+
+
+// Call the `listStaffRef()` function to get a reference to the query.
+const ref = listStaffRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = listStaffRef(dataConnect);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.staffs);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.staffs);
+});
+```
+
+## getStaffById
+You can execute the `getStaffById` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+getStaffById(vars: GetStaffByIdVariables): QueryPromise;
+
+interface GetStaffByIdRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars: GetStaffByIdVariables): QueryRef;
+}
+export const getStaffByIdRef: GetStaffByIdRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+getStaffById(dc: DataConnect, vars: GetStaffByIdVariables): QueryPromise;
+
+interface GetStaffByIdRef {
+ ...
+ (dc: DataConnect, vars: GetStaffByIdVariables): QueryRef;
+}
+export const getStaffByIdRef: GetStaffByIdRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the getStaffByIdRef:
+```typescript
+const name = getStaffByIdRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `getStaffById` query requires an argument of type `GetStaffByIdVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface GetStaffByIdVariables {
+ id: UUIDString;
+}
+```
+### Return Type
+Recall that executing the `getStaffById` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `GetStaffByIdData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface GetStaffByIdData {
+ staff?: {
+ id: UUIDString;
+ employeeName: string;
+ vendorId?: string | null;
+ vendorName?: string | null;
+ manager?: string | null;
+ contactNumber?: string | null;
+ phone?: string | null;
+ email?: string | null;
+ department?: StaffDepartment | null;
+ hubLocation?: string | null;
+ eventLocation?: string | null;
+ address?: string | null;
+ city?: string | null;
+ track?: string | null;
+ position?: string | null;
+ position2?: string | null;
+ initial?: string | null;
+ profileType?: ProfileType | null;
+ employmentType?: EmploymentType | null;
+ english?: EnglishLevel | null;
+ rate?: number | null;
+ rating?: number | null;
+ reliabilityScore?: number | null;
+ backgroundCheckStatus?: BackgroundCheckStatus | null;
+ notes?: string | null;
+ accountingComments?: string | null;
+ shiftCoveragePercentage?: number | null;
+ cancellationCount?: number | null;
+ noShowCount?: number | null;
+ totalShifts?: number | null;
+ invoiced?: boolean | null;
+ englishRequired?: boolean | null;
+ checkIn?: string | null;
+ scheduleDays?: string | null;
+ replacedBy?: string | null;
+ action?: string | null;
+ ro?: string | null;
+ mon?: string | null;
+ } & Staff_Key;
+}
+```
+### Using `getStaffById`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, getStaffById, GetStaffByIdVariables } from '@dataconnect/generated';
+
+// The `getStaffById` query requires an argument of type `GetStaffByIdVariables`:
+const getStaffByIdVars: GetStaffByIdVariables = {
+ id: ...,
+};
+
+// Call the `getStaffById()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await getStaffById(getStaffByIdVars);
+// Variables can be defined inline as well.
+const { data } = await getStaffById({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await getStaffById(dataConnect, getStaffByIdVars);
+
+console.log(data.staff);
+
+// Or, you can use the `Promise` API.
+getStaffById(getStaffByIdVars).then((response) => {
+ const data = response.data;
+ console.log(data.staff);
+});
+```
+
+### Using `getStaffById`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, getStaffByIdRef, GetStaffByIdVariables } from '@dataconnect/generated';
+
+// The `getStaffById` query requires an argument of type `GetStaffByIdVariables`:
+const getStaffByIdVars: GetStaffByIdVariables = {
+ id: ...,
+};
+
+// Call the `getStaffByIdRef()` function to get a reference to the query.
+const ref = getStaffByIdRef(getStaffByIdVars);
+// Variables can be defined inline as well.
+const ref = getStaffByIdRef({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = getStaffByIdRef(dataConnect, getStaffByIdVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.staff);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.staff);
+});
+```
+
+## filterStaff
+You can execute the `filterStaff` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+filterStaff(vars?: FilterStaffVariables): QueryPromise;
+
+interface FilterStaffRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars?: FilterStaffVariables): QueryRef;
+}
+export const filterStaffRef: FilterStaffRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+filterStaff(dc: DataConnect, vars?: FilterStaffVariables): QueryPromise;
+
+interface FilterStaffRef {
+ ...
+ (dc: DataConnect, vars?: FilterStaffVariables): QueryRef;
+}
+export const filterStaffRef: FilterStaffRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the filterStaffRef:
+```typescript
+const name = filterStaffRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `filterStaff` query has an optional argument of type `FilterStaffVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface FilterStaffVariables {
+ employeeName?: string | null;
+ vendorId?: string | null;
+ department?: StaffDepartment | null;
+ employmentType?: EmploymentType | null;
+ english?: EnglishLevel | null;
+ backgroundCheckStatus?: BackgroundCheckStatus | null;
+}
+```
+### Return Type
+Recall that executing the `filterStaff` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `FilterStaffData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface FilterStaffData {
+ staffs: ({
+ id: UUIDString;
+ employeeName: string;
+ vendorId?: string | null;
+ vendorName?: string | null;
+ department?: StaffDepartment | null;
+ hubLocation?: string | null;
+ eventLocation?: string | null;
+ position?: string | null;
+ position2?: string | null;
+ employmentType?: EmploymentType | null;
+ english?: EnglishLevel | null;
+ rate?: number | null;
+ rating?: number | null;
+ reliabilityScore?: number | null;
+ backgroundCheckStatus?: BackgroundCheckStatus | null;
+ notes?: string | null;
+ invoiced?: boolean | null;
+ } & Staff_Key)[];
+}
+```
+### Using `filterStaff`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, filterStaff, FilterStaffVariables } from '@dataconnect/generated';
+
+// The `filterStaff` query has an optional argument of type `FilterStaffVariables`:
+const filterStaffVars: FilterStaffVariables = {
+ employeeName: ..., // optional
+ vendorId: ..., // optional
+ department: ..., // optional
+ employmentType: ..., // optional
+ english: ..., // optional
+ backgroundCheckStatus: ..., // optional
+};
+
+// Call the `filterStaff()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await filterStaff(filterStaffVars);
+// Variables can be defined inline as well.
+const { data } = await filterStaff({ employeeName: ..., vendorId: ..., department: ..., employmentType: ..., english: ..., backgroundCheckStatus: ..., });
+// Since all variables are optional for this query, you can omit the `FilterStaffVariables` argument.
+const { data } = await filterStaff();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await filterStaff(dataConnect, filterStaffVars);
+
+console.log(data.staffs);
+
+// Or, you can use the `Promise` API.
+filterStaff(filterStaffVars).then((response) => {
+ const data = response.data;
+ console.log(data.staffs);
+});
+```
+
+### Using `filterStaff`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, filterStaffRef, FilterStaffVariables } from '@dataconnect/generated';
+
+// The `filterStaff` query has an optional argument of type `FilterStaffVariables`:
+const filterStaffVars: FilterStaffVariables = {
+ employeeName: ..., // optional
+ vendorId: ..., // optional
+ department: ..., // optional
+ employmentType: ..., // optional
+ english: ..., // optional
+ backgroundCheckStatus: ..., // optional
+};
+
+// Call the `filterStaffRef()` function to get a reference to the query.
+const ref = filterStaffRef(filterStaffVars);
+// Variables can be defined inline as well.
+const ref = filterStaffRef({ employeeName: ..., vendorId: ..., department: ..., employmentType: ..., english: ..., backgroundCheckStatus: ..., });
+// Since all variables are optional for this query, you can omit the `FilterStaffVariables` argument.
+const ref = filterStaffRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = filterStaffRef(dataConnect, filterStaffVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.staffs);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.staffs);
+});
+```
+
+## listOrder
+You can execute the `listOrder` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+listOrder(): QueryPromise;
+
+interface ListOrderRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (): QueryRef;
+}
+export const listOrderRef: ListOrderRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+listOrder(dc: DataConnect): QueryPromise;
+
+interface ListOrderRef {
+ ...
+ (dc: DataConnect): QueryRef;
+}
+export const listOrderRef: ListOrderRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the listOrderRef:
+```typescript
+const name = listOrderRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `listOrder` query has no variables.
+### Return Type
+Recall that executing the `listOrder` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `ListOrderData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface ListOrderData {
+ orders: ({
+ id: UUIDString;
+ orderNumber: string;
+ partnerId: UUIDString;
+ orderType?: OrderType | null;
+ orderStatus?: OrderStatus | null;
+ } & Order_Key)[];
+}
+```
+### Using `listOrder`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, listOrder } from '@dataconnect/generated';
+
+
+// Call the `listOrder()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await listOrder();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await listOrder(dataConnect);
+
+console.log(data.orders);
+
+// Or, you can use the `Promise` API.
+listOrder().then((response) => {
+ const data = response.data;
+ console.log(data.orders);
+});
+```
+
+### Using `listOrder`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, listOrderRef } from '@dataconnect/generated';
+
+
+// Call the `listOrderRef()` function to get a reference to the query.
+const ref = listOrderRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = listOrderRef(dataConnect);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.orders);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.orders);
+});
+```
+
+## getOrderById
+You can execute the `getOrderById` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+getOrderById(vars: GetOrderByIdVariables): QueryPromise;
+
+interface GetOrderByIdRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars: GetOrderByIdVariables): QueryRef;
+}
+export const getOrderByIdRef: GetOrderByIdRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+getOrderById(dc: DataConnect, vars: GetOrderByIdVariables): QueryPromise;
+
+interface GetOrderByIdRef {
+ ...
+ (dc: DataConnect, vars: GetOrderByIdVariables): QueryRef;
+}
+export const getOrderByIdRef: GetOrderByIdRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the getOrderByIdRef:
+```typescript
+const name = getOrderByIdRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `getOrderById` query requires an argument of type `GetOrderByIdVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface GetOrderByIdVariables {
+ id: UUIDString;
+}
+```
+### Return Type
+Recall that executing the `getOrderById` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `GetOrderByIdData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface GetOrderByIdData {
+ order?: {
+ id: UUIDString;
+ orderNumber: string;
+ partnerId: UUIDString;
+ orderType?: OrderType | null;
+ orderStatus?: OrderStatus | null;
+ } & Order_Key;
+}
+```
+### Using `getOrderById`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, getOrderById, GetOrderByIdVariables } from '@dataconnect/generated';
+
+// The `getOrderById` query requires an argument of type `GetOrderByIdVariables`:
+const getOrderByIdVars: GetOrderByIdVariables = {
+ id: ...,
+};
+
+// Call the `getOrderById()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await getOrderById(getOrderByIdVars);
+// Variables can be defined inline as well.
+const { data } = await getOrderById({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await getOrderById(dataConnect, getOrderByIdVars);
+
+console.log(data.order);
+
+// Or, you can use the `Promise` API.
+getOrderById(getOrderByIdVars).then((response) => {
+ const data = response.data;
+ console.log(data.order);
+});
+```
+
+### Using `getOrderById`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, getOrderByIdRef, GetOrderByIdVariables } from '@dataconnect/generated';
+
+// The `getOrderById` query requires an argument of type `GetOrderByIdVariables`:
+const getOrderByIdVars: GetOrderByIdVariables = {
+ id: ...,
+};
+
+// Call the `getOrderByIdRef()` function to get a reference to the query.
+const ref = getOrderByIdRef(getOrderByIdVars);
+// Variables can be defined inline as well.
+const ref = getOrderByIdRef({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = getOrderByIdRef(dataConnect, getOrderByIdVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.order);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.order);
+});
+```
+
+## filterOrder
+You can execute the `filterOrder` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+filterOrder(vars?: FilterOrderVariables): QueryPromise;
+
+interface FilterOrderRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars?: FilterOrderVariables): QueryRef;
+}
+export const filterOrderRef: FilterOrderRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+filterOrder(dc: DataConnect, vars?: FilterOrderVariables): QueryPromise;
+
+interface FilterOrderRef {
+ ...
+ (dc: DataConnect, vars?: FilterOrderVariables): QueryRef;
+}
+export const filterOrderRef: FilterOrderRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the filterOrderRef:
+```typescript
+const name = filterOrderRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `filterOrder` query has an optional argument of type `FilterOrderVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface FilterOrderVariables {
+ orderNumber?: string | null;
+ partnerId?: UUIDString | null;
+ orderType?: OrderType | null;
+ orderStatus?: OrderStatus | null;
+}
+```
+### Return Type
+Recall that executing the `filterOrder` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `FilterOrderData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface FilterOrderData {
+ orders: ({
+ id: UUIDString;
+ orderNumber: string;
+ partnerId: UUIDString;
+ orderType?: OrderType | null;
+ orderStatus?: OrderStatus | null;
+ } & Order_Key)[];
+}
+```
+### Using `filterOrder`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, filterOrder, FilterOrderVariables } from '@dataconnect/generated';
+
+// The `filterOrder` query has an optional argument of type `FilterOrderVariables`:
+const filterOrderVars: FilterOrderVariables = {
+ orderNumber: ..., // optional
+ partnerId: ..., // optional
+ orderType: ..., // optional
+ orderStatus: ..., // optional
+};
+
+// Call the `filterOrder()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await filterOrder(filterOrderVars);
+// Variables can be defined inline as well.
+const { data } = await filterOrder({ orderNumber: ..., partnerId: ..., orderType: ..., orderStatus: ..., });
+// Since all variables are optional for this query, you can omit the `FilterOrderVariables` argument.
+const { data } = await filterOrder();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await filterOrder(dataConnect, filterOrderVars);
+
+console.log(data.orders);
+
+// Or, you can use the `Promise` API.
+filterOrder(filterOrderVars).then((response) => {
+ const data = response.data;
+ console.log(data.orders);
+});
+```
+
+### Using `filterOrder`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, filterOrderRef, FilterOrderVariables } from '@dataconnect/generated';
+
+// The `filterOrder` query has an optional argument of type `FilterOrderVariables`:
+const filterOrderVars: FilterOrderVariables = {
+ orderNumber: ..., // optional
+ partnerId: ..., // optional
+ orderType: ..., // optional
+ orderStatus: ..., // optional
+};
+
+// Call the `filterOrderRef()` function to get a reference to the query.
+const ref = filterOrderRef(filterOrderVars);
+// Variables can be defined inline as well.
+const ref = filterOrderRef({ orderNumber: ..., partnerId: ..., orderType: ..., orderStatus: ..., });
+// Since all variables are optional for this query, you can omit the `FilterOrderVariables` argument.
+const ref = filterOrderRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = filterOrderRef(dataConnect, filterOrderVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.orders);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.orders);
+});
+```
+
+## listPartner
+You can execute the `listPartner` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+listPartner(): QueryPromise;
+
+interface ListPartnerRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (): QueryRef;
+}
+export const listPartnerRef: ListPartnerRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+listPartner(dc: DataConnect): QueryPromise;
+
+interface ListPartnerRef {
+ ...
+ (dc: DataConnect): QueryRef;
+}
+export const listPartnerRef: ListPartnerRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the listPartnerRef:
+```typescript
+const name = listPartnerRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `listPartner` query has no variables.
+### Return Type
+Recall that executing the `listPartner` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `ListPartnerData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface ListPartnerData {
+ partners: ({
+ id: UUIDString;
+ partnerName: string;
+ partnerNumber: string;
+ partnerType?: PartnerType | null;
+ } & Partner_Key)[];
+}
+```
+### Using `listPartner`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, listPartner } from '@dataconnect/generated';
+
+
+// Call the `listPartner()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await listPartner();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await listPartner(dataConnect);
+
+console.log(data.partners);
+
+// Or, you can use the `Promise` API.
+listPartner().then((response) => {
+ const data = response.data;
+ console.log(data.partners);
+});
+```
+
+### Using `listPartner`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, listPartnerRef } from '@dataconnect/generated';
+
+
+// Call the `listPartnerRef()` function to get a reference to the query.
+const ref = listPartnerRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = listPartnerRef(dataConnect);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.partners);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.partners);
+});
+```
+
+## getPartnerById
+You can execute the `getPartnerById` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+getPartnerById(vars: GetPartnerByIdVariables): QueryPromise;
+
+interface GetPartnerByIdRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars: GetPartnerByIdVariables): QueryRef;
+}
+export const getPartnerByIdRef: GetPartnerByIdRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+getPartnerById(dc: DataConnect, vars: GetPartnerByIdVariables): QueryPromise;
+
+interface GetPartnerByIdRef {
+ ...
+ (dc: DataConnect, vars: GetPartnerByIdVariables): QueryRef;
+}
+export const getPartnerByIdRef: GetPartnerByIdRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the getPartnerByIdRef:
+```typescript
+const name = getPartnerByIdRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `getPartnerById` query requires an argument of type `GetPartnerByIdVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface GetPartnerByIdVariables {
+ id: UUIDString;
+}
+```
+### Return Type
+Recall that executing the `getPartnerById` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `GetPartnerByIdData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface GetPartnerByIdData {
+ partner?: {
+ id: UUIDString;
+ partnerName: string;
+ partnerNumber: string;
+ partnerType?: PartnerType | null;
+ } & Partner_Key;
+}
+```
+### Using `getPartnerById`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, getPartnerById, GetPartnerByIdVariables } from '@dataconnect/generated';
+
+// The `getPartnerById` query requires an argument of type `GetPartnerByIdVariables`:
+const getPartnerByIdVars: GetPartnerByIdVariables = {
+ id: ...,
+};
+
+// Call the `getPartnerById()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await getPartnerById(getPartnerByIdVars);
+// Variables can be defined inline as well.
+const { data } = await getPartnerById({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await getPartnerById(dataConnect, getPartnerByIdVars);
+
+console.log(data.partner);
+
+// Or, you can use the `Promise` API.
+getPartnerById(getPartnerByIdVars).then((response) => {
+ const data = response.data;
+ console.log(data.partner);
+});
+```
+
+### Using `getPartnerById`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, getPartnerByIdRef, GetPartnerByIdVariables } from '@dataconnect/generated';
+
+// The `getPartnerById` query requires an argument of type `GetPartnerByIdVariables`:
+const getPartnerByIdVars: GetPartnerByIdVariables = {
+ id: ...,
+};
+
+// Call the `getPartnerByIdRef()` function to get a reference to the query.
+const ref = getPartnerByIdRef(getPartnerByIdVars);
+// Variables can be defined inline as well.
+const ref = getPartnerByIdRef({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = getPartnerByIdRef(dataConnect, getPartnerByIdVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.partner);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.partner);
+});
+```
+
+## filterPartner
+You can execute the `filterPartner` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+filterPartner(vars?: FilterPartnerVariables): QueryPromise;
+
+interface FilterPartnerRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars?: FilterPartnerVariables): QueryRef;
+}
+export const filterPartnerRef: FilterPartnerRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+filterPartner(dc: DataConnect, vars?: FilterPartnerVariables): QueryPromise;
+
+interface FilterPartnerRef {
+ ...
+ (dc: DataConnect, vars?: FilterPartnerVariables): QueryRef;
+}
+export const filterPartnerRef: FilterPartnerRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the filterPartnerRef:
+```typescript
+const name = filterPartnerRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `filterPartner` query has an optional argument of type `FilterPartnerVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface FilterPartnerVariables {
+ partnerName?: string | null;
+ partnerNumber?: string | null;
+ partnerType?: PartnerType | null;
+}
+```
+### Return Type
+Recall that executing the `filterPartner` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `FilterPartnerData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface FilterPartnerData {
+ partners: ({
+ id: UUIDString;
+ partnerName: string;
+ partnerNumber: string;
+ partnerType?: PartnerType | null;
+ } & Partner_Key)[];
+}
+```
+### Using `filterPartner`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, filterPartner, FilterPartnerVariables } from '@dataconnect/generated';
+
+// The `filterPartner` query has an optional argument of type `FilterPartnerVariables`:
+const filterPartnerVars: FilterPartnerVariables = {
+ partnerName: ..., // optional
+ partnerNumber: ..., // optional
+ partnerType: ..., // optional
+};
+
+// Call the `filterPartner()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await filterPartner(filterPartnerVars);
+// Variables can be defined inline as well.
+const { data } = await filterPartner({ partnerName: ..., partnerNumber: ..., partnerType: ..., });
+// Since all variables are optional for this query, you can omit the `FilterPartnerVariables` argument.
+const { data } = await filterPartner();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await filterPartner(dataConnect, filterPartnerVars);
+
+console.log(data.partners);
+
+// Or, you can use the `Promise` API.
+filterPartner(filterPartnerVars).then((response) => {
+ const data = response.data;
+ console.log(data.partners);
+});
+```
+
+### Using `filterPartner`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, filterPartnerRef, FilterPartnerVariables } from '@dataconnect/generated';
+
+// The `filterPartner` query has an optional argument of type `FilterPartnerVariables`:
+const filterPartnerVars: FilterPartnerVariables = {
+ partnerName: ..., // optional
+ partnerNumber: ..., // optional
+ partnerType: ..., // optional
+};
+
+// Call the `filterPartnerRef()` function to get a reference to the query.
+const ref = filterPartnerRef(filterPartnerVars);
+// Variables can be defined inline as well.
+const ref = filterPartnerRef({ partnerName: ..., partnerNumber: ..., partnerType: ..., });
+// Since all variables are optional for this query, you can omit the `FilterPartnerVariables` argument.
+const ref = filterPartnerRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = filterPartnerRef(dataConnect, filterPartnerVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.partners);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.partners);
+});
+```
+
+## listVendor
+You can execute the `listVendor` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+listVendor(): QueryPromise;
+
+interface ListVendorRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (): QueryRef;
+}
+export const listVendorRef: ListVendorRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+listVendor(dc: DataConnect): QueryPromise;
+
+interface ListVendorRef {
+ ...
+ (dc: DataConnect): QueryRef;
+}
+export const listVendorRef: ListVendorRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the listVendorRef:
+```typescript
+const name = listVendorRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `listVendor` query has no variables.
+### Return Type
+Recall that executing the `listVendor` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `ListVendorData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface ListVendorData {
+ vendors: ({
+ id: UUIDString;
+ vendorNumber: string;
+ legalName: string;
+ region: VendorRegion;
+ platformType: VendorPlatformType;
+ primaryContactEmail: string;
+ approvalStatus: VendorApprovalStatus;
+ isActive?: boolean | null;
+ } & Vendor_Key)[];
+}
+```
+### Using `listVendor`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, listVendor } from '@dataconnect/generated';
+
+
+// Call the `listVendor()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await listVendor();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await listVendor(dataConnect);
+
+console.log(data.vendors);
+
+// Or, you can use the `Promise` API.
+listVendor().then((response) => {
+ const data = response.data;
+ console.log(data.vendors);
+});
+```
+
+### Using `listVendor`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, listVendorRef } from '@dataconnect/generated';
+
+
+// Call the `listVendorRef()` function to get a reference to the query.
+const ref = listVendorRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = listVendorRef(dataConnect);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.vendors);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.vendors);
+});
+```
+
+## getVendorById
+You can execute the `getVendorById` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+getVendorById(vars: GetVendorByIdVariables): QueryPromise;
+
+interface GetVendorByIdRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars: GetVendorByIdVariables): QueryRef;
+}
+export const getVendorByIdRef: GetVendorByIdRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+getVendorById(dc: DataConnect, vars: GetVendorByIdVariables): QueryPromise;
+
+interface GetVendorByIdRef {
+ ...
+ (dc: DataConnect, vars: GetVendorByIdVariables): QueryRef;
+}
+export const getVendorByIdRef: GetVendorByIdRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the getVendorByIdRef:
+```typescript
+const name = getVendorByIdRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `getVendorById` query requires an argument of type `GetVendorByIdVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface GetVendorByIdVariables {
+ id: UUIDString;
+}
+```
+### Return Type
+Recall that executing the `getVendorById` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `GetVendorByIdData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface GetVendorByIdData {
+ vendor?: {
+ id: UUIDString;
+ vendorNumber: string;
+ legalName: string;
+ region: VendorRegion;
+ platformType: VendorPlatformType;
+ primaryContactEmail: string;
+ approvalStatus: VendorApprovalStatus;
+ isActive?: boolean | null;
+ } & Vendor_Key;
+}
+```
+### Using `getVendorById`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, getVendorById, GetVendorByIdVariables } from '@dataconnect/generated';
+
+// The `getVendorById` query requires an argument of type `GetVendorByIdVariables`:
+const getVendorByIdVars: GetVendorByIdVariables = {
+ id: ...,
+};
+
+// Call the `getVendorById()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await getVendorById(getVendorByIdVars);
+// Variables can be defined inline as well.
+const { data } = await getVendorById({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await getVendorById(dataConnect, getVendorByIdVars);
+
+console.log(data.vendor);
+
+// Or, you can use the `Promise` API.
+getVendorById(getVendorByIdVars).then((response) => {
+ const data = response.data;
+ console.log(data.vendor);
+});
+```
+
+### Using `getVendorById`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, getVendorByIdRef, GetVendorByIdVariables } from '@dataconnect/generated';
+
+// The `getVendorById` query requires an argument of type `GetVendorByIdVariables`:
+const getVendorByIdVars: GetVendorByIdVariables = {
+ id: ...,
+};
+
+// Call the `getVendorByIdRef()` function to get a reference to the query.
+const ref = getVendorByIdRef(getVendorByIdVars);
+// Variables can be defined inline as well.
+const ref = getVendorByIdRef({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = getVendorByIdRef(dataConnect, getVendorByIdVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.vendor);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.vendor);
+});
+```
+
+## filterVendors
+You can execute the `filterVendors` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+filterVendors(vars?: FilterVendorsVariables): QueryPromise;
+
+interface FilterVendorsRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars?: FilterVendorsVariables): QueryRef;
+}
+export const filterVendorsRef: FilterVendorsRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+filterVendors(dc: DataConnect, vars?: FilterVendorsVariables): QueryPromise;
+
+interface FilterVendorsRef {
+ ...
+ (dc: DataConnect, vars?: FilterVendorsVariables): QueryRef;
+}
+export const filterVendorsRef: FilterVendorsRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the filterVendorsRef:
+```typescript
+const name = filterVendorsRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `filterVendors` query has an optional argument of type `FilterVendorsVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface FilterVendorsVariables {
+ region?: VendorRegion | null;
+ approvalStatus?: VendorApprovalStatus | null;
+ isActive?: boolean | null;
+ vendorNumber?: string | null;
+ primaryContactEmail?: string | null;
+ legalName?: string | null;
+ platformType?: VendorPlatformType | null;
+}
+```
+### Return Type
+Recall that executing the `filterVendors` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `FilterVendorsData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface FilterVendorsData {
+ vendors: ({
+ id: UUIDString;
+ vendorNumber: string;
+ legalName: string;
+ region: VendorRegion;
+ platformType: VendorPlatformType;
+ primaryContactEmail: string;
+ approvalStatus: VendorApprovalStatus;
+ isActive?: boolean | null;
+ } & Vendor_Key)[];
+}
+```
+### Using `filterVendors`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, filterVendors, FilterVendorsVariables } from '@dataconnect/generated';
+
+// The `filterVendors` query has an optional argument of type `FilterVendorsVariables`:
+const filterVendorsVars: FilterVendorsVariables = {
+ region: ..., // optional
+ approvalStatus: ..., // optional
+ isActive: ..., // optional
+ vendorNumber: ..., // optional
+ primaryContactEmail: ..., // optional
+ legalName: ..., // optional
+ platformType: ..., // optional
+};
+
+// Call the `filterVendors()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await filterVendors(filterVendorsVars);
+// Variables can be defined inline as well.
+const { data } = await filterVendors({ region: ..., approvalStatus: ..., isActive: ..., vendorNumber: ..., primaryContactEmail: ..., legalName: ..., platformType: ..., });
+// Since all variables are optional for this query, you can omit the `FilterVendorsVariables` argument.
+const { data } = await filterVendors();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await filterVendors(dataConnect, filterVendorsVars);
+
+console.log(data.vendors);
+
+// Or, you can use the `Promise` API.
+filterVendors(filterVendorsVars).then((response) => {
+ const data = response.data;
+ console.log(data.vendors);
+});
+```
+
+### Using `filterVendors`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, filterVendorsRef, FilterVendorsVariables } from '@dataconnect/generated';
+
+// The `filterVendors` query has an optional argument of type `FilterVendorsVariables`:
+const filterVendorsVars: FilterVendorsVariables = {
+ region: ..., // optional
+ approvalStatus: ..., // optional
+ isActive: ..., // optional
+ vendorNumber: ..., // optional
+ primaryContactEmail: ..., // optional
+ legalName: ..., // optional
+ platformType: ..., // optional
+};
+
+// Call the `filterVendorsRef()` function to get a reference to the query.
+const ref = filterVendorsRef(filterVendorsVars);
+// Variables can be defined inline as well.
+const ref = filterVendorsRef({ region: ..., approvalStatus: ..., isActive: ..., vendorNumber: ..., primaryContactEmail: ..., legalName: ..., platformType: ..., });
+// Since all variables are optional for this query, you can omit the `FilterVendorsVariables` argument.
+const ref = filterVendorsRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = filterVendorsRef(dataConnect, filterVendorsVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.vendors);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.vendors);
+});
+```
+
+## listWorkforce
+You can execute the `listWorkforce` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+listWorkforce(): QueryPromise;
+
+interface ListWorkforceRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (): QueryRef;
+}
+export const listWorkforceRef: ListWorkforceRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+listWorkforce(dc: DataConnect): QueryPromise;
+
+interface ListWorkforceRef {
+ ...
+ (dc: DataConnect): QueryRef;
+}
+export const listWorkforceRef: ListWorkforceRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the listWorkforceRef:
+```typescript
+const name = listWorkforceRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `listWorkforce` query has no variables.
+### Return Type
+Recall that executing the `listWorkforce` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `ListWorkforceData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface ListWorkforceData {
+ workforces: ({
+ id: UUIDString;
+ workforceNumber: string;
+ vendorId: UUIDString;
+ firstName: string;
+ lastName: string;
+ employmentType?: WorkforceEmploymentType | null;
+ } & Workforce_Key)[];
+}
+```
+### Using `listWorkforce`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, listWorkforce } from '@dataconnect/generated';
+
+
+// Call the `listWorkforce()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await listWorkforce();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await listWorkforce(dataConnect);
+
+console.log(data.workforces);
+
+// Or, you can use the `Promise` API.
+listWorkforce().then((response) => {
+ const data = response.data;
+ console.log(data.workforces);
+});
+```
+
+### Using `listWorkforce`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, listWorkforceRef } from '@dataconnect/generated';
+
+
+// Call the `listWorkforceRef()` function to get a reference to the query.
+const ref = listWorkforceRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = listWorkforceRef(dataConnect);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.workforces);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.workforces);
+});
+```
+
+## getWorkforceById
+You can execute the `getWorkforceById` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+getWorkforceById(vars: GetWorkforceByIdVariables): QueryPromise;
+
+interface GetWorkforceByIdRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars: GetWorkforceByIdVariables): QueryRef;
+}
+export const getWorkforceByIdRef: GetWorkforceByIdRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+getWorkforceById(dc: DataConnect, vars: GetWorkforceByIdVariables): QueryPromise;
+
+interface GetWorkforceByIdRef {
+ ...
+ (dc: DataConnect, vars: GetWorkforceByIdVariables): QueryRef;
+}
+export const getWorkforceByIdRef: GetWorkforceByIdRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the getWorkforceByIdRef:
+```typescript
+const name = getWorkforceByIdRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `getWorkforceById` query requires an argument of type `GetWorkforceByIdVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface GetWorkforceByIdVariables {
+ id: UUIDString;
+}
+```
+### Return Type
+Recall that executing the `getWorkforceById` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `GetWorkforceByIdData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface GetWorkforceByIdData {
+ workforce?: {
+ id: UUIDString;
+ workforceNumber: string;
+ vendorId: UUIDString;
+ firstName: string;
+ lastName: string;
+ employmentType?: WorkforceEmploymentType | null;
+ } & Workforce_Key;
+}
+```
+### Using `getWorkforceById`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, getWorkforceById, GetWorkforceByIdVariables } from '@dataconnect/generated';
+
+// The `getWorkforceById` query requires an argument of type `GetWorkforceByIdVariables`:
+const getWorkforceByIdVars: GetWorkforceByIdVariables = {
+ id: ...,
+};
+
+// Call the `getWorkforceById()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await getWorkforceById(getWorkforceByIdVars);
+// Variables can be defined inline as well.
+const { data } = await getWorkforceById({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await getWorkforceById(dataConnect, getWorkforceByIdVars);
+
+console.log(data.workforce);
+
+// Or, you can use the `Promise` API.
+getWorkforceById(getWorkforceByIdVars).then((response) => {
+ const data = response.data;
+ console.log(data.workforce);
+});
+```
+
+### Using `getWorkforceById`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, getWorkforceByIdRef, GetWorkforceByIdVariables } from '@dataconnect/generated';
+
+// The `getWorkforceById` query requires an argument of type `GetWorkforceByIdVariables`:
+const getWorkforceByIdVars: GetWorkforceByIdVariables = {
+ id: ...,
+};
+
+// Call the `getWorkforceByIdRef()` function to get a reference to the query.
+const ref = getWorkforceByIdRef(getWorkforceByIdVars);
+// Variables can be defined inline as well.
+const ref = getWorkforceByIdRef({ id: ..., });
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = getWorkforceByIdRef(dataConnect, getWorkforceByIdVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.workforce);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.workforce);
+});
+```
+
+## filterWorkforce
+You can execute the `filterWorkforce` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+filterWorkforce(vars?: FilterWorkforceVariables): QueryPromise;
+
+interface FilterWorkforceRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars?: FilterWorkforceVariables): QueryRef;
+}
+export const filterWorkforceRef: FilterWorkforceRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+filterWorkforce(dc: DataConnect, vars?: FilterWorkforceVariables): QueryPromise;
+
+interface FilterWorkforceRef {
+ ...
+ (dc: DataConnect, vars?: FilterWorkforceVariables): QueryRef;
+}
+export const filterWorkforceRef: FilterWorkforceRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the filterWorkforceRef:
+```typescript
+const name = filterWorkforceRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `filterWorkforce` query has an optional argument of type `FilterWorkforceVariables`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+
+```typescript
+export interface FilterWorkforceVariables {
+ workforceNumber?: string | null;
+ vendorId?: UUIDString | null;
+ firstName?: string | null;
+ lastName?: string | null;
+ employmentType?: WorkforceEmploymentType | null;
+}
+```
+### Return Type
+Recall that executing the `filterWorkforce` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `FilterWorkforceData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface FilterWorkforceData {
+ workforces: ({
+ id: UUIDString;
+ workforceNumber: string;
+ vendorId: UUIDString;
+ firstName: string;
+ lastName: string;
+ employmentType?: WorkforceEmploymentType | null;
+ } & Workforce_Key)[];
+}
+```
+### Using `filterWorkforce`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, filterWorkforce, FilterWorkforceVariables } from '@dataconnect/generated';
+
+// The `filterWorkforce` query has an optional argument of type `FilterWorkforceVariables`:
+const filterWorkforceVars: FilterWorkforceVariables = {
+ workforceNumber: ..., // optional
+ vendorId: ..., // optional
+ firstName: ..., // optional
+ lastName: ..., // optional
+ employmentType: ..., // optional
+};
+
+// Call the `filterWorkforce()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await filterWorkforce(filterWorkforceVars);
+// Variables can be defined inline as well.
+const { data } = await filterWorkforce({ workforceNumber: ..., vendorId: ..., firstName: ..., lastName: ..., employmentType: ..., });
+// Since all variables are optional for this query, you can omit the `FilterWorkforceVariables` argument.
+const { data } = await filterWorkforce();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await filterWorkforce(dataConnect, filterWorkforceVars);
+
+console.log(data.workforces);
+
+// Or, you can use the `Promise` API.
+filterWorkforce(filterWorkforceVars).then((response) => {
+ const data = response.data;
+ console.log(data.workforces);
+});
+```
+
+### Using `filterWorkforce`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, filterWorkforceRef, FilterWorkforceVariables } from '@dataconnect/generated';
+
+// The `filterWorkforce` query has an optional argument of type `FilterWorkforceVariables`:
+const filterWorkforceVars: FilterWorkforceVariables = {
+ workforceNumber: ..., // optional
+ vendorId: ..., // optional
+ firstName: ..., // optional
+ lastName: ..., // optional
+ employmentType: ..., // optional
+};
+
+// Call the `filterWorkforceRef()` function to get a reference to the query.
+const ref = filterWorkforceRef(filterWorkforceVars);
+// Variables can be defined inline as well.
+const ref = filterWorkforceRef({ workforceNumber: ..., vendorId: ..., firstName: ..., lastName: ..., employmentType: ..., });
+// Since all variables are optional for this query, you can omit the `FilterWorkforceVariables` argument.
+const ref = filterWorkforceRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = filterWorkforceRef(dataConnect, filterWorkforceVars);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.workforces);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.workforces);
+});
+```
+
+## listActivityLog
+You can execute the `listActivityLog` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+listActivityLog(): QueryPromise;
+
+interface ListActivityLogRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (): QueryRef;
+}
+export const listActivityLogRef: ListActivityLogRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+listActivityLog(dc: DataConnect): QueryPromise;
+
+interface ListActivityLogRef {
+ ...
+ (dc: DataConnect): QueryRef;
+}
+export const listActivityLogRef: ListActivityLogRef;
+```
+
+If you need the name of the operation without creating a ref, you can retrieve the operation name by calling the `operationName` property on the listActivityLogRef:
+```typescript
+const name = listActivityLogRef.operationName;
+console.log(name);
+```
+
+### Variables
+The `listActivityLog` query has no variables.
+### Return Type
+Recall that executing the `listActivityLog` query returns a `QueryPromise` that resolves to an object with a `data` property.
+
+The `data` property is an object of type `ListActivityLogData`, which is defined in [dataconnect-generated/index.d.ts](./index.d.ts). It has the following fields:
+```typescript
+export interface ListActivityLogData {
+ activityLogs: ({
+ id: UUIDString;
+ title: string;
+ description: string;
+ activityType: ActivityType;
+ userId: string;
+ isRead?: boolean | null;
+ iconType?: string | null;
+ iconColor?: string | null;
+ } & ActivityLog_Key)[];
+}
+```
+### Using `listActivityLog`'s action shortcut function
+
+```typescript
+import { getDataConnect } from 'firebase/data-connect';
+import { connectorConfig, listActivityLog } from '@dataconnect/generated';
+
+
+// Call the `listActivityLog()` function to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await listActivityLog();
+
+// You can also pass in a `DataConnect` instance to the action shortcut function.
+const dataConnect = getDataConnect(connectorConfig);
+const { data } = await listActivityLog(dataConnect);
+
+console.log(data.activityLogs);
+
+// Or, you can use the `Promise` API.
+listActivityLog().then((response) => {
+ const data = response.data;
+ console.log(data.activityLogs);
+});
+```
+
+### Using `listActivityLog`'s `QueryRef` function
+
+```typescript
+import { getDataConnect, executeQuery } from 'firebase/data-connect';
+import { connectorConfig, listActivityLogRef } from '@dataconnect/generated';
+
+
+// Call the `listActivityLogRef()` function to get a reference to the query.
+const ref = listActivityLogRef();
+
+// You can also pass in a `DataConnect` instance to the `QueryRef` function.
+const dataConnect = getDataConnect(connectorConfig);
+const ref = listActivityLogRef(dataConnect);
+
+// Call `executeQuery()` on the reference to execute the query.
+// You can use the `await` keyword to wait for the promise to resolve.
+const { data } = await executeQuery(ref);
+
+console.log(data.activityLogs);
+
+// Or, you can use the `Promise` API.
+executeQuery(ref).then((response) => {
+ const data = response.data;
+ console.log(data.activityLogs);
+});
+```
+
+## getActivityLogById
+You can execute the `getActivityLogById` query using the following action shortcut function, or by calling `executeQuery()` after calling the following `QueryRef` function, both of which are defined in [dataconnect-generated/index.d.ts](./index.d.ts):
+```typescript
+getActivityLogById(vars: GetActivityLogByIdVariables): QueryPromise;
+
+interface GetActivityLogByIdRef {
+ ...
+ /* Allow users to create refs without passing in DataConnect */
+ (vars: GetActivityLogByIdVariables): QueryRef;
+}
+export const getActivityLogByIdRef: GetActivityLogByIdRef;
+```
+You can also pass in a `DataConnect` instance to the action shortcut function or `QueryRef` function.
+```typescript
+getActivityLogById(dc: DataConnect, vars: GetActivityLogByIdVariables): QueryPromise;
+
+interface GetActivityLogByIdRef {
+ ...
+ (dc: DataConnect, vars: GetActivityLogByIdVariables): QueryRef