my stock update page ui
This commit is contained in:
@@ -260,10 +260,17 @@ export function ProductDrawer({
|
||||
{/* ── Health score ──────────────────────────────────────────────────
|
||||
Under Sizes and above the shop detail: it is what a SHOPPER reads,
|
||||
and it belongs with the other shopper-facing facts. */}
|
||||
{/* The toggle is behind `canManage` for the same reason hiding a product
|
||||
is: it writes `products.showhealthscore`, which is per TENANT and not
|
||||
per outlet, so a branch turning a rating off would turn it off at
|
||||
every shop the business runs. Absent rather than disabled — a greyed
|
||||
switch invites "why", and the answer is that it is not a decision one
|
||||
outlet makes. The panel itself still renders: a branch user sees what
|
||||
a customer sees, they just cannot change it. */}
|
||||
<HealthScorePanel
|
||||
product={product}
|
||||
category={product.categoryname || product.Subcategoryname}
|
||||
{...(product.tenantid && product.productid
|
||||
{...(canManage && product.tenantid && product.productid
|
||||
? { onToggleShown: (show: boolean) => showScore.mutate(show) }
|
||||
: {})}
|
||||
/>
|
||||
|
||||
@@ -227,14 +227,14 @@ function RequestsPanel({
|
||||
};
|
||||
|
||||
const decide = useMutation({
|
||||
mutationFn: ({ requestid, action }: { requestid: number; action: 'approve' | 'reject' | 'arrive' }) =>
|
||||
action === 'approve'
|
||||
? stockApi.approve(requestid)
|
||||
: action === 'arrive'
|
||||
? stockApi.confirmArrival(requestid)
|
||||
: stockApi.reject(requestid),
|
||||
/* No 'arrive' here. Confirming arrival writes stock onto a branch's
|
||||
shelf and belongs to the branch — see the row actions below. Narrowing
|
||||
the type rather than leaving the branch unreachable, so a future caller
|
||||
cannot quietly reintroduce it from this screen. */
|
||||
mutationFn: ({ requestid, action }: { requestid: number; action: 'approve' | 'reject' }) =>
|
||||
action === 'approve' ? stockApi.approve(requestid) : stockApi.reject(requestid),
|
||||
onSuccess: (_data, { action }) => {
|
||||
const verb = action === 'approve' ? 'approved' : action === 'arrive' ? 'confirmed as arrived' : 'rejected';
|
||||
const verb = action === 'approve' ? 'approved' : 'rejected';
|
||||
setOutcome(`Request ${verb}.`);
|
||||
},
|
||||
onError: () => {
|
||||
@@ -292,26 +292,14 @@ function RequestsPanel({
|
||||
[requests, selection],
|
||||
);
|
||||
|
||||
const selectedInTransit = useMemo(
|
||||
() =>
|
||||
requests
|
||||
.filter((r) => selection.has(r.requestid) && r.status === 'Approved')
|
||||
.map((r) => r.requestid),
|
||||
[requests, selection],
|
||||
);
|
||||
|
||||
const decideBatch = useMutation({
|
||||
mutationFn: ({ ids, action }: { ids: number[]; action: 'approve' | 'reject' | 'arrive' }) =>
|
||||
action === 'approve'
|
||||
? stockApi.approveMany(ids)
|
||||
: action === 'arrive'
|
||||
? stockApi.confirmArrivalMany(ids)
|
||||
: stockApi.rejectMany(ids),
|
||||
mutationFn: ({ ids, action }: { ids: number[]; action: 'approve' | 'reject' }) =>
|
||||
action === 'approve' ? stockApi.approveMany(ids) : stockApi.rejectMany(ids),
|
||||
onSuccess: (result, { ids, action }) => {
|
||||
const done = result?.updated?.length ?? ids.length;
|
||||
const failed = result?.failed?.length ?? 0;
|
||||
const verb =
|
||||
action === 'approve' ? 'approved' : action === 'arrive' ? 'added to shelf' : 'rejected';
|
||||
const verb = action === 'approve' ? 'approved' : 'rejected';
|
||||
setOutcome(
|
||||
failed === 0
|
||||
? `${count(done)} request${done === 1 ? '' : 's'} ${verb}.`
|
||||
@@ -490,21 +478,11 @@ function RequestsPanel({
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
{selectedInTransit.length > 0 ? (
|
||||
<Button
|
||||
label={
|
||||
decideBatch.isPending
|
||||
? 'Working…'
|
||||
: `Confirm arrival of ${count(selectedInTransit.length)}`
|
||||
}
|
||||
variant="primary"
|
||||
size="sm"
|
||||
icon={<CheckCheck size={14} />}
|
||||
isLoading={decideBatch.isPending}
|
||||
isDisabled={decideBatch.isPending}
|
||||
onClick={() => decideBatch.mutate({ ids: selectedInTransit, action: 'arrive' })}
|
||||
/>
|
||||
) : null}
|
||||
{/* No bulk "confirm arrival" either, for the same reason as
|
||||
the row action: the stock is written when the BRANCH says
|
||||
the goods arrived, and an admin confirming forty deliveries
|
||||
they never saw is the version of this that puts stock on a
|
||||
shelf that is empty. */}
|
||||
</HStack>
|
||||
</HStack>
|
||||
</div>
|
||||
@@ -710,19 +688,20 @@ function RequestsPanel({
|
||||
/>
|
||||
</HStack>
|
||||
) : request.status === 'Approved' ? (
|
||||
<Button
|
||||
label="Confirm arrival"
|
||||
variant="primary"
|
||||
size="sm"
|
||||
style={{ height: 28, padding: '0 10px', fontSize: 12 }}
|
||||
icon={<CheckCheck size={13} />}
|
||||
isDisabled={decide.isPending && isActing}
|
||||
isLoading={decide.isPending && isActing}
|
||||
onClick={() => {
|
||||
setActing(request.requestid);
|
||||
decide.mutate({ requestid: request.requestid, action: 'arrive' });
|
||||
}}
|
||||
/>
|
||||
/* No action here, deliberately.
|
||||
|
||||
Confirming arrival is what WRITES THE STOCK onto
|
||||
a branch's shelf, and only the branch can know
|
||||
the goods actually turned up. For the admin this
|
||||
row is an acknowledgement — they agreed to send
|
||||
it — so the status is shown and nothing is
|
||||
offered. The control lives on the Store user's
|
||||
own products screen.
|
||||
|
||||
Absent rather than disabled: a greyed button
|
||||
invites "why", and the answer is that it is not
|
||||
this person's call. */
|
||||
null
|
||||
) : (
|
||||
<span style={{ fontSize: 12, color: 'var(--color-ink-4)' }}>
|
||||
{request.status === 'Received' ? 'Completed' : 'Declined'}
|
||||
|
||||
Reference in New Issue
Block a user