ProjectsFoodahTechnical Documentation
Technical Documentation0 min read

Foodah

Live Restaurant Discovery Platform with Swiggy API Integration

Project Walkthrough

Foodah - Full Walkthrough

Foodah - Full Walkthrough

Click to play walkthrough

Foodah: Live Restaurant Discovery Platform

A high-performance food ordering platform demonstrating advanced React patterns, real-time API integration, and production-ready architecture.


Key Metrics at a Glance

MetricValueImpact
🚀 Load Reduction40%Route-level code splitting with React.lazy()
Performance60fpsSmooth scrolling through thousands of listings
📊 Data Size14,000+ JSON LinesOptimized rendering of massive datasets

Introduction

Foodah is a sophisticated restaurant discovery and food ordering interface that demonstrates mastery over advanced React patterns and real-time API integration. The platform fetches live data directly from Swiggy's hosted API, processing over 14,000 lines of JSON restaurant data with graceful error handling across deeply nested objects.

Built with modern React 18, the application showcases production-ready implementations of code splitting, custom hooks for network detection and image fallbacks, shimmer UI for perceived performance, and Redux Toolkit for global state management—all bundled with Parcel for optimized delivery.


ResourceLink
🌐 Live Applicationfoodah.vercel.app
💻 Source CodeGitHub Repository

Table of Contents

  1. The Challenge
  2. The Solution
  3. Business Impact
  4. Technologies and Tools Used
  5. Project Overview
  6. Key Features
  7. Technical Deep Dive
  8. Challenges Faced
  9. Deployment and Testing
  10. Screenshots Gallery
  11. What I Learned
  12. Future Improvements
  13. Conclusion
  14. FAQs
  15. Project Badges

The Challenge

Food ordering applications face significant technical hurdles when dealing with real-world data at scale:

ChallengeImpactComplexity
Large Dataset Rendering14,000+ lines of JSON causing performance degradationHigh
API InconsistenciesFrequently changing data structures breaking the UIHigh
Broken ImagesMissing or invalid image URLs affecting user experienceMedium
Offline HandlingUsers left confused without network status feedbackMedium
Deeply Nested DataSwiggy API returns complex, nested object structuresHigh

User Expectations:

  • Instant loading with no perceptible lag
  • Smooth 60fps scrolling across thousands of restaurant cards
  • No layout shifts or broken image placeholders
  • Clear feedback when network connectivity is lost

The Solution

A comprehensive architecture leveraging modern React patterns and performance optimization techniques:

Code Splitting & Lazy Loading

javascript
const WL_recommendations = lazy(() => import("./src/pages/Wishlist")); // Route with Suspense wrapper { path: '/wishlist', element: ( <Suspense fallback={<LoadingFallback />}> <WL_recommendations /> </Suspense> ), }

Custom Hooks for Resilience

  • useOnlineStatus: Detects network connectivity with navigator.online events
  • useRestaurantMenu: Optimized menu fetching with data transformation
  • useFallbackImage: Intelligent image error handling with random alternatives

Shimmer UI for Perceived Performance

  • Skeleton loading states matching actual content layout
  • Animated placeholders reducing perceived wait time
  • Different shimmer variants for list and menu views

Graceful Degradation

  • Optional chaining (?.) throughout for safe property access
  • Error boundaries preventing full app crashes
  • User-friendly offline messages with retry capabilities

Business Impact

Quantified results demonstrating production-ready quality:

MetricBeforeAfterImprovement
Initial Load Time~3.2s~1.9s40% faster
Scroll PerformanceJanky60fpsButter smooth
Broken ImagesVisibleZero100% handled
Offline UXApp breaksClear messageGraceful degradation
Bundle SizeMonolithicSplit routesOptimized delivery

Technologies and Tools Used

Frontend Core

TechnologyVersionPurpose
React18.2.0UI library with hooks-based architecture
JavaScriptES6+Modern syntax with optional chaining
Tailwind CSS3.4.4Utility-first styling system
React Router DOM6.24.0Client-side routing with nested routes
Redux Toolkit2.2.6Predictable global state management

Build Tools

ToolVersionPurpose
Parcel2.12.0Zero-config bundler with HMR
PostCSS8.4.38CSS processing and Autoprefixer
LightningCSS1.25.1Fast CSS minification

APIs & Services

ServicePurpose
Swiggy APILive restaurant data with 14K+ JSON lines
GitHub APIDynamic developer profile information
EmailJSServerless contact form submissions

Supporting Libraries

