feat/crm-ops #52
No reviewers
Labels
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
psa-systems/mokosh-apps!52
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/crm-ops"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
CompanyDetailPage previously made zero backend calls. The URL props.id was used only for the page title; every other field (Acme Corp, '(555) 123-4500', '123 Business Ave', Bob Johnson / Sarah Miller / Mike Davis contacts, TKT-1234 + TKT-1231 tickets, 'Managed Services Agreement' contract card, 'Revenue (YTD): $42,500') was a literal. Rewire end-to-end: - Detail header pulls the company name and three statistics (open_tickets, contacts, sites) from GET /v1/companies/{id} now that the rollup fields are populated. - Contacts card -> GET /v1/companies/{id}/contacts; each row links to the contact detail page. - Sites card -> GET /v1/companies/{id}/sites (new surface; was not visible anywhere in the UI). Read-only for this commit; the inline add/edit modal lands separately. - Recent Tickets card -> GET /v1/tickets?company_id={id}&page_size=5&sort=-updated_at. Status badge color comes from TicketStatusSummary.is_closed. - Sidebar Details card pulls type / phone / website / industry / address from the loaded CompanyResponse. Empty fields hide entirely rather than displaying placeholder text. - Contract sidebar card removed (separate story); 'Revenue (YTD)' stat removed (no backend source). - Three async resources fire in parallel on mount; each renders loading skeleton, error message, empty state, or rows independently. Tenant-generation read keeps them re-fetching on org switch. New surfaces: - Edit button on the detail header navigates to /companies/:id/edit. - Delete button triggers a window.confirm + DELETE /v1/companies/{id}; on success the user lands back on the list. ButtonVariant::Danger. - CompanyForm component is now shared between New and Edit, with a CompanyFormMode discriminator. Fields expand beyond the original name + type: industry, website, phone, full address (line1, line2, city, state, postal_code, country) - all optional except name. Form errors surface inline rather than via console.error. Wire bits: - New Route::CompanyEdit { id } in lib.rs route table + matching component handler. - CompanyEditPage fetches the existing company first, then mounts CompanyForm with the loaded values; 404 surfaces an inline error card with a back-to-list link. Remaining seeded content lives in ContactDetailPage and the contact new form's company picker; those get separate commits.ContactNewPage previously shipped a hardcoded company dropdown ([("1","Acme Corp"),("2","TechStart Inc"),("3","Global Widgets")]) that parsed unknown values to Uuid::nil() so the server rejected them with a typed validation error. The form was functionally broken; the only path to a successful create was hand-pasting a real company UUID into one of the fake values. The detail page went further: zero backend calls, every field hardcoded (Bob Johnson, bob@acme.com, '(555) 123-4567', '(555) 987-6543', Acme Corp link, 'Created ticket TKT-1234 - 2 hours ago' activity entries, fake 'Portal Access: Active - Today, 9:15 AM' card). Replace end to end. CompanyPicker (new components/company_picker.rs): - Search-input that hits GET /v1/companies?q=...&page_size=20. - Renders results as a click-to-select dropdown; on pick fires onselect((id, name)). - When a selection exists, switches to a 'selected chip + Change' layout so the caller knows what's set without re-running the search. - Tiny inline percent-encoder for the few chars that break URL query strings; avoids pulling in urlencoding for one call site. - Reusable: contact form uses it today, ticket new form / time entry form will reuse it. ContactForm (new): - Shared between ContactNewPage and the new ContactEditPage. - Expands the field set to match the backend's CreateContactRequest / UpdateContactRequest: first_name + last_name (required), email, phone, mobile, title, department, contact_type (primary / technical / billing / other), plus the CompanyPicker. - nil() company guard now lives client-side: submit aborts with an inline error if no UUID is set, instead of round-tripping to the server for a validation error. - Errors surface inline via a red banner above the fields. ContactEditPage + Route::ContactEdit: - /contacts/:id/edit route + dispatch. - Fetches the contact first via GET /v1/contacts/{id}, then mounts ContactForm with the loaded values. CompanyPicker initializes to the linked company so the user can leave it or pick another. ContactDetailPage rewrite: - Two parallel resources: GET /v1/contacts/{id} for the sidebar Contact Information card; GET /v1/tickets?contact_id={id}&page_size=5 for the Recent Tickets card. - Sidebar renders every optional field only when populated; no more placeholder values for missing data. - Company name + link come from the loaded ContactResponse (company_id + company_name). - Edit and Delete actions on the page header; Delete confirms via window.confirm and DELETE /v1/contacts/{id}. Portal Access card (per docs/mokosh-upgrade/CRM/02-contacts.md D-A): - Reads is_portal_user off the contact; shows Granted / Not granted badges instead of the fake 'Active' + 'Last Login: Today, 9:15 AM'. - Grant button PUTs {is_portal_user: true}; Revoke button PUTs {is_portal_user: false}. - Both states surface the password-mint caveat: the flag flip alone does not let the contact sign in; password issuance lives behind Settings > Portal Users (separate story). - On toggle the detail resource restarts so the card re-renders from authoritative state. Wire bits: - New Route::ContactEdit { id } in lib.rs + ContactEdit component wrapper. - Removed every hardcoded TKT-/Bob Johnson/Sarah Miller/Mike Davis/ Acme Corp string from the contact pages. - humanize_contact_type helper for the Type badge. grep -nE 'Acme Corp|TechStart|Global Widgets|Bob Johnson|Sarah Miller|Mike Davis|Alice Williams|Charlie Brown|bob@acme.com|sarah@acme.com|mike@acme.com|TKT-1234|TKT-1231|TKT-1233' src/pages/contacts.rs returns zero results.