@gymmymac/bob-widget 3.1.19 โ 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +46 -0
- package/README.md +435 -38
- package/bin/bob-widget.mjs +1 -1
- package/dist/__tests__/Bob.callbacks.test.d.ts +10 -0
- package/dist/__tests__/bundleDiscount.test.d.ts +7 -0
- package/dist/__tests__/pttLongPress.test.d.ts +13 -0
- package/dist/__tests__/rearBrakeFilter.test.d.ts +7 -0
- package/dist/components/ProductTile.d.ts +4 -5
- package/dist/index.js +34 -34
- package/dist/index.mjs +4738 -4411
- package/dist/style.css +1 -1
- package/dist/types/product.d.ts +9 -0
- package/dist/utils/rearBrakeFilter.d.ts +15 -0
- package/install/carfix/CARFIX-INSTALLATION-BRIEF.md +367 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,49 @@ All notable changes to the `@gymmymac/bob-widget` package will be documented in
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [v3.2.1] - 2026-02-15
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- ๐ **Auto-Scroll to Highlighted Category**: Mobile/tablet product shelf now auto-scrolls to the matching partslot group when Bob mentions a specific part type (e.g. "front pads"), bringing parity with desktop behaviour
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- ๐ข **PTT Idle Button Colour**: Changed from blue to green to match the breathing idle ring
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## [v3.2.0] - 2026-02-15
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
- ๐ฏ **PTT 4-State Visual Feedback**: Push-to-Talk button now provides visual cues via circumference rings and chat bar overlays across four states (idle, listening, processing, speaking)
|
|
22
|
+
- ๐ข **Green Idle PTT**: Idle state uses green button and breathing green ring to indicate "action required"
|
|
23
|
+
- ๐ **Orange Listening State**: Expanding orange wave rings around PTT + pulsing dot in chat bar
|
|
24
|
+
- โ๏ธ **Processing Overlay**: Grey contracting ring + "Bob is researching your input." message in chat bar
|
|
25
|
+
- ๐ **Speaking Waveform**: Green glowing ring + 5-bar CSS waveform visualizer in chat bar with muted warning icon
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
- ๐จ **Chat Bar**: White background (#FFFFFF) with Deep Navy text (#0F172A) for high contrast โ enforced via `!important` overrides to prevent host-site bleeding
|
|
29
|
+
- ๐ค **Processing Text**: Changed from "Bob is thinking..." to "Bob is researching your input."
|
|
30
|
+
- ๐ข **PTT Button Colour**: Idle state changed from blue to green to match the idle ring
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
- ๐จ **Chat Bar Dark Blue Override**: Fixed `widget-reset.css` forcing dark blue background on inputs โ now forces white
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## [3.1.20] - 2026-02-13
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
- ๐ฆ **CARFIX Installation Brief**: README.md now serves as the comprehensive installation document with full container preparation requirements, anti-patterns table, pre-mount checklist, and layout diagram
|
|
41
|
+
- ๐งช **Quality Baseline Tests**: 36 unit tests locked in across rear brake filter, bundle discount pricing, and callback stability
|
|
42
|
+
- ๐ฐ **Bundle Discount Display**: Was/Now pricing with savings badges for service package tiers when `savingsAmount > 0`
|
|
43
|
+
- ๐ **Bundle Cart Metadata**: Cart items from service packages now include `is_bundle_item`, `bundle_discount_percentage`, `service_package_name`, and `quality_tier`
|
|
44
|
+
|
|
45
|
+
### Changed
|
|
46
|
+
- ๐ **README Overhaul**: Full installation brief is now front-and-center โ visible on npm, GitHub, and in `node_modules`
|
|
47
|
+
- ๐ **Container Anti-Patterns**: Documented all prohibited CSS properties (`overflow: hidden`, `transform`, etc.) that break Bob's layering
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
8
51
|
## [3.1.19] - 2026-02-04
|
|
9
52
|
|
|
10
53
|
### Added
|
|
@@ -15,6 +58,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
15
58
|
- ๐ข **Speech Count Alignment**: Bob's spoken variant count now matches the deduplicated UI cards shown on screen
|
|
16
59
|
- ๐ด **Variant Card Display**: Cards now show specs-first format without characterization text
|
|
17
60
|
|
|
61
|
+
### Documentation
|
|
62
|
+
- ๐ **bottomOffset Clarification**: `bottomOffset` prop only applies to fixed-position variants. Contained/embedded variants position relative to their container (which should already be sized to fit between header/footer).
|
|
63
|
+
|
|
18
64
|
---
|
|
19
65
|
|
|
20
66
|
## [3.1.18] - 2026-01-28
|
package/README.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# @gymmymac/bob-widget
|
|
2
2
|
|
|
3
|
-
AI-powered automotive parts assistant widget for
|
|
3
|
+
AI-powered automotive parts assistant widget for partner websites.
|
|
4
4
|
|
|
5
|
-
**Current Version:**
|
|
5
|
+
**Current Version:** v3.2.1 | **36 unit tests** | **8+ E2E scenarios** | Production-ready
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
## ๐จ STOP
|
|
9
|
+
## ๐จ STOP โ RUN THE INSTALLER FIRST
|
|
10
10
|
|
|
11
11
|
Bob v3.1.19 includes an **executable 3-stage installer**. Do NOT skip this step.
|
|
12
12
|
|
|
@@ -21,63 +21,460 @@ npx @gymmymac/bob-widget carfix stage-b --target next-pages --output pages/ask-b
|
|
|
21
21
|
npx @gymmymac/bob-widget carfix stage-c --partner CARFIX
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
---
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|----------|-------------|
|
|
28
|
-
| **[BOB-DOCUMENTATION.md](./BOB-DOCUMENTATION.md)** | **Complete integration guide** - Contains CARFIX-specific installation steps, container height calculations, and verification tests. **START HERE.** |
|
|
29
|
-
| **[CHANGELOG.md](./CHANGELOG.md)** | Version history and release notes |
|
|
30
|
-
| **[install/carfix/](./install/carfix/)** | Installer scripts and templates |
|
|
26
|
+
## 1. Peer Dependencies
|
|
31
27
|
|
|
32
|
-
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"react": "^18.0.0",
|
|
32
|
+
"react-dom": "^18.0.0"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
```
|
|
33
36
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
3. **HTTPS Required**: Push-to-Talk (PTT) requires HTTPS - will be disabled on HTTP connections
|
|
37
|
-
4. **No Background Blur**: v3.1.10 removes hardcoded blur - background is crisp by default
|
|
37
|
+
> `@supabase/supabase-js` and `@tanstack/react-query` are bundled โ no action needed.
|
|
38
|
+
> If CARFIX already uses `@tanstack/react-query`, ensure v5+ compatibility.
|
|
38
39
|
|
|
39
40
|
---
|
|
40
41
|
|
|
41
|
-
##
|
|
42
|
-
|
|
43
|
-
After completing the 3-stage installation:
|
|
42
|
+
## 2. Minimal Integration (4 Lines)
|
|
44
43
|
|
|
45
44
|
```tsx
|
|
46
45
|
import { BobStandalone } from '@gymmymac/bob-widget';
|
|
47
46
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
sessionToken=
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
47
|
+
function AskBobPage() {
|
|
48
|
+
const router = useRouter();
|
|
49
|
+
const sessionToken = router.query.session as string;
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<div style={{
|
|
53
|
+
height: 'calc(100dvh - 144px - env(safe-area-inset-bottom, 0px))',
|
|
54
|
+
position: 'relative',
|
|
55
|
+
/* DO NOT use overflow: hidden โ clips PTT button and chat drawer */
|
|
56
|
+
}}>
|
|
57
|
+
<BobStandalone
|
|
58
|
+
partner="CARFIX"
|
|
59
|
+
sessionToken={sessionToken}
|
|
60
|
+
bottomOffset={0}
|
|
61
|
+
zIndexBase={100}
|
|
62
|
+
onAddToCart={async (item) => await carfixCart.add(item)}
|
|
63
|
+
onNavigate={(url) => router.push(url)}
|
|
64
|
+
onCheckout={(checkoutUrl) => window.location.href = checkoutUrl}
|
|
65
|
+
onError={(error) => console.error('[Bob Error]', error)}
|
|
66
|
+
/>
|
|
67
|
+
</div>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
> **Auto-configuration:** `partner="CARFIX"` loads all API URLs, credentials, layout defaults, and feature flags from the `bob_partners` database table. No manual config needed.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 3. CARFIX API Configuration (Already in Database)
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"baseUrl": "https://flpzjbasdsfwoeruyxgp.supabase.co/functions/v1",
|
|
81
|
+
"apiKey": "(anon key โ auto-loaded)",
|
|
82
|
+
"partnerCode": "CARFIX"
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Available Endpoints
|
|
87
|
+
|
|
88
|
+
| Endpoint | Purpose |
|
|
89
|
+
|---|---|
|
|
90
|
+
| `partner-api` | Session creation, cart, user context, orders |
|
|
91
|
+
| `calculate-service-bundles` | Service packs with `preparedTiers[]` (incl. bundle discounts) |
|
|
92
|
+
| `retrieve-vehicle-info` | NZ rego lookup |
|
|
93
|
+
| `retrieve-parts` | Vehicle parts by category |
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## 4. Host Container Preparation (MANDATORY)
|
|
98
|
+
|
|
99
|
+
> โ ๏ธ **Bob will not render correctly if the host container is misconfigured.** Complete ALL items below before mounting `<BobStandalone>`.
|
|
100
|
+
|
|
101
|
+
### 4.1 Container Requirements
|
|
102
|
+
|
|
103
|
+
The CARFIX page that hosts Bob **must** provide a container element with these exact properties:
|
|
104
|
+
|
|
105
|
+
```css
|
|
106
|
+
/* The Bob container โ EVERY property is required */
|
|
107
|
+
.bob-container {
|
|
108
|
+
height: calc(100dvh - 144px - env(safe-area-inset-bottom, 0px));
|
|
109
|
+
position: relative;
|
|
110
|
+
width: 100%;
|
|
111
|
+
|
|
112
|
+
/* โ PROHIBITED โ these WILL break Bob */
|
|
113
|
+
/* overflow: hidden; โ Clips PTT button, chat drawer, and expand handle */
|
|
114
|
+
/* overflow: clip; โ Same issue on WebKit */
|
|
115
|
+
/* overflow: auto; โ Creates nested scroll context, breaks shelf scrolling */
|
|
116
|
+
/* overflow: scroll; โ Same as above */
|
|
117
|
+
/* transform: ...; โ Creates new stacking context, breaks z-index layering */
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
// โ
Correct JSX
|
|
123
|
+
<div style={{
|
|
124
|
+
height: 'calc(100dvh - 144px - env(safe-area-inset-bottom, 0px))',
|
|
125
|
+
position: 'relative',
|
|
126
|
+
width: '100%',
|
|
127
|
+
}}>
|
|
128
|
+
<BobStandalone partner="CARFIX" ... />
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
// โ WRONG โ overflow hidden clips Bob's interactive elements
|
|
132
|
+
<div style={{ height: '100%', overflow: 'hidden' }}>
|
|
133
|
+
<BobStandalone partner="CARFIX" ... />
|
|
134
|
+
</div>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### 4.2 Height Calculation Breakdown
|
|
138
|
+
|
|
139
|
+
| Component | Height | Notes |
|
|
140
|
+
|---|---|---|
|
|
141
|
+
| CARFIX Header | 72px | `position: fixed; top: 0; z-index: 40` |
|
|
142
|
+
| CARFIX Bottom Nav | 72px | `position: fixed; bottom: 0; z-index: 30` |
|
|
143
|
+
| **Total chrome** | **144px** | Subtracted from viewport |
|
|
144
|
+
| Safe area inset | Variable | For notched devices (iPhone, etc.) |
|
|
145
|
+
| **Bob container** | `100dvh - 144px - safe-area` | Everything between header and nav |
|
|
146
|
+
|
|
147
|
+
### 4.3 Header & Bottom Nav Requirements
|
|
148
|
+
|
|
149
|
+
Bob's UI layers (chat drawer at z-130, PTT at z-145) must sit **above** CARFIX navigation:
|
|
150
|
+
|
|
151
|
+
```css
|
|
152
|
+
/* CARFIX Header */
|
|
153
|
+
.carfix-header {
|
|
154
|
+
position: fixed;
|
|
155
|
+
top: 0;
|
|
156
|
+
left: 0;
|
|
157
|
+
right: 0;
|
|
158
|
+
height: 72px;
|
|
159
|
+
z-index: 40; /* Bob uses zIndexBase=100, so Bob layers above this */
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* CARFIX Bottom Nav */
|
|
163
|
+
.carfix-bottom-nav {
|
|
164
|
+
position: fixed;
|
|
165
|
+
bottom: 0;
|
|
166
|
+
left: 0;
|
|
167
|
+
right: 0;
|
|
168
|
+
height: 72px;
|
|
169
|
+
z-index: 30; /* Must be BELOW Bob's z-base of 100 */
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
> **If your header or nav use `z-index: 50` or higher**, increase Bob's `zIndexBase` prop accordingly (e.g., `zIndexBase={150}`).
|
|
174
|
+
|
|
175
|
+
### 4.4 Container Anti-Patterns (WILL CAUSE BUGS)
|
|
176
|
+
|
|
177
|
+
| โ Don't Do This | Why It Breaks |
|
|
178
|
+
|---|---|
|
|
179
|
+
| `overflow: hidden` on container | Clips PTT button, chat drawer, and expand handle |
|
|
180
|
+
| `overflow: auto/scroll` on container | Creates nested scroll context โ product shelf scroll breaks |
|
|
181
|
+
| `transform` on container or ancestors | Creates new stacking context โ z-index layering fails |
|
|
182
|
+
| `isolation: isolate` on container | Same stacking context issue (Bob manages its own isolation) |
|
|
183
|
+
| Container height as `%` without parent height | Bob collapses to 0px |
|
|
184
|
+
| Missing `position: relative` | Absolutely-positioned Bob layers escape the container |
|
|
185
|
+
| Wrapping Bob in a scrollable parent | Bob has its own scroll management โ nesting causes conflicts |
|
|
186
|
+
|
|
187
|
+
### 4.5 Pre-Mount Checklist
|
|
188
|
+
|
|
189
|
+
Before writing any integration code, verify:
|
|
190
|
+
|
|
191
|
+
```
|
|
192
|
+
โก Header is position: fixed, 72px tall, z-index โค 49
|
|
193
|
+
โก Bottom nav is position: fixed, 72px tall, z-index โค 49
|
|
194
|
+
โก Bob container uses calc(100dvh - 144px - env(safe-area-inset-bottom, 0px))
|
|
195
|
+
โก Bob container has position: relative
|
|
196
|
+
โก Bob container has NO overflow property set
|
|
197
|
+
โก Bob container has NO transform property set
|
|
198
|
+
โก No ancestor element between <body> and Bob container has overflow: hidden
|
|
199
|
+
โก No ancestor element has a transform that creates a stacking context
|
|
200
|
+
โก Container renders at correct height (inspect element in DevTools)
|
|
201
|
+
โก HTTPS is enabled (required for Push-to-Talk microphone access)
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
### 4.6 Layout Diagram
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
210
|
+
โ CARFIX Header (72px, z-40) โ โ position: fixed; top: 0
|
|
211
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
|
|
212
|
+
โ โ
|
|
213
|
+
โ Bob Container โ โ position: relative
|
|
214
|
+
โ height: calc(100dvh - 144px โ NO overflow property
|
|
215
|
+
โ - safe-area-inset) โ NO transform property
|
|
216
|
+
โ โ
|
|
217
|
+
โ โโ Bob Internal Layers โโโโ โ
|
|
218
|
+
โ โ PTT Button z-145 โ โ
|
|
219
|
+
โ โ Chat Drawer z-130 โ โ
|
|
220
|
+
โ โ Counter Overlay z-70 โ โ
|
|
221
|
+
โ โ Bob Character z-60 โ โ
|
|
222
|
+
โ โ Product Shelf z-55 โ โ
|
|
223
|
+
โ โ Backdrop z-10 โ โ
|
|
224
|
+
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
|
|
225
|
+
โ โ
|
|
226
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
|
|
227
|
+
โ Bottom Nav (72px, z-30) โ โ position: fixed; bottom: 0
|
|
228
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
**Bob's internal z-index stack (relative to `zIndexBase={100}`):**
|
|
232
|
+
|
|
233
|
+
| Layer | z-index |
|
|
234
|
+
|---|---|
|
|
235
|
+
| Chat PTT Button | 145 |
|
|
236
|
+
| Chat Drawer | 130 |
|
|
237
|
+
| Counter Overlay | 70 |
|
|
238
|
+
| Bob Character | 60 |
|
|
239
|
+
| Product Shelf | 55 |
|
|
240
|
+
| Backdrop | 10 |
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## 5. Callback Signatures
|
|
245
|
+
|
|
246
|
+
### onAddToCart
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
onAddToCart: (item: {
|
|
250
|
+
product_id: string;
|
|
251
|
+
product_name: string;
|
|
252
|
+
quantity: number;
|
|
253
|
+
unit_price: number; // Final price (discount already applied for bundle items)
|
|
254
|
+
sku?: string;
|
|
255
|
+
brand?: string;
|
|
256
|
+
image_url?: string;
|
|
257
|
+
vehicle_id?: string;
|
|
258
|
+
// Bundle metadata (present when item is part of a service package)
|
|
259
|
+
is_bundle_item?: boolean;
|
|
260
|
+
bundle_discount_percentage?: number;
|
|
261
|
+
service_package_name?: string;
|
|
262
|
+
service_package_id?: string;
|
|
263
|
+
quality_tier?: string; // "Economy" | "Standard" | "Premium" | "Performance"
|
|
264
|
+
}) => Promise<void> | void;
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### onNavigate
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
onNavigate: (url: string) => void;
|
|
271
|
+
// Example urls: "/product/SKU123", "/checkout"
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### onCheckout
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
onCheckout: (checkoutUrl: string) => void;
|
|
278
|
+
// checkoutUrl is a full Stripe payment URL
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### onError
|
|
282
|
+
|
|
283
|
+
```typescript
|
|
284
|
+
onError: (error: Error) => void;
|
|
285
|
+
// Bob shows toast by default โ this is for host-side logging
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## 6. Bundle Discount Fields (NEW)
|
|
291
|
+
|
|
292
|
+
The `calculate-service-bundles` API returns these fields per `PreparedTier`:
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
interface PreparedTier {
|
|
296
|
+
tierName: string; // "Economy" | "Standard" | "Premium" | "Performance"
|
|
297
|
+
displayName: string;
|
|
298
|
+
description: string;
|
|
299
|
+
isRecommended: boolean; // true = CARFIX Value tier
|
|
300
|
+
isHidden: boolean; // true = filter out (duplicate price)
|
|
301
|
+
|
|
302
|
+
// Pricing (pre-calculated by API โ never recompute)
|
|
303
|
+
totalPrice: number; // Discounted bundle price
|
|
304
|
+
originalTotalPrice?: number; // Full price before discount
|
|
305
|
+
savingsAmount?: number; // Dollar savings
|
|
306
|
+
bundleDiscountPercentage?: number; // Discount % (0โ50)
|
|
307
|
+
|
|
308
|
+
productCount: number;
|
|
309
|
+
dominantBrand: string | null;
|
|
310
|
+
brands: PreparedTierBrand[];
|
|
311
|
+
products: PreparedTierProduct[];
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
interface PreparedTierProduct {
|
|
315
|
+
partslotId: number;
|
|
316
|
+
partslotName: string; // "BRAKE PADS FRONT"
|
|
317
|
+
sku: string;
|
|
318
|
+
name: string;
|
|
319
|
+
brand: string;
|
|
320
|
+
brandFullName: string;
|
|
321
|
+
brandImageUrl: string; // Full URL โ use directly in <img>
|
|
322
|
+
productImageUrl: string; // Full URL โ use directly in <img>
|
|
323
|
+
price: number; // Legacy unit price
|
|
324
|
+
unitPrice: number; // Per-unit price
|
|
325
|
+
displayPrice: number; // Total (unitPrice ร perCarQty) โ USE THIS
|
|
326
|
+
isRotor: boolean; // Show "[Pair]" badge
|
|
327
|
+
isMultiQty: boolean; // Show quantity breakdown (e.g. spark plugs)
|
|
328
|
+
perCarQty: number;
|
|
329
|
+
partNumber: string | null;
|
|
330
|
+
webDescription: string | null;
|
|
331
|
+
viscosity: string | null;
|
|
332
|
+
volume: number | null;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
interface PreparedTierBrand {
|
|
336
|
+
name: string;
|
|
337
|
+
fullName: string;
|
|
338
|
+
imageUrl: string; // Full URL
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Rendering Rules
|
|
343
|
+
|
|
344
|
+
1. **Filter hidden tiers:** `preparedTiers.filter(t => !t.isHidden)`
|
|
345
|
+
2. **When `savingsAmount > 0`:** Show ~~$originalTotalPrice~~ โ **$totalPrice** + "SAVE $XX โ X% Bundle Deal"
|
|
346
|
+
3. **When `savingsAmount === 0`:** Show `totalPrice` normally, no discount UI
|
|
347
|
+
4. **Use `displayPrice`** for individual products (already includes quantity)
|
|
348
|
+
5. **Never calculate prices client-side** โ all values arrive pre-calculated
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
## 7. Session Handoff (Pre-authenticated Users)
|
|
353
|
+
|
|
354
|
+
```
|
|
355
|
+
1. CARFIX calls partner-api: { action: "create_session", vehicle_id: 42899 }
|
|
356
|
+
โ vehicle_id MUST be a NUMBER (not string)
|
|
357
|
+
โ Returns: { session_token: "abc123..." }
|
|
358
|
+
|
|
359
|
+
2. Redirect to: /ask-bob?session=abc123...
|
|
360
|
+
|
|
361
|
+
3. BobStandalone reads sessionToken โ resolves vehicle + customer context
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
> **Critical:** `vehicle_id` must be numeric throughout the pipeline. String values cause silent API failures.
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
## 8. Design Tokens
|
|
369
|
+
|
|
370
|
+
Exported from the package for use on CARFIX pages that mirror Bob's styling:
|
|
371
|
+
|
|
372
|
+
```typescript
|
|
373
|
+
import {
|
|
374
|
+
CARFIX_COLORS,
|
|
375
|
+
QUALITY_TIER_CONFIG,
|
|
376
|
+
IMAGE_URLS,
|
|
377
|
+
BADGE_CONFIG,
|
|
378
|
+
TYPOGRAPHY,
|
|
379
|
+
isRotorProduct,
|
|
380
|
+
getDisplayPrice,
|
|
381
|
+
formatNZD,
|
|
382
|
+
} from '@gymmymac/bob-widget';
|
|
55
383
|
```
|
|
56
384
|
|
|
57
|
-
|
|
385
|
+
### Key Colors
|
|
386
|
+
|
|
387
|
+
| Token | Value | Usage |
|
|
388
|
+
|---|---|---|
|
|
389
|
+
| `primary` | `#0052CC` | Standard tier, CTAs, CARFIX Value |
|
|
390
|
+
| `secondary` | `#38BDF8` | Accents, links |
|
|
391
|
+
| `accent` | `#FF8C00` | Premium tier |
|
|
392
|
+
| `success` | `#22C55E` | "Fits Vehicle" badges, Add to Cart |
|
|
393
|
+
| `destructive` | `#EF4444` | Performance tier |
|
|
394
|
+
|
|
395
|
+
### Tier Visual Config
|
|
396
|
+
|
|
397
|
+
| Tier | Color | Background | Badge |
|
|
398
|
+
|---|---|---|---|
|
|
399
|
+
| Economy | `#475569` | `#F1F5F9` | ๐ฐ |
|
|
400
|
+
| Standard | `#0052CC` | `rgba(0,82,204,0.1)` | โญ CARFIX Value |
|
|
401
|
+
| Premium | `#D97706` | `#FEF3C7` | ๐ |
|
|
402
|
+
| Performance | `#DC2626` | `#FEE2E2` | โก |
|
|
58
403
|
|
|
59
404
|
---
|
|
60
405
|
|
|
61
|
-
##
|
|
406
|
+
## 9. Exported Types (Full List)
|
|
407
|
+
|
|
408
|
+
```typescript
|
|
409
|
+
// Components
|
|
410
|
+
export { BobStandalone } from '@gymmymac/bob-widget';
|
|
411
|
+
export type { StandaloneWidgetProps } from '@gymmymac/bob-widget';
|
|
62
412
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
413
|
+
// Types
|
|
414
|
+
export type {
|
|
415
|
+
HostContext, HostUserContext, HostVehicleContext, HostCartContext,
|
|
416
|
+
BobConfig, HostApiConfig, BobCallbacks, BobProviderConfig, BobLayoutConfig,
|
|
417
|
+
Product, CartItem, ServicePackage, PreparedTier, PreparedTierProduct, PreparedTierBrand,
|
|
418
|
+
Partslot, QualityTiers, Part,
|
|
419
|
+
PartnerConfig, PartnerFeatureFlags, EssentialCallbacks,
|
|
420
|
+
Vehicle, Message, HighlightedProduct,
|
|
421
|
+
BobAnalyticsEvent, BobGA4Config,
|
|
422
|
+
} from '@gymmymac/bob-widget';
|
|
423
|
+
```
|
|
69
424
|
|
|
70
|
-
|
|
425
|
+
---
|
|
71
426
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
427
|
+
## 10. Post-Install Verification Checklist
|
|
428
|
+
|
|
429
|
+
```
|
|
430
|
+
โก npm install completes without peer dependency warnings
|
|
431
|
+
โก BobStandalone renders loading spinner, then Bob appears
|
|
432
|
+
โก Bob character sits between header (72px) and bottom nav (72px)
|
|
433
|
+
โก Chat drawer opens above bottom navigation (z-index check)
|
|
434
|
+
โก PTT button is visible and not clipped
|
|
435
|
+
โก Vehicle lookup works (try rego: HZP550)
|
|
436
|
+
โก Service packages appear with tier cards
|
|
437
|
+
โก Bundle discount shows Was/Now pricing where applicable
|
|
438
|
+
โก "Add to Cart" callback fires with correct item shape
|
|
439
|
+
โก Session handoff works (pass ?session=TOKEN)
|
|
440
|
+
โก No console errors (filter for [Bob)
|
|
441
|
+
โก Mobile: safe-area-inset respected on notched devices
|
|
442
|
+
```
|
|
75
443
|
|
|
76
|
-
|
|
444
|
+
---
|
|
445
|
+
|
|
446
|
+
## 11. Test Baseline
|
|
447
|
+
|
|
448
|
+
Bob ships with **36 unit tests** and **8+ E2E scenarios** covering:
|
|
449
|
+
|
|
450
|
+
- Callback mapping and stability
|
|
451
|
+
- Tier validation and empty states
|
|
452
|
+
- Rear Brake Disc/Drum filter logic
|
|
453
|
+
- Bundle discount display and cart pricing
|
|
454
|
+
- Vehicle lookup flow
|
|
455
|
+
- Service package rendering
|
|
456
|
+
|
|
457
|
+
Run locally: `cd packages/bob-widget && npx vitest run`
|
|
458
|
+
|
|
459
|
+
---
|
|
460
|
+
|
|
461
|
+
## ๐ Additional Documentation
|
|
462
|
+
|
|
463
|
+
| Document | Description |
|
|
464
|
+
|----------|-------------|
|
|
465
|
+
| **[BOB-DOCUMENTATION.md](./BOB-DOCUMENTATION.md)** | Complete integration guide with troubleshooting |
|
|
466
|
+
| **[CHANGELOG.md](./CHANGELOG.md)** | Version history and release notes |
|
|
467
|
+
| **[install/carfix/](./install/carfix/)** | Installer scripts, templates, and verification checklists |
|
|
468
|
+
|
|
469
|
+
---
|
|
77
470
|
|
|
78
471
|
## Support
|
|
79
472
|
|
|
80
|
-
For integration issues,
|
|
473
|
+
For integration issues, the Bob team needs:
|
|
474
|
+
1. Browser console output (filter for `[Bob`)
|
|
475
|
+
2. Network tab showing failed API calls
|
|
476
|
+
3. Screenshot of layout issue
|
|
477
|
+
4. Device / browser / viewport info
|
|
81
478
|
|
|
82
479
|
## License
|
|
83
480
|
|
package/bin/bob-widget.mjs
CHANGED
|
@@ -18,7 +18,7 @@ const __filename = fileURLToPath(import.meta.url);
|
|
|
18
18
|
const __dirname = dirname(__filename);
|
|
19
19
|
const INSTALL_DIR = join(__dirname, '..', 'install', 'carfix');
|
|
20
20
|
|
|
21
|
-
const VERSION = '3.1
|
|
21
|
+
const VERSION = '3.2.1';
|
|
22
22
|
|
|
23
23
|
const COLORS = {
|
|
24
24
|
reset: '\x1b[0m',
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bob Callback Stability Tests
|
|
3
|
+
*
|
|
4
|
+
* These tests verify that the callback refs in Bob.tsx maintain stable references
|
|
5
|
+
* and correctly update state when parts/packages are received.
|
|
6
|
+
*
|
|
7
|
+
* Critical for preventing the "500 parts received but not displayed" regression.
|
|
8
|
+
* See: .lovable/plan.md - "Layer 2: Unit Tests for State Management"
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PTT Long-Press Protection Tests
|
|
3
|
+
*
|
|
4
|
+
* Verifies the 3-layer defense against mobile browsers triggering
|
|
5
|
+
* "Save image" context menus when users long-press the PTT button.
|
|
6
|
+
*
|
|
7
|
+
* Layer 1: CSS properties on all widget images (-webkit-touch-callout, user-select, draggable)
|
|
8
|
+
* Layer 2: contextmenu event prevention on the widget container
|
|
9
|
+
* Layer 3: preventDefault() on PTT touchstart/mousedown handlers
|
|
10
|
+
*
|
|
11
|
+
* See: .lovable/plan.md - "Fix: PTT Long-Press Triggers Save Image on Mobile"
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
@@ -10,11 +10,10 @@ interface ProductTileProps {
|
|
|
10
10
|
/**
|
|
11
11
|
* ProductTile - Premium Glassmorphism Product Cards
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* - Hover: scale(1.04), translateY(-4px), enhanced glow
|
|
13
|
+
* Image fallback chain:
|
|
14
|
+
* 1. product.image_url (product photo)
|
|
15
|
+
* 2. product.brandImageUrl (brand logo)
|
|
16
|
+
* 3. "No Image" placeholder
|
|
18
17
|
*/
|
|
19
18
|
export declare const ProductTile: React.FC<ProductTileProps>;
|
|
20
19
|
export {};
|