LibraryPurpose
React IconsScalable SVG icon components
React ReduxReact bindings for Redux
AbortController PolyfillRequest cancellation support

Project Overview

Core Capabilities

FeatureDescription
🍕 Restaurant DiscoveryBrowse restaurants with live Swiggy data (14K+ JSON lines)
🔍 Smart SearchReal-time filtering by restaurant name with reset
Rating FilterShow only top-rated restaurants (4.5+)
📋 Menu BrowsingNested accordion menus with category grouping
🛒 Shopping CartRedux-powered cart with order summary, taxes, and delivery fee
🥗 Veg/Non-Veg IndicatorsVisual diet classification for each menu item
👤 Developer ProfileGitHub API integration with live repo stats
📧 Contact FormEmailJS + WhatsApp integration for messaging
🔐 Authentication UILogin/Signup forms with Google sign-in button
📱 Responsive NavbarMobile modal menu with cart badge counter
📅 GitHub CalendarContribution calendar visualization

Architecture Diagram

┌─────────────────────────────────────────────────────────┐
│                     React Application                    │
├─────────────────────────────────────────────────────────┤
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────┐  │
│  │   Navbar    │  │    Body     │  │     Footer      │  │
│  │  (Router)   │  │  (Outlets)  │  │   (Developer)   │  │
│  └─────────────┘  └─────────────┘  └─────────────────┘  │
├─────────────────────────────────────────────────────────┤
│                    Custom Hooks Layer                    │
│  ┌────────────────┐ ┌────────────────┐ ┌─────────────┐  │
│  │ useOnlineStatus│ │useRestaurantMenu│ │useFallbackImg│ │
│  └────────────────┘ └────────────────┘ └─────────────┘  │
├─────────────────────────────────────────────────────────┤
│                    State Management                      │
│  ┌─────────────────────────────────────────────────────┐│
│  │           Redux Toolkit (cartSlice)                 ││
│  └─────────────────────────────────────────────────────┘│
├─────────────────────────────────────────────────────────┤
│                     API Layer                            │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐   │
│  │  Swiggy API  │  │  GitHub API  │  │   EmailJS    │   │
│  └──────────────┘  └──────────────┘  └──────────────┘   │
└─────────────────────────────────────────────────────────┘

Project Structure

Foodah/
├── App.js                 # Root component with router config
├── App.css                # Global styles
├── index.html             # Entry HTML
├── package.json           # Dependencies and scripts
├── vercel.json            # Deployment configuration
├── tailwind.config.js     # Tailwind customization
├── Assets/                # Static images and fallbacks
│   ├── 1.jpg - 7.jpg      # Fallback food images
│   ├── Logo.png           # App logo
│   ├── main logo.png      # Developer branding
│   └── veg.png, nonVeg.png# Diet indicators
└── src/
    ├── components/
    │   ├── Navbar.js          # Responsive nav with mobile modal
    │   ├── Footer.js          # Social links and quick navigation
    │   ├── RestaurantCard.js  # Card with fallback image handling
    │   ├── RestaurantCategory.js  # Accordion toggle component
    │   ├── RestaurantItemList.js  # Menu items with add/remove
    │   ├── ScrollToTop.js     # Route change scroll reset
    │   └── About/             # About section components
    │       ├── AboutHeader/   # Header sub-components
    │       ├── AboutMe.js     # Personal info section
    │       ├── GithubProfile.js   # Live GitHub user data
    │       ├── GithubCalendar.js  # Contribution calendar
    │       ├── RepoData.js    # Foodah repo statistics
    │       └── Skills.js      # Tech stack display
    ├── pages/
    │   ├── Body.js            # Homepage with search/filter
    │   ├── RestaurantMenu.js  # Menu with nested categories
    │   ├── Cart.js            # Cart with order summary
    │   ├── Contact.js         # EmailJS + WhatsApp form
    │   ├── About.js           # Toggle profile + GitHub stats
    │   ├── Auth.js            # Login/Signup with Google
    │   ├── Wishlist.js        # Lazy-loaded coming soon
    │   ├── Shimmer.js         # List and menu skeletons
    │   └── Error.js           # useRouteError display
    └── utils/
        ├── constant.js        # CDN_URL, API endpoints
        ├── appStore.js        # Redux store configuration
        ├── cartSlice.js       # add/remove/clear actions
        ├── useOnlineStatus.js # Network detection hook
        ├── useRestaurantMenu.js # Menu fetching hook
        └── useFallbackImage.js  # Image error handling hook

