updates on the design and chatbot fix
This commit is contained in:
@@ -1428,6 +1428,7 @@ const AIPanel = ({ isOpen, onClose }) => {
|
||||
<IconButton
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
side="bottom"
|
||||
label={view === 'history' ? 'Back to conversation' : 'Conversation history'}
|
||||
tooltip={view === 'history' ? 'Back to conversation' : 'History'}
|
||||
aria-pressed={view === 'history'}
|
||||
@@ -1437,6 +1438,7 @@ const AIPanel = ({ isOpen, onClose }) => {
|
||||
<IconButton
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
side="bottom"
|
||||
label="New conversation"
|
||||
tooltip="New conversation"
|
||||
icon={<LuRotateCcw />}
|
||||
@@ -1445,6 +1447,7 @@ const AIPanel = ({ isOpen, onClose }) => {
|
||||
<IconButton
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
side="bottom"
|
||||
label={isWide ? 'Standard width (20%)' : 'Expand width (30%)'}
|
||||
tooltip={isWide ? 'Standard width (20%)' : 'Expand width (30%)'}
|
||||
aria-pressed={isWide}
|
||||
@@ -1454,6 +1457,7 @@ const AIPanel = ({ isOpen, onClose }) => {
|
||||
<IconButton
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
side="bottom"
|
||||
label="Close assistant"
|
||||
tooltip="Close assistant"
|
||||
icon={<LuX />}
|
||||
|
||||
@@ -69,7 +69,12 @@ export const CHIP_LABELS = {
|
||||
'How many tripsheets are dispatched?': 'Tripsheets',
|
||||
'How many open exceptions?': 'Open exceptions',
|
||||
'How many pricing rules are configured?': 'Pricing rules',
|
||||
"Repeat yesterday's orders": 'Repeat yesterday'
|
||||
"Repeat yesterday's orders": 'Repeat yesterday',
|
||||
'How many consignments do we have?': 'Consignments',
|
||||
'How many app users do we have?': 'App users',
|
||||
'How many partners do we have?': 'Partners',
|
||||
'How many competitor branches are tracked?': 'Competitor branches',
|
||||
'How many carriers do we have?': 'Carriers'
|
||||
};
|
||||
|
||||
// The one follow-up phrasing that is not already a page suggestion. Verified
|
||||
@@ -121,39 +126,27 @@ const ORDERS = {
|
||||
};
|
||||
|
||||
const RIDERS = {
|
||||
label: 'Riders',
|
||||
label: 'Milers',
|
||||
suggestions: [
|
||||
{ icon: LuBike, text: 'How many riders are active?' },
|
||||
{ icon: LuClock3, text: "Give me today's operations summary" },
|
||||
{ icon: LuPackage, text: 'How many orders today?' },
|
||||
{ icon: LuTruck, text: 'How many vehicles are available?' }
|
||||
{ icon: LuUserPlus, text: 'Assign a rider' }
|
||||
],
|
||||
more: [
|
||||
{ icon: LuBuilding2, text: 'Current hub status' },
|
||||
{ icon: LuBanknote, text: 'Total revenue today' }
|
||||
]
|
||||
more: []
|
||||
};
|
||||
|
||||
const VEHICLES = {
|
||||
label: 'Vehicles',
|
||||
suggestions: [
|
||||
{ icon: LuTruck, text: 'How many vehicles are available?' },
|
||||
{ icon: LuBike, text: 'How many riders are active?' },
|
||||
{ icon: LuBuilding2, text: 'Current hub status' },
|
||||
{ icon: LuClock3, text: "Give me today's operations summary" }
|
||||
],
|
||||
more: [{ icon: LuPackage, text: 'How many orders today?' }]
|
||||
suggestions: [{ icon: LuTruck, text: 'How many vehicles are available?' }],
|
||||
more: []
|
||||
};
|
||||
|
||||
const HUBS = {
|
||||
label: 'Hubs',
|
||||
suggestions: [
|
||||
{ icon: LuBuilding2, text: 'Current hub status' },
|
||||
{ icon: LuTimerOff, text: 'Which hubs are experiencing delays?' },
|
||||
{ icon: LuTruck, text: 'How many vehicles are available?' },
|
||||
{ icon: LuBike, text: 'How many riders are active?' }
|
||||
{ icon: LuTimerOff, text: 'Which hubs are experiencing delays?' }
|
||||
],
|
||||
more: [{ icon: LuPackage, text: 'How many orders today?' }]
|
||||
more: []
|
||||
};
|
||||
|
||||
const DISPATCH = {
|
||||
@@ -162,24 +155,16 @@ const DISPATCH = {
|
||||
{ icon: LuLayers, text: 'Morning Batch orders today' },
|
||||
{ icon: LuTimerOff, text: 'Which orders are delayed?' },
|
||||
{ icon: LuBike, text: 'How many riders are active?' },
|
||||
{ icon: LuClock3, text: "Give me today's operations summary" }
|
||||
{ icon: LuUserPlus, text: 'Assign a rider' }
|
||||
],
|
||||
more: [
|
||||
{ icon: LuPackage, text: 'How many orders today?' },
|
||||
{ icon: LuCircleDot, text: 'How many pending orders today?' }
|
||||
]
|
||||
more: []
|
||||
};
|
||||
|
||||
// Linehaul and middle-mile runs.
|
||||
const TRIPSHEETS = {
|
||||
label: 'Tripsheets',
|
||||
suggestions: [
|
||||
{ icon: LuLayers, text: 'How many tripsheets are dispatched?' },
|
||||
{ icon: LuTruck, text: 'How many vehicles are available?' },
|
||||
{ icon: LuBike, text: 'How many riders are active?' },
|
||||
{ icon: LuClock3, text: "Give me today's operations summary" }
|
||||
],
|
||||
more: [{ icon: LuBuilding2, text: 'Current hub status' }]
|
||||
suggestions: [{ icon: LuLayers, text: 'How many tripsheets are dispatched?' }],
|
||||
more: []
|
||||
};
|
||||
|
||||
// The register of things that went wrong.
|
||||
@@ -187,9 +172,7 @@ const EXCEPTIONS = {
|
||||
label: 'Exceptions',
|
||||
suggestions: [
|
||||
{ icon: LuCircleDot, text: 'How many open exceptions?' },
|
||||
{ icon: LuTimerOff, text: 'Which orders are delayed?' },
|
||||
{ icon: LuTimerOff, text: 'Which hubs are experiencing delays?' },
|
||||
{ icon: LuClock3, text: "Give me today's operations summary" }
|
||||
{ icon: LuTimerOff, text: 'Which orders are delayed?' }
|
||||
],
|
||||
more: []
|
||||
};
|
||||
@@ -198,13 +181,8 @@ const EXCEPTIONS = {
|
||||
// real page and deserves its own questions like any other.
|
||||
const PRICING = {
|
||||
label: 'Pricing',
|
||||
suggestions: [
|
||||
{ icon: LuBanknote, text: 'How many pricing rules are configured?' },
|
||||
{ icon: LuBanknote, text: 'Total revenue today' },
|
||||
{ icon: LuUsers, text: 'How many tenants do we have?' },
|
||||
{ icon: LuClock3, text: "Give me today's operations summary" }
|
||||
],
|
||||
more: [{ icon: LuBanknote, text: 'Total revenue this week' }]
|
||||
suggestions: [{ icon: LuBanknote, text: 'How many pricing rules are configured?' }],
|
||||
more: []
|
||||
};
|
||||
|
||||
// Bookings — what customers raised in the app, before it becomes an order.
|
||||
@@ -227,23 +205,62 @@ const BOOKINGS = {
|
||||
suggestions: [
|
||||
{ icon: LuPackage, text: 'How many orders today?' },
|
||||
{ icon: LuCircleDot, text: 'How many pending orders today?' },
|
||||
{ icon: LuTimerOff, text: 'Which orders are delayed?' },
|
||||
{ icon: LuClock3, text: "Give me today's operations summary" }
|
||||
],
|
||||
more: [
|
||||
{ icon: LuPackage, text: 'How many delivered orders today?' },
|
||||
{ icon: LuPackage, text: 'How many cancelled orders today?' },
|
||||
{ icon: LuClock3, text: 'Orders today vs yesterday' }
|
||||
]
|
||||
{ icon: LuTimerOff, text: 'Which orders are delayed?' }
|
||||
],
|
||||
more: []
|
||||
};
|
||||
|
||||
// Deliveries — an order after it has been picked up and become a consignment.
|
||||
//
|
||||
// This page used to be `{ ...ORDERS, label: 'Deliveries' }`: the Orders
|
||||
// question set under a different name, so a table of consignments offered
|
||||
// "Create an order" and "Repeat yesterday's orders". The label made it look
|
||||
// deliberate, which is the same trap the Tripsheets/Exceptions/Pricing note
|
||||
// below describes.
|
||||
//
|
||||
// Every phrasing here is checked against its intent's own `match`:
|
||||
// consignmentStatus is /\bconsignments?\b/, parcelTrack wants a tracking
|
||||
// number, and the delivered/delayed counts are the order intents narrowed to
|
||||
// the statuses this page actually shows.
|
||||
const DELIVERIES = {
|
||||
label: 'Deliveries',
|
||||
suggestions: [
|
||||
{ icon: LuTruck, text: 'How many consignments do we have?' },
|
||||
{ icon: LuPackage, text: 'How many delivered orders today?' },
|
||||
{ icon: LuTimerOff, text: 'Which orders are delayed?' },
|
||||
{ icon: LuBike, text: 'How many riders are active?' }
|
||||
],
|
||||
more: []
|
||||
};
|
||||
|
||||
// Reference data behind the console — not an operational page, so it gets the
|
||||
// one question that is actually about it rather than the operations summary.
|
||||
const APP_USERS = {
|
||||
label: 'App users',
|
||||
suggestions: [{ icon: LuUsers, text: 'How many app users do we have?' }],
|
||||
more: []
|
||||
};
|
||||
|
||||
const COMPETITIVE_INTEL = {
|
||||
label: 'Competitive intel',
|
||||
suggestions: [
|
||||
{ icon: LuBuilding2, text: 'How many competitor branches are tracked?' },
|
||||
// NOT "how many carrier pricing rules", which is the phrasing
|
||||
// carrierPricingCount documents for itself and which never reaches it:
|
||||
// pricingCount matches /\bpricing\b/ and runs 57 lines earlier, so that
|
||||
// wording is answered with the general pricing-rule count. Its actual
|
||||
// predicate is /\bcarriers?\b/.
|
||||
{ icon: LuBanknote, text: 'How many carriers do we have?' }
|
||||
],
|
||||
more: []
|
||||
};
|
||||
|
||||
const TENANTS = {
|
||||
label: 'Tenants',
|
||||
suggestions: [
|
||||
{ icon: LuUsers, text: 'How many tenants do we have?' },
|
||||
{ icon: LuPackage, text: 'How many orders today?' },
|
||||
{ icon: LuBanknote, text: 'Total revenue today' },
|
||||
{ icon: LuClock3, text: "Give me today's operations summary" }
|
||||
{ icon: LuUsers, text: 'How many partners do we have?' }
|
||||
],
|
||||
more: []
|
||||
};
|
||||
@@ -352,7 +369,7 @@ const FOLLOW_UPS = {
|
||||
// with the wrong label.
|
||||
const ROUTES = [
|
||||
['/doormile/control-x', DISPATCH],
|
||||
['/doormile/deliveries', { ...ORDERS, label: 'Deliveries' }],
|
||||
['/doormile/deliveries', DELIVERIES],
|
||||
['/doormile/bookings', BOOKINGS],
|
||||
['/doormile/orders', ORDERS],
|
||||
['/doormile/milers', RIDERS],
|
||||
@@ -386,7 +403,11 @@ const ROUTES = [
|
||||
// so none is shadowed by the order intents that run earlier in the catalog.
|
||||
['/doormile/tripsheets', TRIPSHEETS],
|
||||
['/doormile/exceptions', EXCEPTIONS],
|
||||
['/doormile/pricing', PRICING]
|
||||
['/doormile/pricing', PRICING],
|
||||
// Missing from this list entirely until now, so both fell through to
|
||||
// DEFAULT_CONTEXT and offered rider and hub questions over their own data.
|
||||
['/doormile/app-users', APP_USERS],
|
||||
['/doormile/competitive-intel', COMPETITIVE_INTEL]
|
||||
];
|
||||
|
||||
// ---- every question, from every page ---------------------------------------
|
||||
@@ -399,7 +420,20 @@ const ROUTES = [
|
||||
//
|
||||
// `more` is retired: AIWelcome renders one flat list now, so a second array
|
||||
// would only be a second place for a question to hide.
|
||||
const ALL_CONTEXTS = [ORDERS, RIDERS, VEHICLES, HUBS, DISPATCH, TENANTS, REPORTS, DEFAULT_CONTEXT, ...ROUTES.map(([, c]) => c)];
|
||||
const ALL_CONTEXTS = [
|
||||
ORDERS,
|
||||
RIDERS,
|
||||
VEHICLES,
|
||||
HUBS,
|
||||
DISPATCH,
|
||||
DELIVERIES,
|
||||
APP_USERS,
|
||||
COMPETITIVE_INTEL,
|
||||
TENANTS,
|
||||
REPORTS,
|
||||
DEFAULT_CONTEXT,
|
||||
...ROUTES.map(([, c]) => c)
|
||||
];
|
||||
|
||||
// Every question declared anywhere. Two jobs: it is the icon index behind
|
||||
// QUESTION_BY_TEXT (so a follow-up naming a question that is no longer global
|
||||
|
||||
@@ -2090,6 +2090,30 @@ const INTENTS = [
|
||||
|
||||
const INTENTS_BY_ID = Object.fromEntries(INTENTS.map((i) => [i.id, i]));
|
||||
|
||||
// Which intent the ordered catalog reaches for a question, WITHOUT running it.
|
||||
//
|
||||
// Exported for the page-suggestion test. The catalog is ordered and the first
|
||||
// match wins, so "something matches this chip" and "the right thing matches
|
||||
// this chip" are different questions — ROADMAP.md B1/B2 are two shipped cases
|
||||
// where they had different answers.
|
||||
//
|
||||
// Covers the deterministic pass only. answerQuestion tries semantic routing
|
||||
// and the multi-part splitter ahead of this, both of which are additive: they
|
||||
// can route a question the catalog would miss, never away from one it hits.
|
||||
export const resolveIntentId = (text) => {
|
||||
const normalized = correctTypos(text);
|
||||
for (const intent of INTENTS) {
|
||||
let params = null;
|
||||
try {
|
||||
params = intent.match(normalized);
|
||||
} catch {
|
||||
params = null;
|
||||
}
|
||||
if (params) return intent.id;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export const SUPPORTED_QUESTIONS = INTENTS.map((i) => i.label);
|
||||
|
||||
// Clean, directly-askable example phrasings — for "recommended question"
|
||||
|
||||
Reference in New Issue
Block a user