import React, { useMemo, useState } from 'react';
import { MdOutlineWarehouse, MdEdit, MdDeleteOutline, MdAdd, MdPlace, MdOutlineCheckCircle } from 'react-icons/md';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { enqueueSnackbar } from 'notistack';
import { Grid } from '@astryxdesign/core/Grid';
import { HStack } from '@astryxdesign/core/HStack';
import { VStack } from '@astryxdesign/core/VStack';
import { Text } from '@astryxdesign/core/Text';
import { Button } from '@astryxdesign/core/Button';
import { IconButton } from '@astryxdesign/core/IconButton';
import { Dialog, DialogHeader } from '@astryxdesign/core/Dialog';
import { Layout, LayoutContent, LayoutFooter } from '@astryxdesign/core/Layout';
import { Divider } from '@astryxdesign/core/Divider';
import { TextInput } from '@astryxdesign/core/TextInput';
import { NumberInput } from '@astryxdesign/core/NumberInput';
import { Selector } from '@astryxdesign/core/Selector';
import { EmptyState } from '@astryxdesign/core/EmptyState';
import { Table, TableHeader, TableBody, TableRow, TableCell, TableHeaderCell } from '@astryxdesign/core/Table';
import Loader from 'components/Loader';
import TableLoader from 'components/nearle_components/TableLoader';
import DebounceSearchBar from 'components/nearle_components/DebounceSearchBar';
import PageHeader from 'components/nearle_components/PageHeader';
import StatCard from 'components/nearle_components/StatCard';
import StatusBadge from 'components/nearle_components/StatusBadge';
import { PageShell, KpiGrid, FilterToolbar, DataCard } from 'components/nearle_components/PageLayout';
import { getHubs, createHub, updateHub, deleteHub } from 'pages/api/doormileApi';
import { DT, STATUS } from 'themes/dt/tokens';
import { TableScroll, AccentAvatar } from 'themes/dt/primitives';
const BRAND = DT.brand;
const HUB_TYPE_OPTIONS = [
{ value: 'sorting_center', label: 'Sorting Center' },
{ value: 'delivery_hub', label: 'Delivery Hub' }
];
const STATUS_OPTIONS = [
{ value: 'Active', label: 'Active' },
{ value: 'Inactive', label: 'Inactive' }
];
const emptyForm = {
hubid: null,
hubname: '',
hubtype: 'delivery_hub',
applocationid: '',
contactno: '',
address: '',
latitude: '',
longitude: '',
pincode: '',
// Confirmed live: POST /admin/hubs rejects lowercase status ("active"
// fails, "Active" works) — Inactive was never confirmed to work even on
// create, so this only offers the confirmed-working value here.
status: 'Active'
};
const Hubs = () => {
const queryClient = useQueryClient();
const [searchword, setSearchword] = useState('');
const [debouncedSearch, setDebouncedSearch] = useState('');
const [dialogOpen, setDialogOpen] = useState(false);
const [form, setForm] = useState(emptyForm);
const { data: hubs = [], isLoading } = useQuery({ queryKey: ['admin-hubs'], queryFn: getHubs });
const rows = useMemo(() => {
if (!debouncedSearch) return hubs;
const q = debouncedSearch.toLowerCase().trim();
return hubs.filter((row) =>
[row.hubname, row.hubtype, row.address, row.pincode].filter(Boolean).some((f) => String(f).toLowerCase().includes(q))
);
}, [hubs, debouncedSearch]);
const stats = useMemo(() => {
const total = hubs.length;
const sorting = hubs.filter((h) => h.hubtype === 'sorting_center').length;
const delivery = hubs.filter((h) => h.hubtype === 'delivery_hub').length;
const active = hubs.filter((h) => String(h.status || '').toLowerCase() === 'active').length;
return { total, sorting, delivery, active };
}, [hubs]);
const opentoast = (message, variant = 'error') =>
enqueueSnackbar(message, { variant, anchorOrigin: { vertical: 'top', horizontal: 'right' }, autoHideDuration: 2000 });
const saveMutation = useMutation({
mutationFn: (payload) => (payload.hubid ? updateHub(payload.hubid, payload.data) : createHub(payload.data)),
onSuccess: (res) => {
if (res.success) {
opentoast(form.hubid ? 'Hub updated' : 'Hub created', 'success');
queryClient.invalidateQueries({ queryKey: ['admin-hubs'] });
setDialogOpen(false);
} else {
opentoast(res.message || 'Failed to save hub');
}
},
onError: (err) => opentoast(err.response?.data?.message || err.message || 'Failed to save hub')
});
const deleteMutation = useMutation({
mutationFn: (id) => deleteHub(id),
onSuccess: (res) => {
if (res.success) {
opentoast('Hub deleted', 'success');
queryClient.invalidateQueries({ queryKey: ['admin-hubs'] });
} else {
opentoast(res.message || 'Failed to delete hub');
}
},
onError: (err) => opentoast(err.response?.data?.message || err.message || 'Failed to delete hub')
});
const openCreate = () => {
setForm(emptyForm);
setDialogOpen(true);
};
const openEdit = (row) => {
setForm({
hubid: row.hubid,
hubname: row.hubname || '',
hubtype: row.hubtype || 'delivery_hub',
applocationid: row.applocationid ?? '',
contactno: row.contactno || '',
address: row.address || '',
latitude: row.latitude ?? '',
longitude: row.longitude ?? '',
pincode: row.pincode || '',
status: row.status || 'Active'
});
setDialogOpen(true);
};
const handleDelete = (row) => {
if (window.confirm(`Delete hub "${row.hubname}"?`)) deleteMutation.mutate(row.hubid);
};
const handleSave = () => {
if (!form.hubname || !form.applocationid) {
opentoast('Fill Hub Name and City (applocationid)');
return;
}
const { hubid, ...data } = form;
saveMutation.mutate({
hubid,
data: {
...data,
applocationid: Number(data.applocationid),
latitude: Number(data.latitude) || 0,
longitude: Number(data.longitude) || 0
}
});
};
const set = (key) => (value) => setForm((f) => ({ ...f, [key]: value }));
return (
<>
{(isLoading || deleteMutation.isPending) && }
} onClick={openCreate} />}
/>
} color={BRAND} />
} color={STATUS.info} />
} color={STATUS.delivered} />
} color={STATUS.active} />
{hubs.length} total · {rows.length} shown
}
>
#
Hub Name
Type
City
Address
Pincode
Status
Actions
{isLoading && }
{rows.length === 0 && !isLoading ? (
}
/>
) : (
rows.map((row, index) => (
{index + 1}
{row.hubname}
{row.hubtype === 'sorting_center' ? 'Sorting Center' : 'Delivery Hub'}
{row.applocationid ?? '—'}
{row.address || '—'}
{row.pincode || '—'}
{row.status ? : '—'}
}
onClick={() => openEdit(row)}
/>
}
onClick={() => handleDelete(row)}
/>
))
)}
>
);
};
export default Hubs;