updates on the customer app and map stuck issue
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Mail, Package, Pencil, Phone, Plus, Users } from 'lucide-react';
|
||||
import {
|
||||
@@ -22,22 +22,38 @@ const custId = (row) => row.appcustomerid ?? row.tenantcustomerid ?? row.custome
|
||||
const custName = (row) => row.name || [row.firstname, row.lastname].filter(Boolean).join(' ') || '—';
|
||||
const custPhone = (row) => row.phone || row.contactno || '';
|
||||
const custEmail = (row) => row.email || '';
|
||||
/** Address accessor for search and preview */
|
||||
const custAddress = (row) => [row.address, row.deliveryaddress, row.suburb, row.city, row.postcode].filter(Boolean).join(', ');
|
||||
/** Tenant customers carry no booking count; 0 is honest rather than blank. */
|
||||
const custBookings = (row) => row.totalbookings ?? 0;
|
||||
|
||||
const readSavedContacts = () => {
|
||||
try {
|
||||
const data = localStorage.getItem('doormile_saved_contacts');
|
||||
return data ? JSON.parse(data) : [];
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
export default function Customers({ embedded = false }) {
|
||||
const navigate = useNavigate();
|
||||
const { data: customers = [], isLoading, isFetching } = useTenantCustomers();
|
||||
const updateCustomer = useUpdateTenantCustomer();
|
||||
|
||||
const [localSavedContacts] = useState(() => {
|
||||
try {
|
||||
const data = localStorage.getItem('doormile_saved_contacts');
|
||||
return data ? JSON.parse(data) : [];
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
});
|
||||
const [localSavedContacts, setLocalSavedContacts] = useState(readSavedContacts);
|
||||
|
||||
useEffect(() => {
|
||||
const handleUpdate = () => setLocalSavedContacts(readSavedContacts());
|
||||
window.addEventListener('doormile_saved_contacts_updated', handleUpdate);
|
||||
window.addEventListener('storage', handleUpdate);
|
||||
window.addEventListener('focus', handleUpdate);
|
||||
return () => {
|
||||
window.removeEventListener('doormile_saved_contacts_updated', handleUpdate);
|
||||
window.removeEventListener('storage', handleUpdate);
|
||||
window.removeEventListener('focus', handleUpdate);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const mergedCustomers = useMemo(() => {
|
||||
const list = [...(customers || [])];
|
||||
@@ -86,7 +102,7 @@ export default function Customers({ embedded = false }) {
|
||||
let list = mergedCustomers;
|
||||
if (activeFilter === 'withEmail') list = list.filter((row) => Boolean(row.email));
|
||||
else if (activeFilter === 'withPhone') list = list.filter((row) => Boolean(row.phone));
|
||||
return list.filter((row) => matchesQuery(row, [custName, custPhone, custEmail], debouncedSearch));
|
||||
return list.filter((row) => matchesQuery(row, [custName, custPhone, custEmail, custAddress], debouncedSearch));
|
||||
}, [mergedCustomers, activeFilter, debouncedSearch]);
|
||||
|
||||
const toggleFilter = (key) => setActiveFilter((current) => (current === key ? 'all' : key));
|
||||
@@ -97,13 +113,39 @@ export default function Customers({ embedded = false }) {
|
||||
};
|
||||
|
||||
const save = () => {
|
||||
const id = custId(editRow);
|
||||
// If it's a locally saved contact, update localStorage directly
|
||||
if (String(id).startsWith('saved_')) {
|
||||
const cleanPhone = String(form.phone || '').replace(/\D/g, '').slice(-10);
|
||||
try {
|
||||
const stored = JSON.parse(localStorage.getItem('doormile_saved_contacts') || '[]');
|
||||
const updated = stored.map((item) => {
|
||||
if (item.id === id || String(item.phone || item.contactno).replace(/\D/g, '').slice(-10) === cleanPhone) {
|
||||
return {
|
||||
...item,
|
||||
name: form.name,
|
||||
firstname: form.name,
|
||||
phone: form.phone,
|
||||
contactno: form.phone,
|
||||
email: form.email
|
||||
};
|
||||
}
|
||||
return item;
|
||||
});
|
||||
localStorage.setItem('doormile_saved_contacts', JSON.stringify(updated));
|
||||
window.dispatchEvent(new Event('doormile_saved_contacts_updated'));
|
||||
} catch {}
|
||||
setEditRow(null);
|
||||
return;
|
||||
}
|
||||
|
||||
/* The record stores firstname/lastname but the dialog edits one name field.
|
||||
Splitting on the first space keeps the surname through a round trip
|
||||
instead of blanking it. */
|
||||
const [firstname, ...rest] = String(form.name || '').trim().split(/\s+/);
|
||||
updateCustomer.mutate(
|
||||
{
|
||||
id: custId(editRow),
|
||||
id,
|
||||
data: {
|
||||
firstname: firstname || '',
|
||||
lastname: rest.join(' '),
|
||||
@@ -122,15 +164,28 @@ export default function Customers({ embedded = false }) {
|
||||
header: 'Customer',
|
||||
sortable: true,
|
||||
accessor: custName,
|
||||
cell: (row) => (
|
||||
<div className="flex items-center gap-2.5 min-w-0">
|
||||
<Avatar name={custName(row)} size="sm" />
|
||||
<div className="min-w-0">
|
||||
<p className="truncate text-body-sm font-semibold text-ink-1">{custName(row)}</p>
|
||||
<p className="text-caption text-ink-3">ID #{custId(row) ?? '—'}</p>
|
||||
cell: (row) => {
|
||||
const addr = custAddress(row);
|
||||
const isSaved = row.isSavedForLater || String(custId(row)).startsWith('saved_');
|
||||
return (
|
||||
<div className="flex items-center gap-2.5 min-w-0">
|
||||
<Avatar name={custName(row)} size="sm" />
|
||||
<div className="min-w-0">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<p className="truncate text-body-sm font-semibold text-ink-1">{custName(row)}</p>
|
||||
{isSaved && (
|
||||
<span className="text-[10px] bg-emerald-50 text-emerald-700 border border-emerald-200 px-1.5 py-0.5 rounded font-semibold shrink-0">
|
||||
Saved
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-caption text-ink-3 truncate max-w-xs" title={addr || `ID #${custId(row) ?? '—'}`}>
|
||||
{addr ? `📍 ${addr}` : `ID #${custId(row) ?? '—'}`}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'contact',
|
||||
@@ -219,7 +274,7 @@ export default function Customers({ embedded = false }) {
|
||||
search={search}
|
||||
onSearchChange={setSearch}
|
||||
placeholder="Search by name, phone or email"
|
||||
count={{ shown: rows.length, total: customers.length, noun: 'customers' }}
|
||||
count={{ shown: rows.length, total: mergedCustomers.length, noun: 'customers' }}
|
||||
actions={
|
||||
<Button onClick={() => navigate('/doormile/customer/create')}>
|
||||
<Plus className="mr-1.5 h-4 w-4" /> New customer
|
||||
|
||||
Reference in New Issue
Block a user