@gymmymac/bob-widget 3.1.10 → 3.1.20

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.
@@ -56,8 +56,9 @@ export declare const QUALITY_TIER_CONFIG: {
56
56
  * Service Package Descriptions - Problem → Benefit → CFX Pack format
57
57
  */
58
58
  export declare const SERVICE_PACKAGE_DESCRIPTIONS: Record<string, string>;
59
- export declare const DEFAULT_SERVICE_DESCRIPTION = "Keep your vehicle running safely and efficiently with quality parts matched to your specific make and model. Each CFX Service Pack includes everything you need for this essential maintenance.";
59
+ export declare const DEFAULT_SERVICE_DESCRIPTION = "Keep your vehicle running safely and efficiently with quality parts matched to your specific make and model. Each CARFIX Service Pack includes everything you need for this essential maintenance.";
60
60
  export declare const IMAGE_URLS: {
61
+ readonly storageBase: "https://flpzjbasdsfwoeruyxgp.supabase.co/storage/v1/object/public";
61
62
  readonly productImage: (sku: string) => string;
62
63
  readonly brandLogo: (brandName: string) => string;
63
64
  readonly carfixImage: (sku: string) => string;
@@ -15,6 +15,12 @@ export interface Product {
15
15
  image_url?: string;
16
16
  image?: string;
17
17
  quantity?: number;
18
+ webDescription?: string;
19
+ brandDescription?: string;
20
+ perCarQty?: number;
21
+ volume?: string;
22
+ viscosity?: string;
23
+ brandImageUrl?: string;
18
24
  }
19
25
  /**
20
26
  * API response format from CARFIX retrieve-parts endpoint
@@ -77,6 +83,9 @@ export interface PreparedTier {
77
83
  isRecommended: boolean;
78
84
  isHidden: boolean;
79
85
  totalPrice: number;
86
+ originalTotalPrice?: number;
87
+ savingsAmount?: number;
88
+ bundleDiscountPercentage?: number;
80
89
  productCount: number;
81
90
  dominantBrand: string | null;
82
91
  brands: PreparedTierBrand[];
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Rear Brake Service: Disc vs Drum filter utility
3
+ * Used by mobile ServicePackageDetailView
4
+ */
5
+ export type RearBrakeType = 'disc' | 'drum';
6
+ export declare function isRearBrakePackage(pkg: {
7
+ id?: string;
8
+ title?: string;
9
+ }): boolean;
10
+ export declare function filterByBrakeType<T extends {
11
+ partslotName: string;
12
+ }>(products: T[], brakeType: RearBrakeType): T[];
13
+ export declare function recalcTierTotal<T extends {
14
+ displayPrice: number;
15
+ }>(products: T[]): number;
@@ -1,8 +1,8 @@
1
- # Bob Widget v3.1.10 - CARFIX Installation Guide
1
+ # Bob Widget v3.1.11 - CARFIX Installation Guide
2
2
 
3
3
  > 🚨 **STOP - READ THIS FIRST**
4
4
  >
5
- > Bob v3.1.10 requires a **strict 3-stage installation process**. Skipping stages WILL cause visual issues (blur, wrong scale, wrong position).
5
+ > Bob v3.1.11 requires a **strict 3-stage installation process**. Skipping stages WILL cause visual issues (blur, wrong scale, wrong position).
6
6
 
7
7
  ## Overview
8
8
 
@@ -17,9 +17,12 @@ The 3-stage process ensures:
17
17
  # Stage A: Forensic Scan & Purge
18
18
  npx @gymmymac/bob-widget carfix stage-a
19
19
 
20
- # Stage B: Generate Page Template
20
+ # Stage B: Generate Page Template (if you have existing Header/BottomNav)
21
21
  npx @gymmymac/bob-widget carfix stage-b --target next-pages --output pages/ask-bob.tsx
22
22
 
23
+ # Stage B: Generate Page Template WITH Layout Components (if you need Header/BottomNav)
24
+ npx @gymmymac/bob-widget carfix stage-b --target next-pages --with-layout
25
+
23
26
  # Stage C: Install & Verify
24
27
  npx @gymmymac/bob-widget carfix stage-c --partner CARFIX
25
28
  ```
@@ -49,6 +52,23 @@ Generates a container page template for your framework:
49
52
  - `next-app` - Next.js App Router
50
53
  - `react-router` - React Router (Vite)
51
54
 
55
+ **⚠️ IMPORTANT: Layout Components Required**
56
+
57
+ The container height formula assumes you have:
58
+ - **CARFIX Header**: 72px fixed at top
59
+ - **CARFIX Bottom Navigation**: 72px fixed at bottom
60
+
61
+ If these components **don't exist**, use the `--with-layout` flag:
62
+
63
+ ```bash
64
+ npx @gymmymac/bob-widget carfix stage-b --target next-pages --with-layout
65
+ ```
66
+
67
+ This generates:
68
+ - `components/CarfixHeader.tsx` (72px header)
69
+ - `components/CarfixBottomNav.tsx` (72px bottom nav)
70
+ - Complete page template with layout wired up
71
+
52
72
  The template includes the correct container height calculation:
53
73
  ```css
54
74
  height: calc(100dvh - 144px - env(safe-area-inset-bottom, 0px))
@@ -58,7 +78,7 @@ height: calc(100dvh - 144px - env(safe-area-inset-bottom, 0px))
58
78
 
59
79
  **Time: 1-2 minutes**
60
80
 
61
- - Installs `@gymmymac/bob-widget@3.1.10`
81
+ - Installs `@gymmymac/bob-widget@3.1.11`
62
82
  - Verifies the installed version
63
83
  - Tests backend connectivity
64
84
  - Provides final code integration example
@@ -77,12 +97,14 @@ After completing all stages, verify in browser:
77
97
 
78
98
  | Test | Expected Result |
79
99
  |------|-----------------|
80
- | Console version | `[BobWidget] Package loaded - v3.1.10` |
100
+ | Console version | `[BobWidget] Package loaded - v3.1.11` |
81
101
  | Bob visibility | Fully visible, not cropped |
82
102
  | No blur | Background is NOT blurred |
83
103
  | Correct scale | Bob is prominently sized |
84
104
  | Chat works | Messages send and Bob responds |
85
105
  | PTT (HTTPS) | Speech recognition activates |
106
+ | Header visible | 72px CARFIX header at top |
107
+ | Bottom nav visible | 72px navigation at bottom |
86
108
 
87
109
  ## Support
88
110
 
@@ -1,4 +1,4 @@
1
- # Bob Widget v3.1.10 - Runtime Verification Checklist
1
+ # Bob Widget v3.1.19 - Runtime Verification Checklist
2
2
 
3
3
  > Complete this checklist after Stage C to confirm Bob is working correctly.
4
4
 
@@ -6,8 +6,8 @@
6
6
 
7
7
  Open DevTools (F12) → Console tab:
8
8
 
9
- - [ ] `[BobWidget] Package loaded - v3.1.10`
10
- - [ ] `[BobStandalone] Initialized { version: "3.1.10", partner: "CARFIX", ... }`
9
+ - [ ] `[BobWidget] Package loaded - v3.1.19`
10
+ - [ ] `[BobStandalone] Initialized { version: "3.1.19", partner: "CARFIX", ... }`
11
11
  - [ ] `[BobWidget] Partner config loaded: { partner: "CARFIX", ... }`
12
12
  - [ ] No red error messages
13
13
 
@@ -0,0 +1,367 @@
1
+ # Bob Widget — CARFIX Installation Brief
2
+
3
+ **Package:** `@gymmymac/bob-widget@3.1.19`
4
+ **Date:** 2026-02-13
5
+ **Status:** Production-ready, 36 unit tests passing, E2E baseline locked
6
+
7
+ ---
8
+
9
+ ## 1. Peer Dependencies (Critical for Build)
10
+
11
+ ```json
12
+ {
13
+ "peerDependencies": {
14
+ "react": "^18.0.0",
15
+ "react-dom": "^18.0.0"
16
+ },
17
+ "dependencies (bundled — no action needed)": {
18
+ "@supabase/supabase-js": "^2.84.0",
19
+ "@tanstack/react-query": "^5.0.0"
20
+ }
21
+ }
22
+ ```
23
+
24
+ > If CARFIX already uses `@tanstack/react-query`, ensure versions are compatible (v5+).
25
+
26
+ ---
27
+
28
+ ## 2. Installation
29
+
30
+ ```bash
31
+ npm install @gymmymac/bob-widget@latest
32
+ ```
33
+
34
+ ---
35
+
36
+ ## 3. Minimal Integration (4 lines)
37
+
38
+ ```tsx
39
+ import { BobStandalone } from '@gymmymac/bob-widget';
40
+
41
+ function AskBobPage() {
42
+ const router = useRouter();
43
+ const sessionToken = router.query.session as string;
44
+
45
+ return (
46
+ <div style={{
47
+ height: 'calc(100dvh - 144px - env(safe-area-inset-bottom, 0px))',
48
+ position: 'relative',
49
+ /* DO NOT use overflow: hidden — clips PTT button and chat drawer */
50
+ }}>
51
+ <BobStandalone
52
+ partner="CARFIX"
53
+ sessionToken={sessionToken}
54
+ bottomOffset={0} /* Container already handles spacing */
55
+ zIndexBase={100} /* Above header z-40 and nav z-30 */
56
+ onAddToCart={async (item) => {
57
+ // See Section 6 for full item shape including bundle metadata
58
+ await carfixCart.add(item);
59
+ }}
60
+ onNavigate={(url) => router.push(url)}
61
+ onCheckout={(checkoutUrl) => window.location.href = checkoutUrl}
62
+ onError={(error) => console.error('[Bob Error]', error)}
63
+ />
64
+ </div>
65
+ );
66
+ }
67
+ ```
68
+
69
+ > **Auto-configuration:** The `partner="CARFIX"` prop loads all API URLs, credentials, layout defaults, and feature flags from the `bob_partners` database table. No manual config needed.
70
+
71
+ ---
72
+
73
+ ## 4. CARFIX API Configuration (Already in Database)
74
+
75
+ ```json
76
+ {
77
+ "baseUrl": "https://flpzjbasdsfwoeruyxgp.supabase.co/functions/v1",
78
+ "apiKey": "eyJhbGciOiJIUzI1NiIs...wKoJ51_VPro_BrJz-A-NRpSmUW0XBP-7TJJcrhvYwxE",
79
+ "partnerCode": "CARFIX"
80
+ }
81
+ ```
82
+
83
+ ### Available Endpoints
84
+
85
+ | Endpoint | Purpose |
86
+ |---|---|
87
+ | `partner-api` | Session creation, cart, user context, orders |
88
+ | `calculate-service-bundles` | Service packs with `preparedTiers[]` (incl. bundle discounts) |
89
+ | `retrieve-vehicle-info` | NZ rego lookup |
90
+ | `retrieve-parts` | Vehicle parts by category |
91
+
92
+ ---
93
+
94
+ ## 5. Layout Constraints
95
+
96
+ ```
97
+ ┌──────────────────────────────┐
98
+ │ CARFIX Header (72px, z-40) │
99
+ ├──────────────────────────────┤
100
+ │ │
101
+ │ Bob Container │
102
+ │ height: calc(100dvh - 144px │
103
+ │ - safe-area-inset) │
104
+ │ position: relative │
105
+ │ NO overflow: hidden! │
106
+ │ │
107
+ ├──────────────────────────────┤
108
+ │ Bottom Nav (72px, z-30) │
109
+ └──────────────────────────────┘
110
+ ```
111
+
112
+ **Bob's internal z-index stack (relative to `zIndexBase={100}`):**
113
+
114
+ | Layer | z-index |
115
+ |---|---|
116
+ | Chat PTT Button | 145 |
117
+ | Chat Drawer | 130 |
118
+ | Counter Overlay | 70 |
119
+ | Bob Character | 60 |
120
+ | Product Shelf | 55 |
121
+ | Backdrop | 10 |
122
+
123
+ ---
124
+
125
+ ## 6. Callback Signatures
126
+
127
+ ### onAddToCart
128
+
129
+ ```typescript
130
+ onAddToCart: (item: {
131
+ product_id: string;
132
+ product_name: string;
133
+ quantity: number;
134
+ unit_price: number; // Final price (discount already applied for bundle items)
135
+ sku?: string;
136
+ brand?: string;
137
+ image_url?: string;
138
+ vehicle_id?: string;
139
+ // Bundle metadata (present when item is part of a service package)
140
+ is_bundle_item?: boolean;
141
+ bundle_discount_percentage?: number;
142
+ service_package_name?: string;
143
+ service_package_id?: string;
144
+ quality_tier?: string; // "Economy" | "Standard" | "Premium" | "Performance"
145
+ }) => Promise<void> | void;
146
+ ```
147
+
148
+ ### onNavigate
149
+
150
+ ```typescript
151
+ onNavigate: (url: string) => void;
152
+ // Example urls: "/product/SKU123", "/checkout"
153
+ ```
154
+
155
+ ### onCheckout
156
+
157
+ ```typescript
158
+ onCheckout: (checkoutUrl: string) => void;
159
+ // checkoutUrl is a full Stripe payment URL
160
+ ```
161
+
162
+ ### onError
163
+
164
+ ```typescript
165
+ onError: (error: Error) => void;
166
+ // Bob shows toast by default — this is for host-side logging
167
+ ```
168
+
169
+ ---
170
+
171
+ ## 7. Bundle Discount Fields (NEW)
172
+
173
+ The `calculate-service-bundles` API returns these fields per `PreparedTier`:
174
+
175
+ ```typescript
176
+ interface PreparedTier {
177
+ tierName: string; // "Economy" | "Standard" | "Premium" | "Performance"
178
+ displayName: string;
179
+ description: string;
180
+ isRecommended: boolean; // true = CARFIX Value tier
181
+ isHidden: boolean; // true = filter out (duplicate price)
182
+
183
+ // Pricing (pre-calculated by API — never recompute)
184
+ totalPrice: number; // Discounted bundle price
185
+ originalTotalPrice?: number; // Full price before discount
186
+ savingsAmount?: number; // Dollar savings (originalTotalPrice - totalPrice)
187
+ bundleDiscountPercentage?: number; // Discount % applied (0-50)
188
+
189
+ productCount: number;
190
+ dominantBrand: string | null;
191
+ brands: PreparedTierBrand[];
192
+ products: PreparedTierProduct[];
193
+ }
194
+
195
+ interface PreparedTierProduct {
196
+ partslotId: number;
197
+ partslotName: string; // "BRAKE PADS FRONT"
198
+ sku: string;
199
+ name: string;
200
+ brand: string;
201
+ brandFullName: string;
202
+ brandImageUrl: string; // Full URL — use directly in <img>
203
+ productImageUrl: string; // Full URL — use directly in <img>
204
+ price: number; // Legacy unit price
205
+ unitPrice: number; // Per-unit price
206
+ displayPrice: number; // Total (unitPrice × perCarQty) — USE THIS
207
+ isRotor: boolean; // Show "[Pair]" badge
208
+ isMultiQty: boolean; // Show quantity breakdown (e.g. spark plugs)
209
+ perCarQty: number; // Quantity needed
210
+ partNumber: string | null;
211
+ webDescription: string | null;
212
+ viscosity: string | null;
213
+ volume: number | null;
214
+ }
215
+
216
+ interface PreparedTierBrand {
217
+ name: string;
218
+ fullName: string;
219
+ imageUrl: string; // Full URL
220
+ }
221
+ ```
222
+
223
+ ### Rendering Rules
224
+
225
+ 1. **Filter hidden tiers:** `preparedTiers.filter(t => !t.isHidden)`
226
+ 2. **When `savingsAmount > 0`:** Show ~~$originalTotalPrice~~ → **$totalPrice** + "SAVE $XX — X% Bundle Deal"
227
+ 3. **When `savingsAmount === 0`:** Show `totalPrice` normally, no discount UI
228
+ 4. **Use `displayPrice`** for individual products (already includes quantity)
229
+ 5. **Never calculate prices client-side** — all values arrive pre-calculated
230
+
231
+ ---
232
+
233
+ ## 8. Session Handoff (Pre-authenticated Users)
234
+
235
+ To pass vehicle/customer context from CARFIX to Bob:
236
+
237
+ ```
238
+ 1. CARFIX calls partner-api with action: "create_session"
239
+ → Body: { vehicle_id: 42899 } ← MUST be a NUMBER
240
+ → Returns: { session_token: "abc123..." }
241
+
242
+ 2. Redirect to Bob page: /ask-bob?session=abc123...
243
+
244
+ 3. BobStandalone reads sessionToken from URL
245
+ → Calls session-handoff edge function
246
+ → Injects vehicle + customer context into chat
247
+ ```
248
+
249
+ > **Critical:** `vehicle_id` must be numeric throughout the pipeline. String values cause silent API failures.
250
+
251
+ ---
252
+
253
+ ## 9. Design Tokens
254
+
255
+ The full design token file is exported from the package:
256
+
257
+ ```typescript
258
+ import {
259
+ CARFIX_COLORS,
260
+ QUALITY_TIER_CONFIG,
261
+ IMAGE_URLS,
262
+ BADGE_CONFIG,
263
+ TYPOGRAPHY,
264
+ isRotorProduct,
265
+ getDisplayPrice,
266
+ formatNZD,
267
+ } from '@gymmymac/bob-widget';
268
+ ```
269
+
270
+ ### Key Colors
271
+
272
+ | Token | Value | Usage |
273
+ |---|---|---|
274
+ | `primary` | `#0052CC` | Standard tier, CTAs, CARFIX Value |
275
+ | `secondary` | `#38BDF8` | Accents, links |
276
+ | `accent` | `#FF8C00` | Premium tier |
277
+ | `success` | `#22C55E` | "Fits Vehicle" badges, Add to Cart |
278
+ | `destructive` | `#EF4444` | Performance tier |
279
+ | `foreground` | `#0F172A` | Headers, primary text |
280
+ | `mutedForeground` | `#64748B` | Descriptions |
281
+
282
+ ### Tier Visual Config
283
+
284
+ | Tier | Color | Badge |
285
+ |---|---|---|
286
+ | Economy | `#475569` on `#F1F5F9` | 💰 |
287
+ | Standard | `#0052CC` on `rgba(0,82,204,0.1)` | ⭐ CARFIX Value |
288
+ | Premium | `#D97706` on `#FEF3C7` | 🏆 |
289
+ | Performance | `#DC2626` on `#FEE2E2` | ⚡ |
290
+
291
+ ---
292
+
293
+ ## 10. Exported Types (Full List)
294
+
295
+ ```typescript
296
+ // Core widget components
297
+ export { BobStandalone } from '@gymmymac/bob-widget';
298
+ export type { StandaloneWidgetProps } from '@gymmymac/bob-widget';
299
+
300
+ // Types available for CARFIX integration
301
+ export type {
302
+ // Context & Config
303
+ HostContext, HostUserContext, HostVehicleContext, HostCartContext,
304
+ BobConfig, HostApiConfig, BobCallbacks, BobProviderConfig, BobLayoutConfig,
305
+
306
+ // Products & Packages
307
+ Product, CartItem, ServicePackage, PreparedTier, PreparedTierProduct, PreparedTierBrand,
308
+ Partslot, QualityTiers, Part,
309
+
310
+ // Partner
311
+ PartnerConfig, PartnerFeatureFlags, EssentialCallbacks,
312
+
313
+ // Vehicle
314
+ Vehicle,
315
+
316
+ // Messages
317
+ Message, HighlightedProduct,
318
+
319
+ // Analytics
320
+ BobAnalyticsEvent, BobGA4Config,
321
+ } from '@gymmymac/bob-widget';
322
+ ```
323
+
324
+ ---
325
+
326
+ ## 11. Verification Checklist (Post-Install)
327
+
328
+ ```
329
+ □ npm install completes without peer dependency warnings
330
+ □ BobStandalone renders loading spinner, then Bob appears
331
+ □ Bob character sits between header and bottom nav
332
+ □ Chat drawer opens above bottom navigation (z-index check)
333
+ □ PTT button is visible and not clipped
334
+ □ Vehicle lookup works (try rego: HZP550)
335
+ □ Service packages appear with tier cards
336
+ □ Bundle discount shows Was/Now pricing where applicable
337
+ □ "Add to Cart" callback fires with correct item shape
338
+ □ Session handoff works (pass ?session=TOKEN)
339
+ □ No console errors related to Bob
340
+ □ Mobile: safe-area-inset respected on notched devices
341
+ ```
342
+
343
+ ---
344
+
345
+ ## 12. Test Baseline
346
+
347
+ Bob ships with **36 unit tests** and **8+ E2E scenarios** covering:
348
+
349
+ - Callback mapping and stability
350
+ - Tier validation and empty states
351
+ - Rear Brake Disc/Drum filter logic
352
+ - Bundle discount display and cart pricing
353
+ - Vehicle lookup flow
354
+ - Service package rendering
355
+ - Chat drawer positioning
356
+
357
+ Run locally: `cd packages/bob-widget && npx vitest run`
358
+
359
+ ---
360
+
361
+ ## Support
362
+
363
+ For integration issues, the Bob team needs:
364
+ 1. Browser console output (filter for `[Bob`)
365
+ 2. Network tab showing failed API calls
366
+ 3. Screenshot of layout issue
367
+ 4. Device/browser/viewport info
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gymmymac/bob-widget",
3
- "version": "3.1.10",
3
+ "version": "3.1.20",
4
4
  "description": "Bob - AI-powered automotive parts assistant widget with multi-tenant support, RAF animations, swipeable interactions, and GA4 analytics",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",