From 99465a590d481312d572a7bb8aa694a36c0a27d0 Mon Sep 17 00:00:00 2001 From: Trey t Date: Fri, 28 Nov 2025 21:00:42 -0600 Subject: [PATCH] Fix admin panel edit forms and expand API responses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix dropdown population on all edit pages (residence, task, contractor, document) - Add formInitialized state pattern to prevent empty dropdowns - Increase pagination max limit from 100 to 10000 for admin queries - Expand handler responses to include all editable fields - Add settings page with seed data and limitations toggle - Fix user form and API client types 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../contractors/[id]/edit/page.tsx | 272 +++++++++++--- .../(dashboard)/documents/[id]/edit/page.tsx | 338 ++++++++++++++++-- .../(dashboard)/residences/[id]/edit/page.tsx | 246 +++++++++++-- admin/src/app/(dashboard)/settings/page.tsx | 67 +++- .../app/(dashboard)/tasks/[id]/edit/page.tsx | 330 ++++++++++++++++- admin/src/components/ui/textarea.tsx | 4 +- admin/src/components/users/user-form.tsx | 27 +- admin/src/lib/api.ts | 5 + admin/src/types/models.ts | 97 ++++- internal/admin/dto/requests.go | 118 ++++-- internal/admin/dto/responses.go | 131 ++++--- internal/admin/handlers/contractor_handler.go | 79 +++- internal/admin/handlers/document_handler.go | 110 +++++- internal/admin/handlers/residence_handler.go | 86 ++++- internal/admin/handlers/settings_handler.go | 267 ++++++++++++++ internal/admin/handlers/task_handler.go | 70 ++++ internal/admin/handlers/user_handler.go | 21 +- internal/admin/routes.go | 1 + 18 files changed, 2028 insertions(+), 241 deletions(-) diff --git a/admin/src/app/(dashboard)/contractors/[id]/edit/page.tsx b/admin/src/app/(dashboard)/contractors/[id]/edit/page.tsx index d46b4f0..7d36572 100644 --- a/admin/src/app/(dashboard)/contractors/[id]/edit/page.tsx +++ b/admin/src/app/(dashboard)/contractors/[id]/edit/page.tsx @@ -6,13 +6,20 @@ import { useMutation, useQuery } from '@tanstack/react-query'; import { ArrowLeft } from 'lucide-react'; import Link from 'next/link'; -import { contractorsApi } from '@/lib/api'; +import { contractorsApi, usersApi, residencesApi, lookupsApi } from '@/lib/api'; import type { UpdateContractorRequest } from '@/types/models'; 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 { Switch } from '@/components/ui/switch'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select'; import { Card, CardContent, @@ -27,36 +34,56 @@ export default function EditContractorPage() { const params = useParams(); const contractorId = Number(params.id); - const [formData, setFormData] = useState({ - name: '', - company: '', - phone: '', - email: '', - website: '', - notes: '', - is_favorite: false, - is_active: true, - }); + const [formData, setFormData] = useState({}); - const { data: contractor, isLoading } = useQuery({ + const { data: contractor, isLoading: contractorLoading } = useQuery({ queryKey: ['contractor', contractorId], queryFn: () => contractorsApi.get(contractorId), enabled: !!contractorId, }); + const { data: usersData, isLoading: usersLoading } = useQuery({ + queryKey: ['users', { per_page: 1000 }], + queryFn: () => usersApi.list({ per_page: 1000 }), + }); + + const { data: residencesData, isLoading: residencesLoading } = useQuery({ + queryKey: ['residences', { per_page: 1000 }], + queryFn: () => residencesApi.list({ per_page: 1000 }), + }); + + const { data: specialties } = useQuery({ + queryKey: ['lookups', 'specialties'], + queryFn: () => lookupsApi.specialties.list(), + }); + + const [formInitialized, setFormInitialized] = useState(false); + useEffect(() => { - if (contractor) { + if (contractor && !formInitialized) { setFormData({ + residence_id: contractor.residence_id, + created_by_id: contractor.created_by_id, name: contractor.name, company: contractor.company, phone: contractor.phone, email: contractor.email, website: contractor.website, + notes: contractor.notes, + street_address: contractor.street_address, + city: contractor.city, + state_province: contractor.state_province, + postal_code: contractor.postal_code, + rating: contractor.rating, is_favorite: contractor.is_favorite, is_active: contractor.is_active, + specialty_ids: contractor.specialty_ids, }); + setFormInitialized(true); } - }, [contractor]); + }, [contractor, formInitialized]); + + const isDataLoading = contractorLoading || usersLoading || residencesLoading || !formInitialized; const updateMutation = useMutation({ mutationFn: (data: UpdateContractorRequest) => contractorsApi.update(contractorId, data), @@ -82,7 +109,7 @@ export default function EditContractorPage() { setFormData((prev) => ({ ...prev, [field]: value })); }; - if (isLoading) { + if (isDataLoading) { return (
Loading...
@@ -105,10 +132,57 @@ export default function EditContractorPage() {
+ + + Assignment + Contractor ownership + + +
+
+ + +
+
+ + +
+
+
+
+ Basic Information - Update the contractor details + Contractor contact details
@@ -118,7 +192,7 @@ export default function EditContractorPage() { id="name" value={formData.name || ''} onChange={(e) => updateField('name', e.target.value)} - placeholder="John Doe" + placeholder="Contractor name" />
@@ -127,37 +201,10 @@ export default function EditContractorPage() { id="company" value={formData.company || ''} onChange={(e) => updateField('company', e.target.value)} - placeholder="ABC Plumbing" + placeholder="Company name" />
-
-
- updateField('is_favorite', checked)} - /> - -
-
- updateField('is_active', checked)} - /> - -
-
-
-
- - - - Contact Information - Update contact details - -
@@ -165,7 +212,7 @@ export default function EditContractorPage() { id="phone" value={formData.phone || ''} onChange={(e) => updateField('phone', e.target.value)} - placeholder="(555) 123-4567" + placeholder="555-123-4567" />
@@ -188,21 +235,136 @@ export default function EditContractorPage() { placeholder="https://example.com" />
+
+ +