Files
bakery-ia/WIZARD_IMPROVEMENTS_IMPLEMENTATION_GUIDE.md
Claude e3021b839e 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.
2025-11-10 09:38:30 +00:00

17 KiB

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:

// 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:

// 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:
{
  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

<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

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:

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:

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):

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):

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:

// 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:

// 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:

unit_cost: number;

Hook uses:

unit_price: number;

Solution: Search and replace all unit_priceunit_cost in inventory hooks/services, OR update backend to accept both.

Files to check:

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

// 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

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

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