This commit is contained in:
2026-09-09 11:19:05 +05:30
parent a94c23c20e
commit 32c612a10d
8 changed files with 335 additions and 127 deletions

View File

@@ -15,6 +15,7 @@ import { PageBody } from '@/components/PageBody';
import { PageHeader } from '@/components/PageHeader';
import { SectionHeader } from '@/components/SectionHeader';
import { queryKeys } from '@/queries/keys';
import { StoreQrPanel } from '@/features/qr/StoreQrPanel';
import { useAppCategories } from '@/queries/hooks';
interface FormState {
@@ -149,6 +150,27 @@ export function OnboardTenantPage() {
stocking the catalogue — pick products from the global catalogue, or upload the
tenant's own list as a spreadsheet.
</Text>
{/* The storefront code, at the one moment the person who provisioned
the shop is holding its details.
It was reachable only from the branch user's own header, which
is the wrong place for it: the code is what puts the store in
front of a shopper at all — nobody can order from a shop they
have not scanned — and the person onboarding it is the one who
sends it to the merchant. `createtenantuser` returns the tenant
and its primary outlet's id together, so it can be drawn here
without a second read. */}
{created?.tenantid && created?.locationid ? (
<Card padding={3} elevation="low" variant="transparent">
<StoreQrPanel
tenantid={created.tenantid}
locationid={created.locationid}
locationname={form.locationname}
where={[form.suburb, form.city].filter(Boolean).join(', ')}
/>
</Card>
) : null}
<HStack gap={1.5} wrap="wrap">
<Button
label="Stock from global catalogue"

View File

@@ -1,4 +1,4 @@
import { useMemo } from 'react';
import { useMemo, useState } from 'react';
import { Link, useParams } from 'react-router-dom';
import { Badge } from '@astryxdesign/core/Badge';
import { Button } from '@astryxdesign/core/Button';
@@ -7,7 +7,7 @@ import { HStack } from '@astryxdesign/core/HStack';
import { Table, type TableColumn } from '@astryxdesign/core/Table';
import { Text } from '@astryxdesign/core/Text';
import { VStack } from '@astryxdesign/core/VStack';
import { IndianRupee, ShoppingCart, Store, TriangleAlert } from 'lucide-react';
import { IndianRupee, QrCode, ShoppingCart, Store, TriangleAlert } from 'lucide-react';
import { DataState } from '@/components/DataState';
import { Freshness } from '@/components/Freshness';
import { KpiCard } from '@/components/KpiCard';
@@ -17,6 +17,8 @@ import { useLocationSummary, useOrderSummary, useTenantLocations, useTenants } f
import type { LocationOrderSummary, TenantInfo, TenantLocation } from '@/api/types';
import { TablePager } from '@/components/TablePager';
import { usePaged } from '@/components/usePaged';
import { Drawer } from '@/features/store-admin/Drawer';
import { StoreQrPanel } from '@/features/qr/StoreQrPanel';
interface BranchRow extends Record<string, unknown> {
locationid: number;
@@ -91,6 +93,9 @@ export function StoreDetailPage() {
return { branches, active, totalOrders, totalRevenue, cancelled };
}, [rows, orders.data]);
/** The branch whose code is on screen, if any. */
const [qrFor, setQrFor] = useState<BranchRow | null>(null);
const columns: TableColumn<BranchRow>[] = [
{
key: 'locationname',
@@ -172,6 +177,26 @@ export function StoreDetailPage() {
/>
),
},
{
/* The storefront code, per branch, after the day it was commissioned.
Shown at creation too — but a poster gets lost, a shop reopens, a
merchant asks for it again a month later, and the person they ask is
whoever is looking at this page. The code is derived from the two ids
on this row, so there is nothing to look up and nothing to reissue. */
key: 'qr',
header: 'QR',
align: 'end',
width: { type: 'pixel', value: 84 },
renderCell: (row) => (
<Button
label="QR"
variant="ghost"
size="sm"
icon={<QrCode size={14} />}
onClick={() => setQrFor(row)}
/>
),
},
];
return (
@@ -267,6 +292,22 @@ export function StoreDetailPage() {
</DataState>
</Card>
</VStack>
{qrFor && tenantid ? (
<Drawer
title="Store QR code"
subtitle={qrFor.locationname}
width={400}
onClose={() => setQrFor(null)}
>
<StoreQrPanel
tenantid={tenantid}
locationid={qrFor.locationid}
locationname={qrFor.locationname}
{...(qrFor.city ? { where: String(qrFor.city) } : {})}
/>
</Drawer>
) : null}
</VStack>
);
}