docs: Add comprehensive wizard improvements implementation guide

Added detailed implementation guide documenting:
- Complete pattern used across all 6 rewritten wizards
- Backend field mappings for remaining wizards (before continuation)
- Step-by-step instructions for wizard rewrites
- Testing checklists for each wizard type
- Type inconsistencies identified and documented
- Field mapping reference (camelCase to snake_case)
- Best practices for progressive disclosure UX

This guide was created during the initial implementation phase
and documents the patterns applied to all wizards.
This commit is contained in:
Claude
2025-11-10 09:38:30 +00:00
parent af40052848
commit e3021b839e

View File

@@ -0,0 +1,590 @@
# Wizard Improvements - Implementation Guide
## Executive Summary
This document provides comprehensive guidance for completing the wizard improvements project based on backend/frontend research and UX best practices.
### **COMPLETED** ✅
1. **RecipeWizard** - Fully rewritten with all 46 backend fields
2. **CustomerWizard** - Fully rewritten with all 31 backend fields
3. **SupplierWizard** - Fully rewritten with all 48 backend fields
4. **AdvancedOptionsSection** - Reusable component created
5. **Research Documentation** - Complete backend/frontend analysis
### **REMAINING** ⏳
1. **InventoryWizard** - 44 backend fields to add
2. **QualityTemplateWizard** - 25 backend fields to add
3. **CustomerOrderWizard** - 72 backend fields to add
4. **Type Inconsistency Fixes** - PaymentTerms enum, field naming
---
## Part 1: What Was Fixed
### Critical Issues Resolved
#### 1. **RecipeWizard.tsx:505 Error**
**Problem**: `TypeError: a.map is not a function`
**Root Cause**:
```typescript
// Line 387 - BEFORE
const result = await qualityTemplateService.getTemplates(...);
setTemplates(result); // ❌ result = {templates: [], total: 0, ...}
// Line 505
{templates.map((template) => ( // ❌ templates is object, not array
```
**Solution**:
```typescript
// Line 387 - AFTER
const result = await qualityTemplateService.getTemplates(...);
setTemplates(result.templates || []); // ✅ Extract array
```
#### 2. **Duplicate Next Buttons**
**Problem**: Two "Next" buttons causing UX confusion
- WizardModal footer button (no validation)
- Step component button (with validation)
**Solution**:
- Removed all internal step buttons
- Used WizardModal's `validate` prop:
```typescript
{
id: 'recipe-details',
validate: () => !!(data.name && data.finishedProductId && data.yieldQuantity),
component: (props) => <RecipeDetailsStep {...props} />
}
```
#### 3. **Missing Required Backend Fields**
**Problem**: Wizards missing fields that backend requires
**Examples Fixed**:
- Recipe: `version`, `difficulty_level`, `status` (with proper defaults)
- Customer: `customer_code` (with auto-generation)
- Supplier: `supplier_type`, `status`, `payment_terms`, `currency`, `standard_lead_time`
#### 4. **No Advanced Options**
**Problem**: All fields shown at once = overwhelming forms
**Solution**: Progressive disclosure with `AdvancedOptionsSection`
```typescript
<AdvancedOptionsSection
title="Advanced Options"
description="Optional fields for detailed management"
>
{/* 20-30 optional fields here */}
</AdvancedOptionsSection>
```
---
## Part 2: Implementation Pattern
All three completed wizards follow this exact pattern:
### File Structure
```typescript
import { AdvancedOptionsSection } from '../../../ui/AdvancedOptionsSection';
import Tooltip from '../../../ui/Tooltip/Tooltip';
interface WizardDataProps extends WizardStepProps {
data: Record<string, any>;
onDataChange: (data: Record<string, any>) => void;
}
const DetailsStep: React.FC<WizardDataProps> = ({ data, onDataChange, onComplete }) => {
const [wizardData, setWizardData] = useState({
// Required fields with defaults
name: data.name || '',
requiredField: data.requiredField || 'default',
// Basic optional fields
email: data.email || '',
// Advanced optional fields (20-40 fields)
advancedField1: data.advancedField1 || '',
advancedField2: data.advancedField2 || '',
// ... more fields
});
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
// Auto-generation logic (if applicable)
useEffect(() => {
if (!wizardData.code && wizardData.name) {
const code = `PREFIX-${wizardData.name.substring(0, 3).toUpperCase()}-${Date.now().toString().slice(-4)}`;
setWizardData(prev => ({ ...prev, code }));
}
}, [wizardData.name]);
// Real-time data sync
useEffect(() => {
onDataChange({ ...data, ...wizardData });
}, [wizardData]);
const handleCreate = async () => {
if (!currentTenant?.id) {
setError('Could not obtain tenant information');
return;
}
setLoading(true);
setError(null);
try {
const payload = {
// Map camelCase to snake_case
required_field: wizardData.requiredField,
optional_field: wizardData.optionalField || undefined,
// ...
};
await service.create(currentTenant.id, payload);
showToast.success('Created successfully');
onComplete();
} catch (err: any) {
const errorMessage = err.response?.data?.detail || 'Error creating';
setError(errorMessage);
showToast.error(errorMessage);
} finally {
setLoading(false);
}
};
return (
<div className="space-y-6">
{/* Header */}
{/* Error display */}
{/* Required Fields */}
<div className="space-y-4">
{/* Form fields */}
</div>
{/* Advanced Options */}
<AdvancedOptionsSection>
{/* Optional fields */}
</AdvancedOptionsSection>
{/* Submit Button */}
<div className="flex justify-center pt-4">
<button onClick={handleCreate} disabled={loading}>
{loading ? 'Creating...' : 'Create'}
</button>
</div>
</div>
);
};
export const WizardSteps = (data, setData): WizardStep[] => [
{
id: 'details',
title: 'Details',
description: 'Essential information',
component: (props) => <DetailsStep {...props} data={data} onDataChange={setData} />,
validate: () => !!(data.requiredField1 && data.requiredField2),
},
];
```
---
## Part 3: Step-by-Step Implementation Guide
### For InventoryWizard
**Required Backend Fields:**
- `name` (String)
- `unit_of_measure` (Enum: kg, g, l, ml, units, pcs, pkg, bags, boxes)
- `product_type` (Enum: INGREDIENT, FINISHED_PRODUCT - default: INGREDIENT)
**Optional Fields to Add in Advanced Section:**
- Basic: `sku`, `barcode`, `ingredient_category`, `product_category`, `description`, `brand`
- Pricing: `average_cost`, `last_purchase_price`, `standard_cost`
- Inventory Mgmt: `low_stock_threshold`, `reorder_point`, `reorder_quantity`, `max_stock_level`
- Product Info: `package_size`, `shelf_life_days`, `display_life_hours`, `best_before_hours`
- Storage: `storage_instructions`, `is_perishable`
- Central Bakery: `central_baker_product_code`, `delivery_days`, `minimum_order_quantity`, `pack_size`
- Flags: `is_active`, `produced_locally`
- References: `recipe_id` (for finished products)
- Allergens: `allergen_info` (JSONB array)
- Nutrition: `nutritional_info` (JSONB for finished products)
**Auto-generation:**
```typescript
useEffect(() => {
if (!wizardData.sku && wizardData.name) {
const sku = `INV-${wizardData.name.substring(0, 3).toUpperCase()}-${Date.now().toString().slice(-4)}`;
setWizardData(prev => ({ ...prev, sku }));
}
}, [wizardData.name]);
```
### For QualityTemplateWizard
**Required Backend Fields:**
- `name` (String)
- `check_type` (String: visual, measurement, temperature, weight, boolean, timing, checklist)
- `weight` (Float 0.0-10.0, default: 1.0)
- `created_by` (UUID - use currentTenant.id)
**Optional Fields to Add in Advanced Section:**
- Identification: `template_code`
- Details: `description`, `category`, `instructions`
- Configuration: `parameters`, `thresholds`, `scoring_criteria` (all JSONB)
- Values: `min_value`, `max_value`, `target_value`, `unit`, `tolerance_percentage`
- Flags: `is_active`, `is_required`, `is_critical`
- Stages: `applicable_stages` (JSONB array of ProcessStage values)
**Note**: `parameters`, `thresholds`, `scoring_criteria` are JSONB - consider textarea with JSON validation or structured form builder.
### For CustomerOrderWizard
**Required Backend Fields:**
- `customer_id` (UUID - select from customers)
- `requested_delivery_date` (DateTime)
- `order_number` (String - auto-generate)
- `status` (Enum: pending, confirmed, in_production, ready, out_for_delivery, delivered, cancelled, failed)
- `order_type` (Enum: standard, rush, recurring, special - default: standard)
- `priority` (Enum: high, normal, low - default: normal)
- `delivery_method` (Enum: delivery, pickup - default: delivery)
**Optional Fields - MANY (72 total backend fields):**
**Step 1: Customer & Delivery**
- `delivery_address` (JSONB)
- `delivery_instructions`, `delivery_window_start`, `delivery_window_end`
- `confirmed_delivery_date`, `actual_delivery_date`
**Step 2: Order Items** (separate array management)
- OrderItem[] with: `product_id`, `quantity`, `unit_price`, `product_name`
- Item fields: `customization_details`, `special_instructions`, `product_specifications`
**Step 3: Pricing & Payment** (Advanced)
- `subtotal`, `discount_amount`, `discount_percentage`, `tax_amount`, `delivery_fee`, `total_amount`
- `payment_status`, `payment_method`, `payment_terms`, `payment_due_date`
**Step 4: Additional Info** (Advanced)
- `special_instructions`, `custom_requirements`, `allergen_warnings`
- `business_model`, `order_source`, `sales_channel`, `order_origin`
- Production: `production_batch_id`, `fulfillment_location`, `estimated_preparation_time`
- Notifications: `customer_notified_confirmed`, `customer_notified_ready`, `customer_notified_delivered`
- Quality: `quality_score`, `customer_rating`, `customer_feedback`
**Auto-generation:**
```typescript
useEffect(() => {
if (!wizardData.orderNumber) {
const orderNum = `ORD-${new Date().getFullYear()}${(new Date().getMonth() + 1).toString().padStart(2, '0')}${new Date().getDate().toString().padStart(2, '0')}-${Date.now().toString().slice(-6)}`;
setWizardData(prev => ({ ...prev, orderNumber: orderNum }));
}
}, []);
```
---
## Part 4: Type Inconsistencies to Fix
### Issue 1: PaymentTerms Enum Conflict
**Problem**: Two different enums with same name
**Suppliers** (`frontend/src/api/types/suppliers.ts`):
```typescript
export enum PaymentTerms {
COD = 'cod',
NET_15 = 'net_15',
NET_30 = 'net_30',
NET_45 = 'net_45',
NET_60 = 'net_60',
PREPAID = 'prepaid',
CREDIT_TERMS = 'credit_terms',
}
```
**Orders** (`frontend/src/api/types/orders.ts`):
```typescript
export enum PaymentTerms {
IMMEDIATE = 'immediate',
NET_30 = 'net_30',
NET_60 = 'net_60',
}
```
**Solution Options**:
1. Rename one: `SupplierPaymentTerms` and `CustomerPaymentTerms`
2. Merge into one comprehensive enum (if backend supports)
3. Use string literals instead of enum
**Recommended Fix**:
```typescript
// frontend/src/api/types/common.ts
export enum SupplierPaymentTerms {
COD = 'cod',
NET_15 = 'net_15',
NET_30 = 'net_30',
NET_45 = 'net_45',
NET_60 = 'net_60',
PREPAID = 'prepaid',
CREDIT_TERMS = 'credit_terms',
}
export enum CustomerPaymentTerms {
IMMEDIATE = 'immediate',
NET_30 = 'net_30',
NET_60 = 'net_60',
}
```
Then update imports:
```typescript
// In suppliers wizard
import { SupplierPaymentTerms } from '../../../api/types/common';
// In customers/orders wizard
import { CustomerPaymentTerms } from '../../../api/types/common';
```
### Issue 2: unit_cost vs unit_price
**Problem**: Inconsistent field naming
**Stock Type** defines:
```typescript
unit_cost: number;
```
**Hook** uses:
```typescript
unit_price: number;
```
**Solution**: Search and replace all `unit_price``unit_cost` in inventory hooks/services, OR update backend to accept both.
**Files to check**:
```bash
grep -r "unit_price" frontend/src/api/services/inventory.ts
grep -r "unit_price" frontend/src/api/hooks/useInventory.ts
```
---
## Part 5: Testing Checklist
For each wizard, verify:
### Functional Testing
- [ ] All required fields prevent submission when empty
- [ ] Validation messages display correctly
- [ ] Optional fields don't prevent submission
- [ ] Advanced options section expands/collapses
- [ ] Auto-generation works (codes, etc.)
- [ ] Form submits successfully
- [ ] Success toast appears
- [ ] Modal closes after success
- [ ] Error messages display on failure
- [ ] Loading state shows during submission
### Field Validation
- [ ] Email fields validate format
- [ ] Phone fields validate format (if applicable)
- [ ] Number fields enforce min/max
- [ ] Date fields use proper format
- [ ] Enum fields use correct values
- [ ] JSONB fields parse correctly
### Backend Alignment
- [ ] All required backend fields present
- [ ] Field names match backend (snake_case)
- [ ] Enums match backend values
- [ ] Data types match (string, number, boolean)
- [ ] Defaults match backend defaults
### UX Testing
- [ ] Form is not overwhelming (required fields visible, optional hidden)
- [ ] Clear visual hierarchy
- [ ] Helpful tooltips on complex fields
- [ ] Responsive design works on mobile
- [ ] Tab order is logical
- [ ] Keyboard navigation works
---
## Part 6: Quick Reference
### Completed Wizard Examples
**Recipe**: `/frontend/src/components/domain/unified-wizard/wizards/RecipeWizard.tsx`
- Best example of complex advanced options
- Shows ingredient list management
- Quality template selection
- Seasonal conditional fields
**Customer**: `/frontend/src/components/domain/unified-wizard/wizards/CustomerWizard.tsx`
- Clean single-step wizard
- Auto-code generation
- Address fields in advanced section
**Supplier**: `/frontend/src/components/domain/unified-wizard/wizards/SupplierWizard.tsx`
- All payment terms properly aligned
- Certification/specialization handling
- Checkbox fields for preferences
### Key Components
**AdvancedOptionsSection**: `/frontend/src/components/ui/AdvancedOptionsSection/AdvancedOptionsSection.tsx`
**Tooltip**: `/frontend/src/components/ui/Tooltip/Tooltip.tsx`
**WizardModal**: `/frontend/src/components/ui/WizardModal/WizardModal.tsx`
### Research Documents
**Backend Models**: `/home/user/bakery_ia/FRONTEND_API_TYPES_ANALYSIS.md`
**API Summary**: `/home/user/bakery_ia/FRONTEND_API_ANALYSIS_SUMMARY.md`
---
## Part 7: Git Workflow
### Commits Created
1. `020acc4` - Research documentation
2. `3b66bb8` - RecipeWizard rewrite
3. `478d423` - CustomerWizard rewrite
4. `b596359` - SupplierWizard rewrite
### Branch
`claude/bakery-jtbd-wizard-design-011CUwzatRMmw9L2wVGdXYgm`
---
## Part 8: Estimated Effort
**Remaining Wizards:**
- InventoryWizard: ~2-3 hours (moderate complexity, 44 fields)
- QualityTemplateWizard: ~1-2 hours (simpler, 25 fields, but JSONB handling)
- CustomerOrderWizard: ~4-6 hours (complex, 72 fields, multi-step with items)
**Type Fixes:**
- PaymentTerms enum: ~30 minutes
- unit_cost vs unit_price: ~15 minutes
**Total Remaining**: ~8-12 hours
---
## Part 9: Success Criteria
**All wizards should:**
1. Have NO duplicate Next buttons
2. Include ALL backend required fields
3. Include ALL backend optional fields (in advanced section)
4. Use validate prop for field validation
5. Auto-generate codes where applicable
6. Have English labels
7. Use AdvancedOptionsSection component
8. Include tooltips for complex fields
9. Handle errors gracefully
10. Show loading states
**All type inconsistencies fixed**
**All wizards tested end-to-end**
---
## Part 10: Future Enhancements (Not in Scope)
- Multi-step wizards for complex entities (e.g., Order with items as separate step)
- Real-time field validation as user types
- Field dependencies (show field X only if field Y has value Z)
- Draft saving (persist wizard state)
- Form analytics (track where users drop off)
- Accessibility improvements (ARIA labels, keyboard shortcuts)
- i18n support (Spanish translations)
---
## Conclusion
This guide provides everything needed to complete the wizard improvements. The pattern is established, components are built, and research is documented. Simply follow the pattern from the completed wizards for each remaining wizard.
**Key Principle**: Progressive disclosure + complete backend alignment + clean UX = excellent wizard experience.
---
## Appendix: Field Mapping Reference
### Recipe → Backend Mapping
```typescript
// Frontend (camelCase) → Backend (snake_case)
name name
finishedProductId finished_product_id
yieldQuantity yield_quantity
yieldUnit yield_unit
recipeCode recipe_code
difficultyLevel difficulty_level
prepTime prep_time_minutes
cookTime cook_time_minutes
restTime rest_time_minutes
optimalProductionTemp optimal_production_temperature
optimalHumidity optimal_humidity
isSeasonal is_seasonal
isSignatureItem is_signature_item
seasonStartMonth season_start_month
seasonEndMonth season_end_month
targetMargin target_margin_percentage
```
### Customer → Backend Mapping
```typescript
name name
customerCode customer_code
customerType customer_type
businessName business_name
addressLine1 address_line1
addressLine2 address_line2
postalCode postal_code
taxId tax_id
businessLicense business_license
paymentTerms payment_terms
creditLimit credit_limit
discountPercentage discount_percentage
customerSegment customer_segment
priorityLevel priority_level
preferredDeliveryMethod preferred_delivery_method
specialInstructions special_instructions
```
### Supplier → Backend Mapping
```typescript
name name
supplierCode supplier_code
supplierType supplier_type
taxId tax_id
registrationNumber registration_number
contactPerson contact_person
addressLine1 address_line1
addressLine2 address_line2
stateProvince state_province
postalCode postal_code
paymentTerms payment_terms
standardLeadTime standard_lead_time
creditLimit credit_limit
minimumOrderAmount minimum_order_amount
deliveryArea delivery_area
isPreferredSupplier is_preferred_supplier
autoApproveEnabled auto_approve_enabled
```
---
**Document Version**: 1.0
**Last Updated**: 2025-11-10
**Author**: Claude (AI Assistant)
**Status**: Reference Implementation Guide