backend integration started
This commit is contained in:
@@ -30,10 +30,11 @@ import { SectionHeader } from '@/components/SectionHeader';
|
||||
import { queryKeys } from '@/queries/keys';
|
||||
import { useStockRequests, useStockStatement } from '@/queries/hooks';
|
||||
import { useBranchScope } from '../BranchScope';
|
||||
import { CataloguePanel } from '../CataloguePanel';
|
||||
import { ProductsPanel } from '../ProductsPanel';
|
||||
import { branchLabel, count, money } from '../format';
|
||||
|
||||
type Tab = 'products' | 'stock' | 'requests';
|
||||
type Tab = 'products' | 'catalogue' | 'stock' | 'requests';
|
||||
|
||||
/**
|
||||
* Inventory — catalogue, stock and the approval queue.
|
||||
@@ -55,7 +56,6 @@ export function InventoryPage() {
|
||||
const [tab, setTab] = useState<Tab>('products');
|
||||
// Owned here so the button can live in the tab row while the drawer it opens
|
||||
// stays inside the panel that uses it.
|
||||
const [isImporting, setImporting] = useState(false);
|
||||
const [isUploading, setUploading] = useState(false);
|
||||
|
||||
const requests = useStockRequests(
|
||||
@@ -73,9 +73,14 @@ export function InventoryPage() {
|
||||
title="Inventory"
|
||||
count={selected === null ? `${branches.length} branches` : current?.locationname}
|
||||
description="What you sell, where it is stocked, and what the shops are asking you for."
|
||||
/* The two product actions live here, not in the tab row, so their
|
||||
position is fixed — they no longer appear and disappear as the tab
|
||||
changes, and nothing below shifts sideways when they do.
|
||||
/* Upload sheet lives here, not in the tab row, so its position is
|
||||
fixed — it no longer appears and disappears as the tab changes, and
|
||||
nothing below shifts sideways when it does.
|
||||
|
||||
"Import products" used to sit beside it and is gone: once browsing
|
||||
the catalogue became a tab, the button was a second door to a room
|
||||
already on the wall, and it read as a different action than the tab
|
||||
it opened.
|
||||
|
||||
The "N awaiting approval" badge that used to sit here is gone: the
|
||||
Stock requests tab already carries the same count, and a number
|
||||
@@ -89,12 +94,6 @@ export function InventoryPage() {
|
||||
isDisabled={!tenantid}
|
||||
onClick={() => setUploading(true)}
|
||||
/>
|
||||
<BarAction
|
||||
label="Import products"
|
||||
icon={<DownloadCloud size={14} />}
|
||||
isDisabled={!tenantid}
|
||||
onClick={() => setImporting(true)}
|
||||
/>
|
||||
</HStack>
|
||||
}
|
||||
tabs={
|
||||
@@ -102,13 +101,19 @@ export function InventoryPage() {
|
||||
giving it a row of its own below. It only appears on that tab —
|
||||
an action for a panel you are not looking at is a misfire waiting
|
||||
to happen. */
|
||||
<HStack gap={0.5} wrap="wrap" style={{ paddingTop: 12 }}>
|
||||
<HStack gap={0.5} wrap="wrap">
|
||||
<TabButton
|
||||
label="Products"
|
||||
icon={<PackageSearch size={14} />}
|
||||
isActive={tab === 'products'}
|
||||
onClick={() => setTab('products')}
|
||||
/>
|
||||
<TabButton
|
||||
label="Catalogue"
|
||||
icon={<DownloadCloud size={14} />}
|
||||
isActive={tab === 'catalogue'}
|
||||
onClick={() => setTab('catalogue')}
|
||||
/>
|
||||
<TabButton
|
||||
label="Stock requests"
|
||||
icon={<ClipboardList size={14} />}
|
||||
@@ -128,11 +133,11 @@ export function InventoryPage() {
|
||||
|
||||
{tab === 'products' ? (
|
||||
<ProductsPanel
|
||||
isImporting={isImporting}
|
||||
onCloseImport={() => setImporting(false)}
|
||||
isUploading={isUploading}
|
||||
onCloseUpload={() => setUploading(false)}
|
||||
/>
|
||||
) : tab === 'catalogue' ? (
|
||||
<CataloguePanel />
|
||||
) : tab === 'requests' ? (
|
||||
<RequestsPanel requests={requests.data ?? []} isLoading={requests.isLoading} />
|
||||
) : (
|
||||
|
||||
@@ -55,8 +55,15 @@ const EMPTY: FormState = {
|
||||
contactno: '',
|
||||
address: '',
|
||||
suburb: '',
|
||||
city: 'Coimbatore',
|
||||
state: 'Tamil Nadu',
|
||||
// Empty, not pre-filled.
|
||||
//
|
||||
// These carried 'Coimbatore' and 'Tamil Nadu' as VALUES, not placeholders —
|
||||
// so a merchant anywhere else was submitted with the wrong city and state
|
||||
// unless somebody noticed and cleared them. A default that is right most of
|
||||
// the time is worse than a blank field, because it is only checked when it
|
||||
// looks wrong.
|
||||
city: '',
|
||||
state: '',
|
||||
postcode: '',
|
||||
opentime: isoTime('08:00'),
|
||||
closetime: isoTime('22:00'),
|
||||
|
||||
@@ -110,7 +110,7 @@ export function ReportsPage() {
|
||||
/>
|
||||
}
|
||||
tabs={
|
||||
<HStack gap={0.5} wrap="wrap" style={{ paddingTop: 12 }}>
|
||||
<HStack gap={0.5} wrap="wrap">
|
||||
<TabButton
|
||||
label="Revenue"
|
||||
icon={<IndianRupee size={14} />}
|
||||
|
||||
@@ -184,7 +184,7 @@ export function SalesPage() {
|
||||
</HStack>
|
||||
}
|
||||
tabs={
|
||||
<HStack gap={0.5} wrap="wrap" style={{ paddingTop: 12 }}>
|
||||
<HStack gap={0.5} wrap="wrap">
|
||||
<TabButton
|
||||
label="Online Orders"
|
||||
icon={<ShoppingCart size={14} />}
|
||||
|
||||
@@ -125,7 +125,7 @@ export function UsersPage() {
|
||||
/>
|
||||
}
|
||||
tabs={
|
||||
<HStack gap={0.5} wrap="wrap" style={{ paddingTop: 12 }}>
|
||||
<HStack gap={0.5} wrap="wrap">
|
||||
<TabButton
|
||||
label="Store users"
|
||||
icon={<UserCog size={14} />}
|
||||
@@ -426,8 +426,16 @@ function Chip({ label, tone }: { label: string | undefined; tone: keyof typeof T
|
||||
|
||||
/** Active is quiet, anything else is loud — an inactive account is the exception. */
|
||||
function StatusChip({ status }: { status: string | undefined }) {
|
||||
const isActive = (status ?? 'active').toLowerCase().startsWith('active');
|
||||
const colour = isActive ? 'var(--color-success, #10b981)' : 'var(--color-ink-4)';
|
||||
// A missing status is UNKNOWN, not active. Defaulting it to active painted a
|
||||
// green dot and the word "Active" beside an account whose state the API never
|
||||
// reported — which is the one case where somebody most needs to look.
|
||||
const isActive = (status ?? '').toLowerCase().startsWith('active');
|
||||
const isUnknown = !status;
|
||||
const colour = isUnknown
|
||||
? 'var(--color-ink-4)'
|
||||
: isActive
|
||||
? 'var(--color-success, #10b981)'
|
||||
: 'var(--color-ink-4)';
|
||||
return (
|
||||
<span
|
||||
style={{
|
||||
@@ -442,7 +450,7 @@ function StatusChip({ status }: { status: string | undefined }) {
|
||||
<span
|
||||
style={{ width: 6, height: 6, borderRadius: 999, background: colour, flex: 'none' }}
|
||||
/>
|
||||
{isActive ? 'Active' : (status ?? 'Inactive')}
|
||||
{isUnknown ? 'Unknown' : isActive ? 'Active' : status}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user