githubModifier

ViewComponents - Passe Marché

This directory contains ViewComponent-based components for the Passe Marché application. ViewComponents provide a modern, testable, and maintainable approach to building reusable view logic.

What is ViewComponent?

ViewComponent is a framework for building reusable, testable & encapsulated view components in Ruby on Rails. It's an alternative to traditional Rails partials with several advantages:

  • Testable: Components can be unit tested in isolation

  • Encapsulated: Logic and templates are co-located

  • Performance: Components are faster than partials (10-100x in some cases)

  • Type Safety: Ruby classes provide better IDE support and refactoring

  • Documentation: Lookbook provides living documentation with previews

Directory Structure

app/components/
├── market_attribute_response/
│   ├── base_component.rb                                      # Shared base class
│   ├── fields/                                                # Reusable field components
│   │   ├── file_upload_field_component.rb
│   │   └── textarea_field_component.rb
│   ├── shared/                                                # Shared utility components
│   │   ├── document_item_component.rb
│   │   └── progress_bar_component.rb
│   │
│   │   # Simple Input Components
│   ├── text_input_component.rb                                # Text input field
│   ├── textarea_component.rb                                  # Multi-line text area
│   ├── email_input_component.rb                               # Email input field
│   ├── phone_input_component.rb                               # Phone number input
│   │
│   │   # File Upload Components
│   ├── file_upload_component.rb                               # Standard file upload
│   ├── inline_file_upload_component.rb                        # Inline file upload (auto-fillable)
│   ├── inline_url_input_component.rb                          # URL input field
│   │
│   │   # Composite Input Components
│   ├── file_or_textarea_component.rb                          # File OR text choice
│   ├── checkbox_with_document_component.rb                    # Checkbox with document upload
│   ├── radio_with_file_and_text_component.rb                  # Radio with file/text options
│   │
│   │   # Financial/Workforce Components
│   ├── capacite_economique_financiere_chiffre_affaires_global_annuel_component.rb
│   ├── capacite_economique_financiere_effectifs_moyens_annuels_component.rb
│   │
│   │   # Complex Repeatable Components
│   ├── capacites_techniques_professionnelles_outillage_echantillons_component.rb
│   ├── presentation_intervenants_component.rb
│   └── realisations_livraisons_component.rb

├── source_badge_component.rb                                  # Badge showing data source
└── source_badge_component.html.erb

app/views/market_attribute_response/{component_name}_component/
├── _form.html.erb     # Form mode sub-template
├── _display.html.erb  # Display mode sub-template
└── _{nested}.html.erb # Optional nested field templates (for repeatable components)

spec/components/
├── market_attribute_response/
│   ├── base_component_spec.rb
│   ├── fields/
│   │   └── {field}_component_spec.rb
│   ├── shared/
│   │   └── {shared}_component_spec.rb
│   └── {component}_component_spec.rb
└── source_badge_component_spec.rb

spec/components/previews/
└── market_attribute_response/
    └── {component}_component_preview.rb  # Lookbook previews

Using Components

In Views

Components are automatically used via dynamic resolution in the main views. The system tries to load a component first, then falls back to the old partial if the component doesn't exist:

Direct Usage

You can also render components directly:

Component Architecture

BaseComponent

All MarketAttributeResponse components inherit from MarketAttributeResponse::BaseComponent, which provides:

  • Mode Detection: form_mode?, display_mode?

  • Source Helpers: manual?, auto?, manual_after_api_failure?

  • Visibility Logic: show_value? (context-aware)

  • I18n Helpers: field_label, field_description, auto_filled_message

  • Attribute Access: market_attribute delegate

Component Parameters

Components accept these parameters:

Form Mode vs Display Mode

Form Mode (when form is present):

  • Uses form.fields_for :market_attribute_responses for nested attributes

  • Renders input fields or hidden fields (for auto-filled data)

  • Shows validation errors

  • Includes required indicators

