backend integration started

This commit is contained in:
2026-08-26 18:37:28 +05:30
parent 517a99d577
commit 3545819be8
50 changed files with 3461 additions and 3241 deletions

View File

@@ -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} />
) : (

View File

@@ -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'),

View File

@@ -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} />}

View File

@@ -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} />}

View File

@@ -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>
);
}