Key Features

1. useOnlineStatus Custom Hook

Detects network connectivity and provides real-time status updates:

javascript
import { useEffect, useState } from 'react'; const useOnlineStatus = () => { const [isOnline, setIsOnline] = useState(true); useEffect(() => { const handleOnline = () => setIsOnline(true); const handleOffline = () => setIsOnline(false); window.addEventListener('online', handleOnline); window.addEventListener('offline', handleOffline); return () => { window.removeEventListener('online', handleOnline); window.removeEventListener('offline', handleOffline); }; }, []); return isOnline; }; export default useOnlineStatus;

Usage in Component:

javascript
const onlineStatus = useOnlineStatus(); if (onlineStatus === false) { return ( <div className="flex items-center justify-center min-h-screen bg-red-100"> <h1 className="text-red-600"> Looks like you are offline!! Please check your internet connection </h1> </div> ); }

2. useRestaurantMenu Custom Hook

Fetches and transforms complex nested menu data:

javascript
const useRestaurantMenu = (resId) => { const [res, setRes] = useState(null); const [categories, setCategories] = useState(null); const [nestedCategories, setNestedCategories] = useState(null); useEffect(() => { fetchMenu(); }, []); const fetchMenu = async () => { const data = await fetch(resAPI_URL + resId); const response = await data.json(); // Safe extraction with optional chaining const restaurantData = response?.data?.cards[2]?.card?.card?.info; setRes(restaurantData); // Filter item categories const categoriesData = response?.data?.cards[4]?.groupedCard ?.cardGroupMap?.REGULAR?.cards .filter((i) => i.card?.card?.["@type"] === "type.googleapis.com/swiggy.presentation.food.v2.ItemCategory" ); setCategories(categoriesData); // Filter nested categories const nestedCategoriesData = response?.data?.cards[4]?.groupedCard ?.cardGroupMap?.REGULAR?.cards .filter((i) => i.card?.card?.["@type"] === "type.googleapis.com/swiggy.presentation.food.v2.NestedItemCategory" ); setNestedCategories(nestedCategoriesData); }; return [res, categories, nestedCategories]; };

3. useFallbackImage Custom Hook

Handles broken images with intelligent random alternatives:

javascript
import { useState } from "react"; import img1 from "../../Assets/1.jpg"; import img2 from "../../Assets/2.jpg"; // ... more imports const fallbackImages = [img1, img2, img3, img4, img5, img6, img7, img8]; const useFallbackImage = () => { const getRandomFallbackImage = () => { const randomIndex = Math.floor(Math.random() * fallbackImages.length); return fallbackImages[randomIndex]; }; const handleImageError = (e) => { e.target.src = getRandomFallbackImage(); }; return handleImageError; }; export default useFallbackImage;

Usage:

javascript
const handleImageError = useFallbackImage(); <img src={restaurantImage} alt={restaurantName} onError={handleImageError} />

4. Swiggy API Integration

Fetching live restaurant data with robust error handling:

javascript
const fetchData = async () => { try { const data = await fetch(menuAPI_URL); const json = await data.json(); // Dynamic data extraction for changing API structure const checkJsonData = (json) => { for(let i = 0; i < json?.data?.cards.length; i++) { let checkData = json?.data?.cards[i]?.card?.card ?.gridElements?.infoWithStyle?.restaurants; if(checkData !== undefined) { return checkData; } } }; const responseRes = checkJsonData(json); setListOfRestaurants(responseRes); setFilteredRestaurants(responseRes); } catch(error) { console.error("Error in fetching data:", error); } };

5. Responsive Navbar with Mobile Modal

A fully responsive navigation with mobile hamburger menu and cart badge:

javascript
const Navbar = () => { const [isMobile, setIsMobile] = useState(window.innerWidth < 769); const [showModal, setShowModal] = useState(false); const cartItems = useSelector((store) => store.cart.items); const onlineStatus = useOnlineStatus(); useEffect(() => { const handleResize = () => setIsMobile(window.innerWidth < 769); window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); }, []); // Cart badge with item count {cartItems.length > 0 && ( <div className="absolute -top-3 -right-1 bg-primary-yellow"> {cartItems.length} </div> )} // Network status indicator {onlineStatus ? <MdOutlineNetworkWifi /> : <RiSignalWifiOffLine />} };

Features:

  • Window resize listener for responsive breakpoint detection
  • Modal overlay for mobile navigation
  • Real-time cart item count badge
  • Visual network status indicator (online/offline icons)

6. Cart with Order Summary Calculations

Complete shopping cart with itemized billing:

javascript
const Cart = () => { const cartItems = useSelector((store) => store.cart.items); // Calculate order totals const subtotal = cartItems.reduce( (total, item) => total + (item.card.info.price || item.card.info.defaultPrice || 0) / 100, 0 ); const deliveryCharge = 42; const tax = subtotal * 0.1; // 10% tax const totalCost = subtotal + deliveryCharge + tax; return ( <div className="order-summary"> <div>Subtotal:{subtotal.toFixed(2)}</div> <div>Delivery Fee:{deliveryCharge.toFixed(2)}</div> <div>Taxes & Charges:{tax.toFixed(2)}</div> <div className="font-bold">Total:{totalCost.toFixed(2)}</div> </div> ); };

7. Restaurant Category Accordion

Collapsible menu categories with toggle animation:

javascript
const RestaurantCategory = ({ catData }) => { const [showDropdown, setShowDropdown] = useState(false); // Handle nested categories from API const nestedCat = Array.isArray(catData?.categories) ? catData.categories : []; return ( <div className="accordion-container"> <div onClick={() => setShowDropdown(!showDropdown)}> <h1>{catData?.title} ({catData?.itemCards?.length || nestedCat.length})</h1> {showDropdown ? <MdExpandLess /> : <MdExpandMore />} </div> {showDropdown && <RestaurantItemList itemCardsData={catData?.itemCards} />} {showDropdown && nestedCat.map((i, idx) => ( <RestaurantItemList key={idx} itemCardsData={i.itemCards} /> ))} </div> ); };

8. Veg/Non-Veg Classification

Visual diet indicators for each menu item:

javascript
const RestaurantItemList = ({ itemCardsData, isCart = false }) => { return itemCardsData?.map((i, index) => ( <div key={index} className="menu-item"> {/* Veg/Non-Veg indicator */} <img src={i?.card?.info?.itemAttribute?.vegClassifier === "VEG" ? vegIcon : nonVegIcon} alt={i?.card?.info?.itemAttribute?.vegClassifier} className="w-4 h-4" /> {/* Price with fallback */} <span>{((i?.card?.info?.defaultPrice || i?.card?.info?.price) / 100).toFixed(2)}</span> {/* Dynamic Add/Remove button */} <button onClick={() => isCart ? handleRemove(index) : handleAdd(i)}> {isCart ? "REMOVE" : "ADD"} </button> </div> )); };

9. GitHub API Integration

Live developer profile and repository data:

javascript
// GithubProfile.js - User data const GithubProfile = () => { const [userData, setUserData] = useState(null); useEffect(() => { const fetchData = async () => { const response = await fetch('https://api.github.com/users/AmanSuryavanshi-1'); const json = await response.json(); setUserData(json); }; fetchData(); }, []); return ( <div> <img src={userData?.avatar_url} alt="Avatar" /> <p>{userData?.public_repos} Repos | {userData?.followers} Followers</p> <p>{userData?.bio}</p> </div> ); }; // RepoData.js - Repository statistics const RepoData = () => { const [repoData, setRepoData] = useState(null); useEffect(() => { fetch('https://api.github.com/repos/AmanSuryavanshi-1/foodah') .then(res => res.json()) .then(data => setRepoData(data)); }, []); return ( <div> <p>Language: {repoData?.language}</p> <p>Stars: {repoData?.stargazers_count}</p> <p>Forks: {repoData?.forks_count}</p> <p>Last Updated: {new Date(repoData?.updated_at).toLocaleDateString()}</p> </div> ); };

10. Authentication UI

Login/Signup toggle with Google sign-in:

javascript
const Auth = () => { const [isLogin, setIsLogin] = useState(true); return ( <div className="auth-form"> <h1>{isLogin ? 'Login' : 'Sign Up'}</h1> {/* Full Name field only for signup */} {!isLogin && <input type="text" placeholder="Full Name" required />} <input type="email" placeholder="Email address" required /> <input type="password" placeholder="Password" required /> {isLogin && ( <div> <input type="checkbox" /> Remember me <a href="#">Forgot password?</a> </div> )} <button>{isLogin ? 'Sign In' : 'Sign Up'}</button> {/* Google OAuth button */} <button className="google-btn"> <FcGoogle /> Continue with Google </button> <p> {isLogin ? "Don't have an account?" : "Already have an account?"} <button onClick={() => setIsLogin(!isLogin)}> {isLogin ? 'Sign Up' : 'Sign In'} </button> </p> </div> ); };

Technical Deep Dive

Shimmer UI Implementation

Two variants for different loading contexts:

List Shimmer (Homepage):

javascript
const Shimmer = ({ type = 'list' }) => { if (type === 'menu') { return <ShimmerRestaurantMenu />; } return ( <div className="p-8 font-serif mx-28 bg-primary-bgColor"> <div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4"> {[...Array(8)].map((_, index) => ( <div key={index} className="animate-pulse bg-white rounded-lg"> <div className="w-full h-40 mb-4 bg-gray-300 rounded-lg"></div> <div className="w-3/4 h-4 mb-2 bg-gray-300 rounded"></div> <div className="w-1/2 h-4 bg-gray-300 rounded"></div> </div> ))} </div> </div> ); };

Benefits:

  • Matches actual content layout to prevent layout shifts
  • Uses CSS animate-pulse for smooth animation
  • Responsive grid matching real restaurant cards

Code Splitting with React.lazy()

Route-level splitting for optimized initial load:

javascript
import React, { Suspense, lazy } from 'react'; // Lazy load non-critical routes const WL_recommendations = lazy(() => import("./src/pages/Wishlist")); const appRouter = createBrowserRouter([ { path: '/', element: <AppLayout />, children: [ { path: '/', element: <Body /> }, { path: '/about', element: <About /> }, { path: '/contact', element: <Contact /> }, { path: '/wishlist', element: ( <Suspense fallback={ <h1 className="text-2xl font-semibold text-primary-light"> Resources are getting ready </h1> }> <WL_recommendations /> </Suspense> ), }, { path: '/cart', element: <Cart /> }, { path: '/restaurants/:resId', element: <RestaurantMenu /> }, ], errorElement: <Error />, }, ]);

Redux Toolkit State Management

Cart slice with add, remove, and clear actions:

javascript
import { createSlice } from "@reduxjs/toolkit"; const cartSlice = createSlice({ name: 'cart', initialState: { items: [], }, reducers: { addItem: (state, action) => { state.items.push(action.payload); }, clearCart: (state) => { state.items.length = 0; }, removeItem: (state, action) => { state.items.splice(action.payload, 1); }, }, }); export const { addItem, clearCart, removeItem } = cartSlice.actions; export default cartSlice.reducer;

Custom Tailwind Theme Configuration

Extended Tailwind with custom branding colors and fonts:

javascript
// tailwind.config.js module.exports = { content: ["./src/**/*.{html,js,ts,jsx,tsx}"], theme: { extend: { colors: { primary: { light: '#ffffcc', // Cream/yellow tint yellow: '#FDDA24', // Brand yellow (buttons, accents) dark: '#403F45', // Dark gray (cards, overlays) white: '#FFFFFF', // Pure white grey: '#393956', // Blue-gray (borders) bgColor: '#222223', // Near-black background }, }, fontFamily: { 'sans': ['Poppins', 'sans-serif'], // Body text 'serif': ['Cinzel', 'serif'], // Headings }, animation: { profile: 'profile__animate 8s ease-in-out infinite 1s', }, }, }, };

Color Usage:

  • primary-bgColor: Main app background
  • primary-yellow: CTAs, buttons, highlights
  • primary-light: Text, borders, hover states
  • primary-dark: Cards, modal overlays

Challenges Faced

ChallengeRoot CauseSolution
Large Data Handling14,000+ JSON lines causing slow rendersImplemented conditional rendering and filtered data extraction
Frequent Data Structure ChangesSwiggy API updates without noticeDynamic data extraction loop checking multiple card indices
CORS Issues in DevelopmentBrowser blocking cross-origin requestsUsed CORS proxy API (foodfire.onrender.com) wrapping Swiggy endpoints
SPA 404 on RefreshVercel serving 404 for client-side routesAdded rewrites in vercel.json to redirect all to index.html
Image Loading FailuresInvalid or expired CDN URLs from APICreated useFallbackImage hook with random alternatives
Deeply Nested ObjectsAPI returns complex nested structuresApplied optional chaining (?.) throughout data access

CORS Proxy Solution

Since browsers block direct Swiggy API calls, we use a proxy:

javascript
// Instead of direct Swiggy API // ❌ 'https://www.swiggy.com/mapi/homepage/getCards?lat=...' // Use CORS proxy // ✅ 'https://foodfire.onrender.com/api/restaurants?lat=...' export const menuAPI_URL = "https://foodfire.onrender.com/api/restaurants?lat=21.1702401&lng=72.83106070000001";

Deployment and Testing

Vercel Configuration

SPA routing fix for client-side navigation:

json
{ "rewrites": [ { "source": "/(.*)", "destination": "/" } ] }

This ensures all routes are handled by React Router instead of returning 404.

Deployment Steps

  1. Build the Project

    bash
    npm run build
  2. Push to GitHub

    bash
    git add . git commit -m "Deploy: production build" git push origin main
  3. Connect to Vercel

    • Import repository at vercel.com/new
    • Auto-detected Parcel framework settings
    • Automatic builds on every push

Testing Strategy

Test TypeMethodCoverage
Component TestingManual browser testingAll pages and interactions
Network ResilienceChrome DevTools offline modeuseOnlineStatus hook
Image FallbackInvalid image URLsuseFallbackImage hook
Responsive DesignChrome DevTools device modeAll breakpoints
Route TestingDirect URL navigationAll routes including refresh

Desktop Views

Homepage - Restaurant GridRestaurant Menu
Desktop Homepage
Desktop Homepage
Restaurant Menu
Restaurant Menu

Mobile View

Mobile View
Mobile View

What I Learned

Technical Skills

SkillApplication
Custom HooksCreated reusable logic for network detection, data fetching, and error handling
API IntegrationHandled complex nested JSON with optional chaining and dynamic extraction
Performance OptimizationImplemented code splitting, lazy loading, and shimmer UI
State ManagementUsed Redux Toolkit for predictable cart state
Error BoundariesGraceful error handling preventing full app crashes
Responsive DesignTailwind utility classes for mobile-first development

Soft Skills

SkillApplication
Problem SolvingDebugged CORS issues and API structure changes
AdaptabilityHandled evolving API responses without breaking the app
DocumentationCreated comprehensive technical documentation
DebuggingUsed Chrome DevTools for network and performance analysis

Future Improvements

PriorityFeatureDescription
🔴 HighUser AuthenticationImplement Firebase Auth for user accounts
🔴 HighOrder HistoryPersist orders with user profiles
🟡 MediumPayment IntegrationAdd Stripe/Razorpay for checkout
🟡 MediumLocation DetectionAuto-detect user location for restaurant filtering
🟡 MediumPWA SupportAdd service worker for offline capabilities
🟢 LowReviews & RatingsAllow users to rate and review restaurants
🟢 LowDark Mode ToggleUser preference for theme switching
🟢 LowInfinite ScrollLoad more restaurants as user scrolls

Conclusion

Foodah demonstrates production-ready React development practices through:

AreaSkills Demonstrated
ArchitectureComponent-based design, custom hooks, Redux state management
PerformanceCode splitting, lazy loading, optimized re-renders
ResilienceError boundaries, offline handling, image fallbacks
API IntegrationComplex data extraction, CORS handling, optional chaining
User ExperienceShimmer UI, responsive design, instant feedback
DeploymentVercel hosting, SPA routing, production builds

This project showcases the ability to build scalable, maintainable applications that handle real-world complexities like evolving APIs and large datasets.


FAQs

Q1: Why use a CORS proxy instead of direct Swiggy API calls?

Browsers block cross-origin requests for security. The CORS proxy (foodfire.onrender.com) acts as a middleware that fetches Swiggy data server-side and returns it with proper CORS headers.

Q2: How does the shimmer UI improve perceived performance?

Shimmer placeholders matching the actual content layout give users a sense of progress during loading, reducing perceived wait time compared to blank screens or spinners.

Q3: Why Redux Toolkit instead of Context API for cart?

Redux Toolkit provides predictable state updates, time-travel debugging, and scales better for complex state logic. Context API works well for simpler cases but Redux shines for cart operations with multiple actions.

Q4: How does the app handle Swiggy API structure changes?

The checkJsonData function dynamically iterates through response cards to find restaurant data at any index, making the app resilient to minor API structure changes.

Q5: What's the purpose of the useFallbackImage hook?

When Swiggy CDN URLs expire or fail to load, this hook catches the error event and replaces the broken image with a random food-related image from a local collection, ensuring no ugly broken image icons.


Project Badges

ReactReact JavaScriptJavaScript ReduxRedux Tailwind CSSTailwind CSS ParcelParcel React RouterReact Router VercelVercel APIAPI


Built with ☕ and 💙 by Aman Suryavanshi

PortfolioPortfolio LinkedInLinkedIn GitHubGitHub