Display Mode (when form is nil):

  • Shows read-only field values

  • Respects context for visibility (:web/:pdf hide auto values, :buyer shows all)

  • Renders source badges

  • Uses custom layout classes for PDF generation

Context-Aware Rendering

The :context parameter controls visibility:

  • :web - Candidate web view (summary page)

    • Hides auto-filled values for privacy

    • Shows manual values

  • :pdf - Candidate attestation PDF

    • Hides auto-filled values for privacy

    • Shows manual values

    • Uses PDF-specific layout classes

  • :buyer - Buyer's ZIP package

    • Shows ALL values (including auto-filled)

    • Buyer needs complete information

Testing Components

Unit Tests (RSpec)

Components have dedicated RSpec tests using ViewComponent test helpers:

Integration Tests (Cucumber)

Components are tested end-to-end through Cucumber features that test the full candidate flow.

Lookbook Previews

Lookbook provides a UI for viewing and documenting components. Access it at:

Development: http://localhost:3000/lookbook

Sandbox: http://sandbox-url/lookbook

Production: Not accessible (environment-restricted)

Creating Previews

Previews live in spec/components/previews/:

Creating New Components

1. Create Component Class

2. Create Component Template

3. Create Sub-templates

Form template (app/views/market_attribute_response/your_type_component/_form.html.erb):

Display template (app/views/market_attribute_response/your_type_component/_display.html.erb):

4. Create Component Spec

5. Create Lookbook Preview

6. Delete Old Partials

After testing, remove the old partials:

Best Practices

DO:

  • ✅ Inherit from BaseComponent for MarketAttributeResponse components

  • ✅ Use fields_for for nested attributes in form mode

  • ✅ Test components in isolation with RSpec

  • ✅ Create Lookbook previews for visual documentation

  • ✅ Use context parameter for visibility control

  • ✅ Follow DSFR CSS classes (fr-*)

  • ✅ Keep custom classes for PDF layout (field-layout-container)

  • ✅ Extract complex logic to component methods

DON'T:

  • ❌ Put business logic in components (use services/models)

  • ❌ Access instance variables directly (use parameters)

  • ❌ Skip the fields_for wrapper in forms

  • ❌ Forget to update component specs when changing templates

  • ❌ Hardcode labels (use i18n helpers)

  • ❌ Mix DSFR classes with custom layout classes

CSS Classes Reference

DSFR (French Design System)

  • fr-input, fr-input-group, fr-input--error

  • fr-label, fr-label--required

  • fr-hint-text, fr-error-text

  • fr-text--sm, fr-text--md, fr-text--mention-grey

  • fr-badge, fr-badge--success, fr-badge--warning

  • fr-mb-2w, fr-mb-4w

Custom (PDF Generation)

  • field-layout-container - Container for field display

  • field-layout-content - Content wrapper for PDF

Running Tests

Migration Status

All market attribute response partials have been migrated to ViewComponents:

Category
Components
Status

Shared

DocumentItemComponent, ProgressBarComponent

✅ Complete

Fields

FileUploadFieldComponent, TextareaFieldComponent

✅ Complete

Simple Inputs

TextInput, Textarea, Email, Phone

✅ Complete

File Uploads

FileUpload, InlineFileUpload, InlineUrlInput

✅ Complete

Composite

FileOrTextarea, CheckboxWithDocument, RadioWithFileAndText

✅ Complete

Financial

ChiffreAffairesGlobalAnnuel, EffectifsMoyensAnnuels

✅ Complete

Repeatable

OutillageEchantillons, PresentationIntervenants, RealisationsLivraisons

✅ Complete

Legacy partials removed:

  • All _*_form.html.erb partials

  • All _*_display.html.erb partials

  • shared/_progress_bar.html.erb, shared/_document_item.html.erb

  • fields/_file_upload_field.html.erb, fields/_textarea_field.html.erb

  • _source_badge.html.erb

Additional Resources

Questions?

Check the component specs or reach out to the development team.

Mis à jour

Ce contenu vous a-t-il été utile ?