Skip to content

candicejoyballarta/ulamami

Repository files navigation

🍳 Ulamami

A recipe management app for Filipino mothers preserving family traditions

Ulamami combines three meaningful words:

  • Ulam (Tagalog) - the main dish in Filipino cuisine
  • Umami (Japanese) - the fifth basic taste, representing depth of flavor
  • Mami (Filipino) - an affectionate term for "mommy"

πŸ“‹ Table of Contents


✨ Features

Core Functionality

  • Recipe Management: Full CRUD operations (Create, Read, Update, Delete)
  • Smart Search: Real-time search with debouncing and request cancellation
  • Favorites System: Optimistic UI updates with automatic rollback on failure
  • Filtering: Filter recipes by category and difficulty level
  • Persistent Storage: All data saved to localStorage with automatic initialization

User Experience

  • Responsive Design: Works seamlessly on desktop, tablet, and mobile
  • Loading States: Clear visual feedback for all async operations
  • Error Handling: User-friendly error messages with automatic retry
  • Optimistic Updates: Instant UI feedback for all user actions

πŸ›  Tech Stack

Frontend

  • Framework: React 18 with TypeScript
  • Build Tool: Vite 5.x
  • Styling: Tailwind CSS 3.x
  • UI Components: shadcn/ui (Radix UI primitives)
  • Icons: Lucide React

Data Layer

  • API Simulation: Axios + axios-mock-adapter
  • State Management: React Context API + Custom Hooks
  • Storage: localStorage with TypeScript-safe wrappers
  • Validation: Custom validator functions with detailed error messages

Development Tools

  • Language: TypeScript (ES2020+)
  • Package Manager: npm
  • Code Quality: ESLint + TypeScript strict mode

πŸš€ Development Process

1. Planning Phase

  • Initial Research: Studied async patterns and best practices
  • Architecture Design: Planned layered architecture (UI β†’ API β†’ Helpers β†’ Storage)
  • Component Structure: Designed component hierarchy and data flow
  • Color Palette: Created Filipino-inspired theme (Adobo red, Umami brown, Turmeric gold)

2. Core Implementation

Foundation

  • Set up Vite + React + TypeScript project
  • Configured Tailwind CSS and shadcn/ui
  • Created type definitions and interfaces
  • Built mock API layer with axios-mock-adapter

Features

  • Implemented CRUD operations with optimistic UI
  • Built custom hooks (useRecipes, useFavorites, useSearch)
  • Created reusable UI components
  • Added validation layer with helpful error messages

Async Patterns

  • Implemented request cancellation with AbortController
  • Added retry logic with exponential backoff
  • Built debounced search with race condition prevention
  • Added optimistic updates with rollback functionality

Polish

  • Refined UI/UX based on testing
  • Added loading states and error handling
  • Improved accessibility
  • Documentation and code cleanup

3. Challenges & Solutions

Challenge 1: Race Conditions in Search

  • Problem: When user types quickly, older search results could overwrite newer ones
  • Solution: Implemented AbortController to cancel in-flight requests when new search starts
  • Learning: Understanding cleanup functions in useEffect and proper request lifecycle management

Challenge 2: Optimistic UI Rollback

  • Problem: Need to revert UI changes when API calls fail, but maintain correct state
  • Solution: Used refs to store original state before optimistic update, then restore on error
  • Learning: Refs are perfect for storing values that don't need to trigger re-renders

Challenge 3: TypeScript Error Handling

  • Problem: TypeScript doesn't know the type of caught errors (always unknown)
  • Solution: Created getErrorMessage utility function with type guards
  • Learning: Proper TypeScript error handling patterns and type narrowing

Challenge 4: Preventing State Updates After Unmount

  • Problem: setState calls after component unmounts causing React warnings
  • Solution: Used isMountedRef to track mount status and skip updates if unmounted
  • Learning: Component lifecycle management and proper cleanup in useEffect

Challenge 5: Duplicate Favorite Toggles

  • Problem: Rapid clicking on favorite button sends multiple API requests
  • Solution: Implemented version tracking to ignore stale responses and only apply latest
  • Learning: Advanced concurrency patterns and request deduplication strategies

