Skip to content

SoundFoodPhygital/menu-client

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

60 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

SoundFood β€” Menu Intake Frontend

License: Apache-2.0 CI Node TypeScript React Vite Chakra UI Vitest Playwright i18next Docker Ask DeepWiki

A React + TypeScript web interface for collecting restaurant menu data and sending it to the SoundFood API.

SoundFood creates tailored music experiences for restaurants to enhance the perceived flavors of dishes. This app focuses on data collection: menus, dishes, and dish-specific sensory attributes (tastes, colors, textures, shapes, emotions, etc.).


Table of Contents


Features

Category Features
πŸ” Authentication Register, login, logout with token persistence
πŸ‘€ Profile View profile, update email, change password
πŸ“‹ Menus Create, edit, delete, save as draft, submit
🍽️ Dishes Add, edit, delete, reorder via drag & drop
🎨 Sensory Attributes Taste sliders, colors (up to 3), textures, shapes, emotions
🌍 i18n English and Italian with language switcher

Tech Stack

Category Technology
Framework React 18 + TypeScript
Build Tool Vite 5
UI Library Chakra UI 2.x
State React Context + Reducers
i18n i18next
HTTP Client Fetch API (custom wrapper)
Unit Testing Vitest
E2E Testing Playwright
Deployment Docker + Nginx / GitHub Pages

Project Structure

src/
β”œβ”€β”€ api/                 # API client, services, and types
β”‚   β”œβ”€β”€ client.ts        # HTTP client with auth handling
β”‚   β”œβ”€β”€ services.ts      # API service functions
β”‚   └── types.ts         # TypeScript interfaces
β”œβ”€β”€ features/            # Feature-based modules
β”‚   β”œβ”€β”€ auth/            # Authentication (context + UI)
β”‚   β”‚   β”œβ”€β”€ model/       # AuthContext
β”‚   β”‚   └── ui/          # LoginPage, ProfilePage
β”‚   └── menu/            # Menu management
β”‚       β”œβ”€β”€ hooks/       # useAttributes, etc.
β”‚       β”œβ”€β”€ model/       # Dish types
β”‚       └── ui/          # MenuForm, DishCard, etc.
β”œβ”€β”€ shared/              # Shared utilities and components
β”‚   β”œβ”€β”€ config/          # Constants
β”‚   β”œβ”€β”€ lib/             # Utilities (storage, helpers)
β”‚   └── ui/              # Reusable UI components
β”œβ”€β”€ hooks/               # Global custom hooks
β”œβ”€β”€ test/                # Test setup and utilities
β”œβ”€β”€ App.tsx              # Main app component
β”œβ”€β”€ i18n.ts              # i18next configuration
└── theme.ts             # Chakra UI theme

e2e/                     # Playwright E2E tests
public/locales/          # Translation files (EN/IT)
docs/                    # Documentation

More details in src/README.md.


Getting Started

Prerequisites

  • Node.js 20+ (CI uses Node 20)
  • Yarn (recommended) or npm
  • Access to a compatible SoundFood API

Installation

# Clone the repository
git clone https://github.com/SoundFoodPhygital/menu-client.git
cd menu-client

# Install dependencies
yarn install

# Start development server
yarn dev

Configuration

Create a .env file from the template:

cp .env.example .env
Variable Description Default
VITE_API_BASE_URL SoundFood API base URL http://localhost:5000
VITE_BASE_PATH Base path for hosting (production) /

Development

Available Scripts

Command Description
yarn dev Start development server
yarn build Build for production
yarn preview Preview production build
yarn lint Run ESLint
yarn test Run unit tests (watch mode)
yarn test:run Run unit tests once
yarn test:coverage Run tests with coverage
yarn test:e2e Run Playwright E2E tests

Testing

Unit Tests (Vitest)

yarn test          # Watch mode
yarn test:run      # Single run
yarn test:coverage # With coverage report

E2E Tests (Playwright)

yarn test:e2e         # Headless
yarn test:e2e:headed  # With browser UI
yarn test:e2e:debug   # Debug mode

Note: Full E2E coverage requires a reachable API or mock server.


Deployment

Docker

Build and run with Docker:

# Build image
docker build \
  -t menu-client \
  --build-arg VITE_BASE_PATH=/ \
  --build-arg VITE_API_BASE_URL=http://localhost:5000 \
  .

# Run container
docker run --rm -p 8080:80 menu-client

Or use Docker Compose:

docker compose up --build

Open http://localhost:8080.

GitHub Pages

The production build defaults to VITE_BASE_PATH=/menu-client/ for GitHub Pages:

yarn build
yarn deploy

Architecture

System Overview

