updates on the ai bot and assigned by chatbot

This commit is contained in:
2026-08-20 12:00:12 +05:30
parent 37ca2352e2
commit e1cc874218
17 changed files with 794 additions and 248 deletions

View File

@@ -59,122 +59,39 @@
}
/* --------------------------------------------------------------------------
Stage indicator
--------------------------------------------------------------------------
The layout rules below are NOT scoped under .co-root. Only theming needs
the scope; structure must survive it. When `co-root` was being dropped by
PageShell (it didn't forward className), every scoped rule failed silently
and the chips rendered as run-together plain text — "1Pickup & Drop2Schedule".
Keeping layout unscoped means the worst case is unthemed, not unreadable.
Header picker — tenant / business-location control that sits opposite the
title block. One fixed-width slot shared by every state (loading, error,
badge, dropdown) so the control never changes size or drifts out of
vertical alignment with the title as `locationsStatus` changes.
-------------------------------------------------------------------------- */
.co-steps {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 6px;
margin-bottom: 20px;
.co-header-picker {
min-width: 280px;
max-width: 320px;
flex: 0 1 auto;
/* Pins the picker to the far right of the header row even when the row
wraps — a single child on a wrapped flex line sits at flex-start under
justify-content: space-between, so margin-left: auto is what actually
keeps it flush right in that case. */
margin-left: auto;
}
.co-step {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 6px 11px;
border: 1px solid var(--co-border);
border-radius: 999px;
background: var(--co-surface);
font-size: 12.5px;
font-weight: 500;
color: var(--co-text-3);
white-space: nowrap;
}
.co-root .co-step[data-state='active'] {
color: var(--co-brand);
border-color: color-mix(in srgb, var(--co-brand) 35%, transparent);
background: color-mix(in srgb, var(--co-brand) 6%, #fff);
}
.co-root .co-step[data-state='done'] {
color: var(--co-pickup);
border-color: color-mix(in srgb, var(--co-pickup) 30%, transparent);
background: color-mix(in srgb, var(--co-pickup) 6%, #fff);
}
.co-step-num {
display: inline-flex;
align-items: center;
justify-content: center;
width: 17px;
height: 17px;
border-radius: 999px;
font-size: 10.5px;
.co-root .co-header-picker-label {
font-size: 11px;
font-weight: 600;
background: currentColor;
color: #fff;
letter-spacing: 0.02em;
text-transform: uppercase;
color: var(--co-text-3);
}
.co-root .co-step[data-state='done'] .co-step-num::after {
content: '✓';
}
.co-step-sep {
flex: 0 0 auto;
width: 14px;
height: 1px;
background: var(--co-border);
}
/* --------------------------------------------------------------------------
Journey — Pickup ●───→● Drop
-------------------------------------------------------------------------- */
.co-journey {
.co-root .co-header-picker-status {
display: flex;
align-items: center;
gap: 10px;
padding: 9px 13px;
margin-bottom: 14px;
min-height: 38px;
padding: 8px 12px;
border: 1px solid var(--co-border);
border-radius: var(--co-radius);
background: var(--co-surface);
font-size: 12.5px;
color: var(--co-text-2);
overflow: hidden;
}
.co-journey-dot {
flex: 0 0 auto;
width: 9px;
height: 9px;
border-radius: 999px;
}
.co-root .co-journey-dot[data-end='pickup'] {
background: var(--co-pickup);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--co-pickup) 18%, transparent);
}
.co-root .co-journey-dot[data-end='drop'] {
background: var(--co-drop);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--co-drop) 18%, transparent);
}
.co-journey-line {
flex: 1 1 auto;
min-width: 24px;
height: 1px;
background: linear-gradient(90deg, var(--co-pickup), var(--co-drop));
opacity: 0.5;
}
.co-journey-label {
flex: 0 1 auto;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-weight: 500;
color: var(--co-text);
box-sizing: border-box;
}
/* --------------------------------------------------------------------------
@@ -251,12 +168,23 @@
color: var(--co-text-3);
}
/* --------------------------------------------------------------------------
Sticky order summary (desktop only)
-------------------------------------------------------------------------- */
.co-root .co-summary {
position: sticky;
top: calc(var(--appshell-header-height, 64px) + 12px);
/* Pickup/drop dot — shared by the order-summary legs below. */
.co-journey-dot {
flex: 0 0 auto;
width: 9px;
height: 9px;
margin-top: 4px;
border-radius: 999px;
}
.co-root .co-journey-dot[data-end='pickup'] {
background: var(--co-pickup);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--co-pickup) 18%, transparent);
}
.co-root .co-journey-dot[data-end='drop'] {
background: var(--co-drop);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--co-drop) 18%, transparent);
}
.co-root .co-summary-leg {
@@ -291,12 +219,6 @@
/* --------------------------------------------------------------------------
Responsive
-------------------------------------------------------------------------- */
@media (max-width: 1023px) {
.co-root .co-summary {
position: static;
}
}
@media (max-width: 640px) {
.co-root .co-title {
font-size: 20px;
@@ -306,19 +228,9 @@
gap: 10px;
}
.co-root .co-steps {
gap: 4px;
}
.co-root .co-step {
padding: 5px 9px;
font-size: 11.5px;
}
/* The step separators are decoration; drop them before the chips wrap
awkwardly on a 360px screen. */
.co-root .co-step-sep {
display: none;
.co-header-picker {
min-width: 0;
width: 100%;
}
}

View File

@@ -647,7 +647,7 @@ const Createorder1 = () => {
<PageShell className="co-root">
<VStack className="co-header" gap={0} padding={0}>
<HStack justify="between" vAlign="start" gap={2} wrap="wrap" padding={0}>
<HStack justify="between" vAlign="center" gap={3} wrap="wrap" padding={0}>
<HStack gap={2} vAlign="center" padding={0}>
<AccentAvatar color={BRAND} selected size={40}>
<MdAddShoppingCart size={20} />
@@ -658,17 +658,24 @@ const Createorder1 = () => {
</VStack>
</HStack>
{/* One fixed-width, consistently-labelled slot for whichever
picker state is active, so the control never jumps width or
loses vertical alignment with the title block as it switches
between loading / error / badge / dropdown. */}
{locationsStatus === 'loading' ? (
<Text color="secondary" weight="bold">
Loading business locations…
</Text>
<div className="co-header-picker co-header-picker-status">
<Text color="secondary" weight="bold">
Loading business locations…
</Text>
</div>
) : locationsStatus === 'no-tenant' && isStaffLogin ? (
// Staff login (express-console-api.md: token tenantid 0/null
// = "Doormile's own staff... sees everything, all tenants")
// — pick which tenant to create this order for. Everything
// downstream (pricing, saved locations, the booking's own
// tenantid) is keyed off `tid`, which equals selectedTenantId.
<div style={{ minWidth: 260 }}>
<VStack className="co-header-picker" gap={0.5} padding={0}>
<Text className="co-header-picker-label">Tenant</Text>
<Selector
label="Tenant"
isLabelHidden
@@ -679,23 +686,44 @@ const Createorder1 = () => {
isLoading={staffTenantListLoading}
hasSearch
/>
</div>
</VStack>
) : locationsStatus === 'no-tenant' ? (
<Text style={{ color: '#b91c1c' }} weight="bold">
This login has no tenant assigned — sign in as a tenant user
</Text>
<div className="co-header-picker co-header-picker-status">
<Text style={{ color: '#b91c1c' }} weight="bold">
This login has no tenant assigned — sign in as a tenant user
</Text>
</div>
) : locationsStatus === 'error' ? (
<Text style={{ color: '#b91c1c', cursor: 'pointer' }} weight="bold" onClick={gettenantlocations}>
Could not load business locations — tap to retry
</Text>
<div
className="co-header-picker co-header-picker-status"
role="button"
tabIndex={0}
onClick={gettenantlocations}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
gettenantlocations();
}
}}
>
<Text style={{ color: '#b91c1c', cursor: 'pointer' }} weight="bold">
Could not load business locations — tap to retry
</Text>
</div>
) : locationsStatus === 'empty' ? (
<Text style={{ color: '#b45309' }} weight="bold">
No saved locations — enter pickup details manually below
</Text>
<div className="co-header-picker co-header-picker-status">
<Text style={{ color: '#b45309' }} weight="bold">
No saved locations — enter pickup details manually below
</Text>
</div>
) : tenantLocations.length === 1 ? (
<Badge variant="neutral" icon={<MdMyLocation size={14} />} label={locationDisplayName(tenantLocations[0])} />
<VStack className="co-header-picker" gap={0.5} padding={0}>
<Text className="co-header-picker-label">Business Location</Text>
<Badge variant="neutral" icon={<MdMyLocation size={14} />} label={locationDisplayName(tenantLocations[0])} />
</VStack>
) : (
<div style={{ minWidth: 300 }}>
<VStack className="co-header-picker" gap={0.5} padding={0}>
<Text className="co-header-picker-label">Business Location</Text>
<Selector
label="Business Location"
isLabelHidden
@@ -731,50 +759,11 @@ const Createorder1 = () => {
hasSearch
hasClear
/>
</div>
</VStack>
)}
</HStack>
</VStack>
{/* Stage indicator. Derived from the form's own state rather than a
wizard step counter — the page is one scrollable form, so this
reports progress instead of gating it. */}
<HStack className="co-steps" padding={0} gap={0}>
{[
{ n: 1, label: 'Pickup & Drop', done: Boolean(pickCust.address && dropCust.address) },
{ n: 2, label: 'Schedule', done: Boolean(selectedtime) },
{ n: 3, label: 'Package', done: Boolean(category) },
{ n: 4, label: 'Review', done: showDistance && totalCharge > 0 }
].map((step, i, all) => {
const active = !step.done && all.slice(0, i).every((prev) => prev.done);
return (
<HStack key={step.n} padding={0} gap={0} vAlign="center">
{i > 0 && <span className="co-step-sep" />}
<span className="co-step" data-state={step.done ? 'done' : active ? 'active' : 'todo'}>
<span className="co-step-num">{step.done ? '' : step.n}</span>
{step.label}
</span>
</HStack>
);
})}
</HStack>
{/* The delivery journey, stated once at the top so the order's shape
is obvious before reading any field. */}
<HStack className="co-journey" padding={0} gap={0} vAlign="center">
<span className="co-journey-dot" data-end="pickup" />
<span className="co-journey-label">{pickCust.address || 'Pickup address'}</span>
<span className="co-journey-line" />
{showDistance && (
<span className="co-price-note">
{distance} km{durationMin ? ` · ${durationMin} min` : ''}
</span>
)}
<span className="co-journey-line" />
<span className="co-journey-label">{dropCust.address || 'Drop address'}</span>
<span className="co-journey-dot" data-end="drop" />
</HStack>
<Grid columns={{ minWidth: 420, repeat: 'fit' }} gap={3}>
{/* ================================================= || Pickup || ================================================= */}
<Card padding={0} elevation="none" className="co-card" data-end="pickup">
@@ -1282,9 +1271,14 @@ const Createorder1 = () => {
</Card>
{/* ============================== || Order summary || ============================== */}
{/* Sticky on desktop, static below 1024px (see CreateOrder.css). Reads
straight off form state so it updates as the operator types — there
is no second source of truth to drift from. */}
{/* A normal full-width card in the single-column form flow (not a
sidebar next to a taller column), so it stays static. It used to
carry `position: sticky`, inherited from a two-column layout this
page never actually has — with only one column, the card is the
last block on the page, so sticking it caused a visible jump/
collapse right as its own container's bottom edge scrolled into
view. Reads straight off form state so it updates as the operator
types — there is no second source of truth to drift from. */}
<Card padding={0} elevation="none" className="co-card co-summary">
<SectionHeader color="#0f172a" icon={<MdCheckCircle size={16} />} title="Order Summary" subtitle="Updates as you fill the form" />
<VStack gap={2} padding={3}>

View File

@@ -49,7 +49,7 @@ import { FaLocationDot } from 'react-icons/fa6';
import Loader from 'components/Loader';
import PageHeader from 'components/nearle_components/PageHeader';
import { PageShell } from 'components/nearle_components/PageLayout';
import { PageShell, TABLE_FRAME } from 'components/nearle_components/PageLayout';
import { DT } from 'themes/dt/tokens';
import { TableScroll } from 'themes/dt/primitives';
import './OrdersRedesign.css';
@@ -1250,7 +1250,10 @@ const MultipleOrders = () => {
</VStack>
{/* RIGHT — file / drop preview */}
<Card padding={2} elevation="none" style={{ display: 'flex', flexDirection: 'column' }}>
{/* Same frame as every DataCard table — this preview holds a table but
predates DataCard, so it states the shared constant rather than
carrying a second definition of it. */}
<Card padding={2} elevation="none" style={{ border: TABLE_FRAME, display: 'flex', flexDirection: 'column' }}>
<HStack justify="between" vAlign="center" gap={1} wrap="wrap" style={{ marginBottom: 8 }}>
<HStack gap={2} vAlign="center">
<Text weight="bold">{previewMode === 'drops' ? 'Drop List' : previewMode === 'preview' ? 'File Preview' : 'Preview'}</Text>