πŸ”§ Tools & Libraries

Core Dependencies

{
  "react": "^18.3.1",
  "react-dom": "^18.3.1",
  "axios": "^1.7.9",
  "axios-mock-adapter": "^2.1.0",
  "lucide-react": "^0.468.0",
  "clsx": "^2.1.1",
  "tailwind-merge": "^2.6.0"
}

UI Component Library

  • shadcn/ui: Copy-paste component library built on Radix UI
    • Used components: Button, Card, Dialog, Input, Textarea, Badge, Toast, ScrollArea
    • Why chosen: Accessible, customizable, no runtime dependency bloat
    • Contribution: Customized theme colors to match Filipino-inspired palette

Development Dependencies

{
  "typescript": "^5.6.2",
  "vite": "^6.0.3",
  "@vitejs/plugin-react": "^4.3.4",
  "tailwindcss": "^3.4.17",
  "autoprefixer": "^10.4.20",
  "postcss": "^8.4.49",
  "@types/node": "^22.10.2"
}

AI Tools Used

Claude (Anthropic)

  • Used for:
    • Architectural guidance and design pattern discussions
    • Explaining async JavaScript concepts (AbortController, Promise handling, race conditions)
    • Reviewing code structure and identifying potential issues
    • Debugging TypeScript type errors
    • Understanding best practices for React hooks and state management
    • Discussing trade-offs between different implementation approaches
  • How it helped:
    • Provided conceptual explanations using different examples (game systems, library management) to help me understand patterns
    • Guided me through thinking processes rather than just providing code
    • Helped me understand WHY certain approaches are better, not just HOW to implement them
    • Pointed out edge cases and potential bugs before they became issues
  • Note: All code was written by hand to ensure learning and deep understanding

πŸ“š External Resources

Documentation

Code References

  • shadcn/ui component source code - Learned accessibility patterns and component composition
  • Axios documentation - Request interceptors and cancellation
  • React Query source code - Studied optimistic update patterns (adapted approach without the library)

πŸƒ Setup Instructions

Prerequisites

  • Node.js: Version 18 or higher (LTS recommended)
  • npm: Comes with Node.js
  • Browser: Modern browser with ES2020+ support

Installation

  1. Clone the repository

    git clone <repository-url>
    cd ulamami
  2. Install dependencies

    npm install
  3. Run the development server

    npm run dev
  4. Open in browser

    Navigate to http://localhost:5173
    

Available Scripts

npm run dev      # Start development server with HMR
npm run build    # Build for production
npm run preview  # Preview production build locally
npm run lint     # Run ESLint (if configured)

Environment Variables

Create a .env file in the root directory:

VITE_API_URL=http://localhost:5173/api
VITE_DB_KEY=ulamami_db

πŸ“ Project Structure