flowchart TB
  subgraph Client["πŸ–₯️ Frontend (React + Vite)"]
    UI["UI Components"]
    Auth["Auth Feature"]
    Menu["Menu Feature"]
    API["API Client"]
    I18n["i18n"]
  end

  subgraph Backend["☁️ SoundFood API"]
    AuthAPI["Auth Service"]
    MenuAPI["Menu Service"]
    AttrAPI["Attributes Service"]
  end

  User((πŸ‘€ Restaurant User)) --> UI
  UI --> Auth
  UI --> Menu
  UI --> I18n
  Auth --> API
  Menu --> API
  API --> AuthAPI
  API --> MenuAPI
  API --> AttrAPI
Loading

Data Flow

Menu Submission Flow

sequenceDiagram
  autonumber
  actor U as πŸ‘€ User
  participant FE as Frontend
  participant API as SoundFood API

  U->>FE: Fill menu details
  U->>FE: Add dishes with attributes
  U->>FE: Click Submit

  FE->>API: POST /api/menus
  API-->>FE: { id: menuId }

  loop Each dish
    FE->>API: POST /api/menus/{menuId}/dishes
    API-->>FE: { id: dishId }
  end

  FE->>API: POST /api/menus/{menuId}/submit
  API-->>FE: { status: 'submitted' }

  FE-->>U: βœ… Success notification
  FE-->>U: Redirect to menus list
Loading

Menu CRUD Operations

sequenceDiagram
  autonumber
  actor U as πŸ‘€ User
  participant FE as Frontend
  participant API as SoundFood API

  Note over U,API: List Menus
  U->>FE: Open "My Menus"
  FE->>API: GET /api/menus
  API-->>FE: ApiMenu[]
  FE-->>U: Display menu list

  Note over U,API: View Details
  U->>FE: Select menu
  FE->>API: GET /api/menus/{id}
  FE->>API: GET /api/menus/{id}/dishes
  API-->>FE: Menu + Dishes
  FE-->>U: Display details

  Note over U,API: Delete Menu
  U->>FE: Delete menu
  FE->>API: DELETE /api/menus/{id}
  API-->>FE: { success }
  FE-->>U: Remove from list
Loading

Domain Model

classDiagram
  class User {
    +number id
    +string username
    +string role
    +datetime created_at
  }

  class Menu {
    +number id
    +string title
    +string description
    +MenuStatus status
    +datetime updated_at
  }

  class Dish {
    +number id
    +string name
    +string section
    +TasteProfile tastes
    +string[] colors
  }

  class TasteProfile {
    +number sweet
    +number bitter
    +number sour
    +number salty
    +number umami
    +number piquant
    +number fat
    +number temperature
  }

  class Attribute {
    +number id
    +string description
  }

  class MenuStatus {
    <<enumeration>>
    draft
    submitted
  }

  User "1" --> "*" Menu : owns
  Menu "1" --> "*" Dish : contains
  Menu --> MenuStatus
  Dish "1" --> "1" TasteProfile
  Dish "*" --> "*" Attribute : emotions
  Dish "*" --> "*" Attribute : textures
  Dish "*" --> "*" Attribute : shapes
Loading

State Management

Menu Status Lifecycle

stateDiagram-v2
  [*] --> Draft: Create menu

  Draft --> Draft: Edit / Save
  Draft --> Submitted: Submit

  Submitted --> Draft: Revert
  Submitted --> Submitted: Edit

  state Draft {
    [*] --> Valid
    Valid: βœ“ Title required
    Valid: β—‹ Dishes optional
  }

  state Submitted {
    [*] --> Complete
    Complete: βœ“ Title required
    Complete: βœ“ At least 1 dish
  }
Loading

Authentication State

stateDiagram-v2
  [*] --> Checking: App loads

  Checking --> Authenticated: Token valid
  Checking --> Unauthenticated: No token

  Unauthenticated --> Authenticating: Login/Register
  Authenticating --> Authenticated: Success
  Authenticating --> Unauthenticated: Failure

  Authenticated --> Unauthenticated: Logout
Loading

Documentation

Document Description
README.md This file β€” project overview
src/README.md Source code architecture details
docs/REQUIREMENTS.md User stories and functional requirements
.github/copilot-instructions.md Development guidelines for Copilot

Contributing

Contributions are welcome! Please follow the guidelines in .github/copilot-instructions.md:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Follow DRY and SOLID principles
  4. Write tests for new features
  5. Add translations (EN + IT)
  6. Commit your changes
  7. Open a Pull Request

License

This project is licensed under the Apache-2.0 License β€” see the LICENSE file for details.


SoundFood β€” Enhancing flavors through music 🎡🍽️

Contributors 2

  •  
  •  

Languages