ulamami/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ components/              # React components
β”‚   β”‚   β”œβ”€β”€ ui/                  # shadcn/ui components (auto-generated)
β”‚   β”‚   β”‚   β”œβ”€β”€ button.tsx
β”‚   β”‚   β”‚   β”œβ”€β”€ card.tsx
β”‚   β”‚   β”‚   β”œβ”€β”€ dialog.tsx
β”‚   β”‚   β”‚   β”œβ”€β”€ input.tsx
β”‚   β”‚   β”‚   └── ...
β”‚   β”‚   β”œβ”€β”€ RecipeCard.tsx       # Recipe display card
β”‚   β”‚   β”œβ”€β”€ RecipeDetailsDialog.tsx  # Full recipe view modal
β”‚   β”‚   β”œβ”€β”€ RecipeFormDialog.tsx     # Create/edit recipe form
β”‚   β”‚   └── SearchBar.tsx        # Search input with debouncing
β”‚   β”‚
β”‚   β”œβ”€β”€ contexts/                # React Context providers
β”‚   β”‚   └── RecipesContext.tsx   # Global recipe state management
β”‚   β”‚
β”‚   β”œβ”€β”€ hooks/                   # Custom React hooks
β”‚   β”‚   β”œβ”€β”€ useRecipes.ts        # Recipe CRUD with optimistic UI
β”‚   β”‚   β”œβ”€β”€ useFavorites.ts      # Favorites with version tracking
β”‚   β”‚   └── useSearch.ts         # Debounced search (if separated)
β”‚   β”‚
β”‚   β”œβ”€β”€ services/                # Data layer
β”‚   β”‚   β”œβ”€β”€ api/
β”‚   β”‚   β”‚   └── axiosInstance.ts # Mock API with simulated latency/failures
β”‚   β”‚   β”œβ”€β”€ helpers.ts           # Business logic functions
β”‚   β”‚   β”œβ”€β”€ storage.ts           # localStorage wrapper utilities
β”‚   β”‚   └── validators.ts        # Validation functions (if separated)
β”‚   β”‚
β”‚   β”œβ”€β”€ models/                  # TypeScript interfaces
β”‚   β”‚   β”œβ”€β”€ IRecipe.ts           # Recipe type definition
β”‚   β”‚   └── IDatabase.ts         # Database structure type
β”‚   β”‚
β”‚   β”œβ”€β”€ data/                    # Static data
β”‚   β”‚   └── seedData.ts          # Initial recipe data
β”‚   β”‚
β”‚   β”œβ”€β”€ lib/                     # Utilities and config
β”‚   β”‚   β”œβ”€β”€ utils.ts             # Helper functions (retryWithBackoff, cn, etc.)
β”‚   β”‚   β”œβ”€β”€ env.ts               # Environment configuration
β”‚   β”‚   └── validators.ts        # Validation logic (if centralized)
β”‚   β”‚
β”‚   β”œβ”€β”€ App.tsx                  # Root component
β”‚   β”œβ”€β”€ main.tsx                 # App entry point
β”‚   └── index.css                # Global styles + Tailwind imports
β”‚
β”œβ”€β”€ public/                      # Static assets
β”œβ”€β”€ index.html                   # HTML template
β”œβ”€β”€ components.json              # shadcn/ui configuration
β”œβ”€β”€ tailwind.config.js           # Tailwind configuration
β”œβ”€β”€ tsconfig.json                # TypeScript configuration
β”œβ”€β”€ vite.config.ts               # Vite configuration
β”œβ”€β”€ package.json                 # Dependencies and scripts
└── README.md                    # This file

πŸ€” Future Improvements

If I had more time, I would add:

  • User Authentication: Multi-user support with Firebase/Supabase
  • Image Upload: Direct image upload instead of URLs
  • Recipe Ratings: Star ratings and reviews
  • Cooking Timer: Built-in timer for recipe steps
  • Meal Planning: Weekly meal planner calendar
  • Shopping List: Auto-generate from recipe ingredients
  • Recipe Sharing: Share recipes via link or social media
  • Print View: Printer-friendly recipe format
  • Nutrition Info: Automatic nutrition calculation
  • Unit Conversion: Convert measurements (cups ↔ grams)
  • Offline Support: Service worker for offline access
  • Dark Mode: Full dark theme support
  • Recipe Import: Import from URLs (using web scraping)

πŸ‘€ Author

Your Name


πŸ“ License

This project was created as a take-home assignment and is available for educational purposes.


πŸ™ Acknowledgments

  • Inspiration: Filipino home cooking and the mothers who preserve family recipes
  • UI Design: shadcn/ui component library and Tailwind CSS
  • Cultural Heritage: The rich culinary traditions of Filipino cuisine

πŸ“Š Project Statistics

  • Lines of Code: ~3,500 (excluding node_modules)
  • Components: 15+ React components
  • Custom Hooks: 3 specialized hooks
  • Type Definitions: 100% TypeScript coverage
  • Async Patterns: 7 advanced patterns implemented
  • Test Coverage: Manual testing of all async edge cases

Built with ❀️ for Filipino home cooks

About

🍳 Ulamami: Recipe app for Filipino moms. Ulam + Umami + Mami. Built with React + Vite,. Mock API + Tailwind + shadcn.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages