React Bangla Logo
ReactāĻŦāĻžāĻ‚āϞāĻž

đŸŽŦ Movie Portal App āĻŦāĻžāύāĻžāύ⧋āϰ āϏāĻŽā§āĻĒā§‚āĻ°ā§āĻŖ āĻ—āĻ˛ā§āĻĒ â€” āĻ•āύāϏ⧇āĻĒā§āϟ āĻĨ⧇āϕ⧇ āĻĒā§āϰ⧋āĻĄāĻžāĻ•āĻļāύ-āϰ⧇āĻĄāĻŋ āϕ⧋āĻĄ

React 19, Vite 8, Tailwind CSS v4 āφāϰ React Router v8 āĻĻāĻŋāϝāĻŧ⧇ āĻāĻ•āĻĻāĻŽ āĻļ⧁āϰ⧁ āĻĨ⧇āϕ⧇ āĻļ⧇āώ — āĻāĻ•āϟāĻŋ āĻĒā§‚āĻ°ā§āĻŖāĻžāĻ™ā§āĻ— Movie Portal App āĻŦāĻžāύāĻžāύ⧋āϰ Step by Step āĻšāĻžāϤ⧇-āĻ•āϞāĻŽā§‡ āĻ—āĻžāχāĻĄāĨ¤

āϚāϞ⧁āύ, āφāϜ āφāĻŽāϰāĻž āĻāĻ•āϟāĻž āϏāĻŋāύ⧇āĻŽāĻž āĻšāϞ āĻŦāĻžāύāĻžāĻŦā§‹ — āϕ⧋āĻĄ āĻĻāĻŋāϝāĻŧ⧇āĨ¤ đŸŽŦ

āĻ­āϝāĻŧ āĻĒāĻžāĻŦ⧇āύ āύāĻž, āĻĒāĻĒāĻ•āĻ°ā§āύ āϞāĻžāĻ—āĻŦ⧇ āύāĻžāĨ¤ āĻ•āĻŋāĻ¨ā§āϤ⧁ āĻāĻ•āϟāĻž āϜāĻŋāύāĻŋāϏ āϞāĻžāĻ—āĻŦ⧇: āϧ⧈āĻ°ā§āϝāĨ¤ āĻ•āĻžāϰāĻŖ āφāĻŽāϰāĻž āĻļ⧁āϧ⧁ āĻāĻ•āϟāĻž āĻŽā§āĻ­āĻŋ āϞāĻŋāĻ¸ā§āϟ āϏāĻžāϜāĻŋāϝāĻŧ⧇ āϰāĻžāĻ–āĻŦā§‹ āύāĻž — āĻāĻ•āϟāĻž āĻĒ⧁āϰ⧋ Production-Grade Frontend Architecture āĻĻāĻžāρāĻĄāĻŧ āĻ•āϰāĻžāĻŦā§‹, āĻāĻ•āĻĻāĻŽ āĻ¸ā§āĻ•ā§āĻ°ā§āϝāĻžāϚ āĻĨ⧇āϕ⧇āĨ¤ āĻĒā§āĻ˛ā§āϝāĻžāύāĻŋāĻ‚, āĻĄāĻŋāϜāĻžāχāύ, āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āϟ, āĻ¸ā§āĻŸā§‡āϟ āĻŽā§āϝāĻžāύ⧇āϜāĻŽā§‡āĻ¨ā§āϟ — āϏāĻŦāĻ•āĻŋāϛ⧁āĨ¤

āϤāĻžāĻšāϞ⧇ āĻ¸ā§āĻ•ā§āϰāĻŋāύ⧇ āĻšā§‹āĻ– āϰāĻžāϖ⧁āύ — āĻļ⧁āϰ⧁ āĻ•āϰāĻž āϝāĻžāĻ•āĨ¤


Step 1: Movie Portal āφāϏāϞ⧇ āϕ⧀ āϜāĻŋāύāĻŋāϏ? đŸŽĨ

āϕ⧋āύ⧋ āĻĒā§āϰāĻœā§‡āĻ•ā§āĻŸā§‡ āĻšāĻžāϤ āĻĻ⧇āĻ“āϝāĻŧāĻžāϰ āφāϗ⧇ āϏāĻŦāĻšā§‡āϝāĻŧ⧇ āϜāϰ⧁āϰāĻŋ āĻ•āĻžāϜāϟāĻž āĻšāϞ⧋ — āĻĄā§‹āĻŽā§‡āχāύ āĻŦā§‹āĻāĻžāĨ¤ āĻŽāĻžāύ⧇, āϝ⧇ āĻĒā§āϰ⧋āĻĄāĻžāĻ•ā§āϟāϟāĻž āφāĻŽāϰāĻž āĻŦāĻžāύāĻžāϤ⧇ āϝāĻžāĻšā§āĻ›āĻŋ, āĻŦāĻžāĻ¸ā§āϤāĻŦ⧇ āϏ⧇āϟāĻž āϕ⧀ āĻāĻŦāĻ‚ āϕ⧀āĻ­āĻžāĻŦ⧇ āĻ•āĻžāϜ āĻ•āϰ⧇ — āĻāϟāĻž āύāĻž āĻŦ⧁āĻā§‡ āϕ⧋āĻĄ āϞāĻŋāĻ–āϤ⧇ āĻŦāϏāĻž āĻŽāĻžāύ⧇ āĻ¸ā§āĻ•ā§āϰāĻŋāĻĒā§āϟ āύāĻž āĻĒāĻĄāĻŧ⧇āχ āĻļ⧁āϟāĻŋāĻ‚ āĻļ⧁āϰ⧁ āĻ•āϰ⧇ āĻĻ⧇āĻ“āϝāĻŧāĻžāĨ¤

"Movie Portal" āĻļāĻŦā§āĻĻāϟāĻž āĻļ⧁āύāϞ⧇ āϏāĻžāϧāĻžāϰāĻŖāϤ āϝāĻž āĻŽāĻžāĻĨāĻžāϝāĻŧ āφāϏ⧇ āϤāĻž āĻšāϞ⧋:

āĻāĻŽāύ āĻāĻ•āϟāĻŋ āĻ“āϝāĻŧ⧇āĻŦāϏāĻžāχāϟ āĻŦāĻž āĻ…ā§āϝāĻžāĻĒ, āϝ⧇āĻ–āĻžāύ⧇ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀āϰāĻž āϏāĻŋāύ⧇āĻŽāĻž āϖ⧁āρāĻœā§‡ āĻĻ⧇āĻ–āϤ⧇ āĻĒāĻžāϰ⧇, āϤāĻĨā§āϝ āϜāĻžāύāϤ⧇ āĻĒāĻžāϰ⧇, āĻŸā§āϰ⧇āϞāĻžāϰ āĻĻ⧇āĻ–āϤ⧇ āĻĒāĻžāϰ⧇ — āĻāĻŦāĻ‚ āĻ•āĻ–āύ⧋ āĻ•āĻ–āύ⧋ āϰ⧇āĻ¨ā§āϟ āĻŦāĻž āĻ¸ā§āĻŸā§āϰāĻŋāĻŽāĻ“ āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇āĨ¤

āĻŸā§‡āĻ•āύāĻŋāĻ•ā§āϝāĻžāϞ āĻ­āĻžāώāĻžāϝāĻŧ āĻŦāϞāϞ⧇, āĻāϟāĻž āĻāĻ•āϟāĻž content-catalog application — āϝāĻžāϰ āĻŽā§‚āϞ āĻ•āĻžāϜ āĻšāϞ⧋ āĻāĻ•āϟāĻž structured dataset (āĻŽā§āĻ­āĻŋ āĻ•ā§āϝāĻžāϟāĻžāϞāĻ—)-āϕ⧇ browsable, searchable āφāϰ interactive UI-āϤ⧇ āϰ⧂āĻĒāĻžāĻ¨ā§āϤāϰ āĻ•āϰāĻžāĨ¤ āĻāĻ•āϜāύ React developer āĻšāĻŋāϏ⧇āĻŦ⧇ āφāĻĒāύāĻŋ āϝāĻĻāĻŋ āĻāĻ•āϟāĻž āĻ­āĻžāϞ⧋ content catalog architecture āĻŦ⧁āĻā§‡ āĻĢ⧇āϞ⧇āύ, āϤāĻžāĻšāϞ⧇ āĻ…āύ⧇āĻ• āϧāϰāύ⧇āϰ app āĻŦāĻžāύāĻžāύ⧋āϰ base āϤ⧈āϰāĻŋ āĻšā§Ÿā§‡ āϝāĻžā§ŸāĨ¤ āĻāϰ āϤāĻŋāύāϟāĻž āĻŽā§‚āϞ āĻŦāĻŋāĻ˛ā§āĻĄāĻŋāĻ‚ āĻŦā§āϞāĻ•:

  • āĻāĻ•āϟāĻž data layer, āϝ⧇āĻ–āĻžāύ⧇ āĻ…āύ⧇āĻ•āϗ⧁āϞ⧋ āϏāĻŋāύ⧇āĻŽāĻžāϰ āĻŽā§‡āϟāĻžāĻĄā§‡āϟāĻž (āύāĻžāĻŽ, āĻĒā§‹āĻ¸ā§āϟāĻžāϰ, āϰ⧇āϟāĻŋāĻ‚, āĻ­āĻŋāω, āĻĒā§āϰāĻžāχāϏ) āϜāĻŽāĻž āĻĨāĻžāϕ⧇āĨ¤
  • āĻāĻ•āϟāĻž discovery layer, āϝ⧇āĻ–āĻžāύ⧇ āχāωāϜāĻžāϰ āϏāĻžāĻ°ā§āϚ āφāϰ āĻĢāĻŋāĻ˛ā§āϟāĻžāϰ āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇āĨ¤
  • āĻāĻ•āϟāĻž detail/interaction layer, āϝ⧇āĻ–āĻžāύ⧇ āĻāĻ•āϟāĻž āύāĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āϟ āφāχāĻŸā§‡āĻŽā§‡āϰ āĻĄāĻŋāĻŸā§‡āχāϞāϏ āĻĻ⧇āĻ–āĻž āϝāĻžāϝāĻŧ, āφāϰ āĻ…ā§āϝāĻžāĻ•āĻļāύ (āϝ⧇āĻŽāύ āĻ•āĻžāĻ°ā§āĻŸā§‡ āϝ⧋āĻ— āĻ•āϰāĻž) āύ⧇āĻ“āϝāĻŧāĻž āϝāĻžāϝāĻŧāĨ¤

āĻšā§‡āύāĻž āωāĻĻāĻžāĻšāϰāĻŖ: Netflix āĻāĻ•āϟāĻž Movie Portal (āϏāĻžāĻĨ⧇ Streaming Service-āĻ“ āĻŦāĻŸā§‡)āĨ¤ IMDB āφāϰ⧇āĻ•āϟāĻž — āϝ⧇āĻ–āĻžāύ⧇ āϤāĻĨā§āϝ, āĻŸā§āϰ⧇āϞāĻžāϰ, āϰ⧇āϟāĻŋāĻ‚, āϰāĻŋāĻ­āĻŋāω āϏāĻŦ āĻāĻ• āϜāĻžāϝāĻŧāĻ—āĻžāϝāĻŧāĨ¤

đŸ”ĩ āϤāĻžāĻšāϞ⧇ āϕ⧇āω āϝāĻĻāĻŋ āĻŦāϞ⧇ "Movie Portal Website āĻŦāĻžāύāĻžāĻ“" — āϏāĻšāϜ āĻ­āĻžāώāĻžāϝāĻŧ āĻāϰ āĻŽāĻžāύ⧇ āĻĻāĻžāρāĻĄāĻŧāĻžāϝāĻŧ:

āĻāĻŽāύ āĻāĻ•āϟāĻž āĻ“āϝāĻŧ⧇āĻŦāϏāĻžāχāϟ, āϝ⧇āĻ–āĻžāύ⧇ āĻ…āύ⧇āĻ• āϏāĻŋāύ⧇āĻŽāĻžāϰ āϤāĻĨā§āϝ āĻĨāĻžāĻ•āĻŦ⧇, āφāϰ āĻŽāĻžāύ⧁āώ āϏāĻšāĻœā§‡āχ āύāĻŋāĻœā§‡āϰ āĻĒāĻ›āĻ¨ā§āĻĻ⧇āϰ āϏāĻŋāύ⧇āĻŽāĻž āϖ⧁āρāĻœā§‡ āύāĻŋāϤ⧇ āĻĒāĻžāϰāĻŦ⧇āĨ¤

āφāĻŽāϰāĻž āĻāχ āϟāĻŋāωāĻŸā§‹āϰāĻŋāϝāĻŧāĻžāϞ⧇ āϝ⧇āϟāĻž āĻŦāĻžāύāĻžāĻŦā§‹, āϏ⧇āϟāĻž āĻāĻ•āϟ⧁ āĻ¸ā§āĻĒ⧇āϏāĻŋāĻĢāĻŋāĻ• — āĻāĻ•āϟāĻž Cinema Rental PortalāĨ¤ āĻŽāĻžāύ⧇ āĻŽā§āĻ­āĻŋ āĻŦā§āϰāĻžāωāϜ āĻ•āϰāĻž, āĻĄāĻŋāĻŸā§‡āχāϞāϏ āĻĻ⧇āĻ–āĻž, āφāϰ āĻāĻ•āϟāĻž Cart-āĻ­āĻŋāĻ¤ā§āϤāĻŋāĻ• rental flow āĻĒāĻžāϰ āĻšāϝāĻŧ⧇ āϝāĻžāĻ“āϝāĻŧāĻžāĨ¤

Data Model ↓ Fetch Data ↓ Transform Data ↓ Display Cards/List ↓ Search + Filter + Sort ↓ User Interaction


Step 2: āϕ⧋āĻĄ āϞ⧇āĻ–āĻžāϰ āφāϗ⧇ — āĻ¸ā§āĻ•ā§āϰāĻŋāĻĒā§āϟ āϰ⧇āĻĄāĻŋ āĻ•āϰ⧁āύ 📝

āĻŦāĻĄāĻŧ āĻĄāĻŋāϰ⧇āĻ•ā§āϟāϰāϰāĻž āĻļ⧁āϟāĻŋāĻ‚ āĻļ⧁āϰ⧁ āĻ•āϰāĻžāϰ āφāϗ⧇ āĻĒ⧁āϰ⧋ āĻ¸ā§āĻ•ā§āϰāĻŋāĻĒā§āϟ, āĻ¸ā§āĻŸā§‹āϰāĻŋāĻŦā§‹āĻ°ā§āĻĄ, āĻļāϟ-āϞāĻŋāĻ¸ā§āϟ āϰ⧇āĻĄāĻŋ āϰāĻžāϖ⧇āύāĨ¤ āĻĒā§āϰ⧋āĻ—ā§āϰāĻžāĻŽāĻŋāĻ‚āϝāĻŧ⧇āĻ“ āĻ āĻŋāĻ• āĻāĻ•āχ āύāĻŋāϝāĻŧāĻŽ — āϕ⧋āĻĄ āϞ⧇āĻ–āĻžāϰ āφāϗ⧇ Requirement Analysis āφāϰ System Design āύāĻž āĻ•āϰāϞ⧇, āĻĒāϰ⧇ āĻ—āĻŋāϝāĻŧ⧇ Component re-architecture, state management āϜāϟ āφāϰ technical debt-āĻāϰ āĻĒāĻžāĻšāĻžāĻĄāĻŧ āϜāĻŽā§‡ āϝāĻžāϝāĻŧāĨ¤ āφāϰ āĻŦāĻŋāĻļā§āĻŦāĻžāϏ āĻ•āϰ⧁āύ, āĻŽāĻžāĻāĻĒāĻĨ⧇ āĻĒ⧁āϰ⧋ āϏ⧇āϟ āϭ⧇āϙ⧇ āφāĻŦāĻžāϰ āĻŦāĻžāύāĻžāύ⧋āϰ āĻšā§‡āϝāĻŧ⧇ āĻ•āĻˇā§āĻŸā§‡āϰ āφāϰ āĻ•āĻŋāϛ⧁ āύ⧇āχāĨ¤

ā§§. āĻĒā§āϰāĻœā§‡āĻ•ā§āĻŸā§‡āϰ āĻ¸ā§āϕ⧋āĻĒ āĻ āĻŋāĻ• āĻ•āϰ⧁āύ

  • App-āĻāϰ āωāĻĻā§āĻĻ⧇āĻļā§āϝ āϕ⧀? (āĻŽā§āĻ­āĻŋ āĻŦā§āϰāĻžāωāϜ āĻ•āϰāĻž, āϰ⧇āϟāĻŋāĻ‚ āĻĻ⧇āĻ–āĻž, āϏāĻžāĻ°ā§āϚ āĻ•āϰāĻž, āĻ•āĻžāĻ°ā§āĻŸā§‡ āϝ⧋āĻ— āĻ•āϰ⧇ āϰ⧇āĻ¨ā§āϟ āĻ•āϰāĻž)
  • āĻĻāĻ°ā§āĻļāĻ• āĻ•āĻžāϰāĻž? āϕ⧋āύ āĻŦāϝāĻŧāϏ⧇āϰ, āϕ⧋āύ āĻĄāĻŋāĻ­āĻžāχāϏ āĻĨ⧇āϕ⧇ āφāϏāĻŦ⧇ — āĻŽā§‹āĻŦāĻžāχāϞ-āĻĢāĻžāĻ°ā§āĻ¸ā§āϟ āύāĻžāĻ•āĻŋ āĻĄā§‡āĻ¸ā§āĻ•āϟāĻĒ-āĻĢāĻžāĻ°ā§āĻ¸ā§āϟ?
  • Functional Requirements — āĻ…ā§āϝāĻžāĻĒ āφāϏāϞ⧇ āϕ⧀ āϕ⧀ āĻ•āϰāϤ⧇ āĻĒāĻžāϰāĻŦ⧇āĨ¤
  • Non-Functional Requirements — āĻĒāĻžāϰāĻĢāϰāĻŽā§āϝāĻžāĻ¨ā§āϏ, āϰ⧇āϏāĻĒāύāϏāĻŋāĻ­āύ⧇āϏ, āĻ…ā§āϝāĻžāĻ•ā§āϏ⧇āϏāĻŋāĻŦāĻŋāϞāĻŋāϟāĻŋāĨ¤

⧍. āĻĢāĻŋāϚāĻžāϰ āϞāĻŋāĻ¸ā§āϟ āĻ“ āχāωāϜāĻžāϰ āĻ¸ā§āĻŸā§‹āϰāĻŋ

āϤāĻžāĻĒāϏ āĻ­āĻžāχ āĻāχ āĻ­āĻŋāĻĄāĻŋāĻ“āϤ⧇ āĻĻ⧇āĻ–āĻŋāϝāĻŧ⧇āϛ⧇āύ, āĻāĻ•āϟāĻž āϏāĻŋāύ⧇āĻŽāĻž āϰ⧇āĻ¨ā§āϟāĻžāϞ āĻĒā§‹āĻ°ā§āϟāĻžāϞ⧇ āφāϏāϞ⧇ āϕ⧀ āϕ⧀ āĻĢāĻŋāϚāĻžāϰ āĻĨāĻžāĻ•āĻž āĻĻāϰāĻ•āĻžāϰ:

āĻĢāĻŋāϚāĻžāϰāϗ⧁āϞ⧋āϕ⧇ āĻļ⧁āϧ⧁ āĻāĻ•āϟāĻž āϞāĻŋāĻ¸ā§āϟ āĻšāĻŋāϏ⧇āĻŦ⧇ āύāĻž āϰ⧇āϖ⧇ User Story āĻĢāϰāĻŽā§āϝāĻžāĻŸā§‡ āϞāĻŋāĻ–āϞ⧇ āĻāĻ•āϟāĻž āĻŦāĻžāĻĄāĻŧāϤāĻŋ āϏ⧁āĻŦāĻŋāϧāĻž āĻĒāĻžāĻ“āϝāĻŧāĻž āϝāĻžāϝāĻŧ — āĻĒā§āϰāϤāĻŋāϟāĻž āĻĢāĻŋāϚāĻžāϰ⧇āϰ āĻĒ⧇āĻ›āύ⧇āϰ āĻŸā§‡āĻ•āύāĻŋāĻ•ā§āϝāĻžāϞ āϚāĻžāĻšāĻŋāĻĻāĻžāϟāĻž (āϕ⧋āύ state, āϕ⧋āύ component āϞāĻžāĻ—āĻŦ⧇) āφāϗ⧇āχ āĻ¸ā§āĻĒāĻˇā§āϟ āĻšāϝāĻŧ⧇ āϝāĻžāϝāĻŧ:

FeatureUser StoryTechnical Implication
Movie GridāĻāĻ•āϜāύ āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀ āĻšāĻŋāϏ⧇āĻŦ⧇ āφāĻŽāĻŋ āϏāĻŦ āĻŽā§āĻ­āĻŋ āĻāĻ•āϟāĻž āĻ—ā§āϰāĻŋāĻĄā§‡ āĻĻ⧇āĻ–āϤ⧇ āϚāĻžāχ — āĻĒā§‹āĻ¸ā§āϟāĻžāϰ, āϰ⧇āϟāĻŋāĻ‚, āĻ•ā§āϝāĻžāϟāĻžāĻ—āϰāĻŋ āĻ“ āĻĒā§āϰāĻžāχāϏāϏāĻšMovieGrid + MovieCard āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āϟ, movies array-āϤ⧇ .map()
Movie Details ModalāφāĻŽāĻŋ āϝ⧇āϕ⧋āύ⧋ āĻŽā§āĻ­āĻŋ āĻ•āĻžāĻ°ā§āĻĄā§‡ āĻ•ā§āϞāĻŋāĻ• āĻ•āϰ⧇ āĻāϰ āĻŦāĻŋāĻ¸ā§āϤāĻžāϰāĻŋāϤ āĻŽāĻĄāĻžāϞ⧇ āĻĻ⧇āĻ–āϤ⧇ āϚāĻžāχ"selected movie" state, Modal āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āϟ, createPortal
Add to CartāφāĻŽāĻŋ āĻŽā§āĻ­āĻŋ āĻ•āĻžāĻ°ā§āĻŸā§‡ āϝ⧋āĻ— āĻ•āϰāϤ⧇ āϚāĻžāχ, āφāϗ⧇ āĻĨ⧇āϕ⧇ āĻĨāĻžāĻ•āϞ⧇ āĻ“āϝāĻŧāĻžāĻ°ā§āύāĻŋāĻ‚ āĻĒ⧇āϤ⧇ āϚāĻžāχGlobal Cart state (Context + Reducer), duplicate-check action
Cart CounterāĻ•āĻžāĻ°ā§āĻŸā§‡ āĻ•ā§āϞāĻŋāĻ• āĻ•āϰāϞ⧇ āφāĻŽāĻŋ āĻŽā§āĻ­āĻŋāϰ āύāĻžāĻŽ, āĻĒā§āϰāĻžāχāϏ āĻ“ āϏāĻ‚āĻ–ā§āϝāĻž āĻĻ⧇āĻ–āϤ⧇ āϚāĻžāχDerived state — cart items āĻĨ⧇āϕ⧇ āĻ•āĻžāωāĻ¨ā§āϟ āĻ“ āĻŸā§‹āϟāĻžāϞ āĻĒā§āϰāĻžāχāϏ āĻ•ā§āϝāĻžāϞāϕ⧁āϞ⧇āϟ
Remove from CartāφāĻŽāĻŋ āĻ•āĻžāĻ°ā§āϟ āĻĨ⧇āϕ⧇ āĻŽā§āĻ­āĻŋ āϰāĻŋāĻŽā§āĻ­ āĻ•āϰāϤ⧇ āϚāĻžāχ, āϏāĻŦ āϰāĻŋāĻŽā§āĻ­ āĻ•āϰāϞ⧇ empty message āĻĻ⧇āĻ–āϤ⧇ āϚāĻžāχREMOVE_FROM_CART reducer action, conditional rendering
Theme SwitchāφāĻŽāĻŋ Light/Dark āĻĨāĻŋāĻŽā§‡āϰ āĻŽāĻ§ā§āϝ⧇ āϟāĻ—āϞ āĻ•āϰāϤ⧇ āϚāĻžāχGlobal Theme state (Context), localStorage persistence

āĻĒā§āϰāĻĨāĻŽ āĻĒāĻ°ā§āĻŦ⧇ āφāĻŽāϰāĻž āĻāχ āĻĢāĻŋāϚāĻžāϰāϗ⧁āϞ⧋āχ āĻ•āĻ­āĻžāϰ āĻ•āϰāĻŦ:

  • āĻŽā§āĻ­āĻŋ āϞāĻŋāĻ¸ā§āϟ āϰ⧇āĻ¨ā§āĻĄāĻžāϰ āĻ•āϰāĻž — āĻĒā§āϰāϤāĻŋāϟāĻž āĻ•āĻžāĻ°ā§āĻĄā§‡ āĻĢāĻŸā§‹, āϰ⧇āϟāĻŋāĻ‚, āĻ•ā§āϝāĻžāϟāĻžāĻ—āϰāĻŋ āĻ“ āĻĒā§āϰāĻžāχāϏ āĻĻ⧇āĻ–āĻžāύ⧋āĨ¤
  • āϕ⧋āύ⧋ āĻŽā§āĻ­āĻŋ āĻ•āĻžāĻ°ā§āĻĄā§‡ āĻ•ā§āϞāĻŋāĻ• āĻ•āϰāϞ⧇ āĻĄāĻŋāĻŸā§‡āχāϞāϏ āĻŽāĻĄāĻžāϞ āĻĒāĻĒ-āφāĻĒ āĻšāϝāĻŧ⧇ āĻĢ⧁āϞ āχāύāĻĢā§‹ āĻĻ⧇āĻ–āĻžāύ⧋āĨ¤
  • āĻ•āĻžāĻ°ā§āϟ āĻŦāĻžāϟāύ⧇ āĻ•ā§āϞāĻŋāĻ• āĻ•āϰāϞ⧇ āĻŽā§āĻ­āĻŋ āĻ•āĻžāĻ°ā§āĻŸā§‡ āϝ⧋āĻ— āĻšāĻŦ⧇, āĻ•āĻžāωāĻ¨ā§āϟ +ā§§ āĻšāĻŦ⧇, āφāϗ⧇ āĻĨ⧇āϕ⧇ āĻĨāĻžāĻ•āϞ⧇ āĻ“āϝāĻŧāĻžāĻ°ā§āύāĻŋāĻ‚ āĻĻ⧇āĻ–āĻžāĻŦ⧇āĨ¤
  • āĻ•āĻžāĻ°ā§āϟ āĻĨ⧇āϕ⧇ āĻŽā§āĻ­āĻŋ āϰāĻŋāĻŽā§āĻ­ āĻ•āϰāĻžāϰ āĻĢāĻŋāϚāĻžāϰ — āϏāĻŦ āϰāĻŋāĻŽā§āĻ­ āĻšāϞ⧇ empty message āĻĻ⧇āĻ–āĻžāĻŦ⧇āĨ¤

(Search, Watchlist, Review System, Login — āĻāϗ⧁āϞ⧋ āĻĒāϰ⧇āϰ āϏāĻŋāϜāύ⧇āϰ āϜāĻ¨ā§āϝ āϤ⧋āϞāĻž āĻĨāĻžāĻ•āϞ⧋ 😉)

ā§Š. UI/UX āĻĄāĻŋāϜāĻžāχāύ āϰ⧇āĻĄāĻŋ āĻ•āϰ⧁āύ

āĻ•ā§āϝāĻžāĻŽā§‡āϰāĻž āϚāĻžāϞāĻžāύ⧋āϰ āφāϗ⧇ āĻ¸ā§āĻŸā§‹āϰāĻŋāĻŦā§‹āĻ°ā§āĻĄ āϞāĻžāϗ⧇ — āĻ…ā§āϝāĻžāĻĒ⧇āϰ āĻ•ā§āώ⧇āĻ¤ā§āϰ⧇āĻ“ āϤāĻžāχāĨ¤ Figma āĻŦāĻž āϝ⧇āϕ⧋āύ⧋ āϟ⧁āϞ⧇ āĻĢ⧁āϞ UI āĻĄāĻŋāϜāĻžāχāύ āĻŦāĻžāύāĻžāύ, āύāĻŋāĻœā§‡ āύāĻž āĻĒāĻžāϰāϞ⧇ āĻĄāĻŋāϜāĻžāχāύāĻžāϰ⧇āϰ āϏāĻžāĻšāĻžāĻ¯ā§āϝ āύāĻŋāύāĨ¤ āĻļ⧁āϰ⧁āϤ⧇āχ āĻāĻ•āϟāĻž Design System (color tokens, spacing scale, typography scale) āĻ āĻŋāĻ• āĻ•āϰ⧇ āύāĻŋāϞ⧇ āĻĒāϰ⧇ Tailwind āĻ•āύāĻĢāĻŋāĻ—āĻžāϰ⧇āĻļāύ āĻ•āϰāĻžāϟāĻž āĻ…āύ⧇āĻ• āϏāĻšāϜ āĻšāϝāĻŧ⧇ āϝāĻžāϝāĻŧāĨ¤

āĻāχ āĻ…ā§āϝāĻžāĻĒ⧇āϰ āĻĄāĻŋāϜāĻžāχāύ:

ā§§āĨ¤ Movie Portal Homepage

Full Page Screenshot

⧍āĨ¤ Movie Details Modal

Full Page Screenshot

ā§ŠāĨ¤ Cart Page

Full Page Screenshot

ā§ĒāĨ¤ Theme Switch UI

switch theme

ā§Ē. āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āϟ āĻŦā§āϰ⧇āĻ•āĻĄāĻžāωāύ — UI-āϕ⧇ āϟ⧁āĻ•āϰ⧋ āϟ⧁āĻ•āϰ⧋ āĻ•āϰ⧁āύ

āĻĄāĻŋāϜāĻžāχāύ āϰ⧇āĻĄāĻŋ āĻšāϝāĻŧ⧇ āϗ⧇āϞ⧇ āĻĒāϰ⧇āϰ āĻ•āĻžāϜ — āĻĒ⧁āϰ⧋ UI-āϕ⧇ āϛ⧋āϟ āϛ⧋āϟ, āĻ¸ā§āĻŦāĻžāϧ⧀āύ āĻ…āĻ‚āĻļ⧇ āĻ­āĻžāĻ— āĻ•āϰāĻžāĨ¤ āĻāϕ⧇āχ āĻŦāϞ⧇ UI DecompositionāĨ¤ āĻŽā§‚āϞ āύ⧀āϤāĻŋ āĻāĻ•āϟāĻžāχ — Single Responsibility: āĻĒā§āϰāϤāĻŋāϟāĻž āĻ…āĻ‚āĻļ āĻāĻ•āϟāĻž āύāĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āϟ āĻ•āĻžāĻœā§‡āϰ āϜāĻ¨ā§āϝ āĻĻāĻžāϝāĻŧā§€ āĻĨāĻžāĻ•āĻŦ⧇, āφāϰ āĻĻāϰāĻ•āĻžāϰ āĻĒāĻĄāĻŧāϞ⧇ āĻ…āĻ¨ā§āϝ āϜāĻžāϝāĻŧāĻ—āĻžāϤ⧇āĻ“ āϰāĻŋāχāωāϜ āĻ•āϰāĻž āϝāĻžāĻŦ⧇āĨ¤

āφāĻĒāύāĻžāϰ āĻ¸ā§āϕ⧇āϚ UI-āϕ⧇ āĻāĻ­āĻžāĻŦ⧇ āϭ⧇āϙ⧇ āĻĢ⧇āϞ⧁āύ:

break down your sketch UI

āϤāĻžāĻĒāϏ āĻ­āĻžāχ āĻĻ⧇āĻ–āĻŋāϝāĻŧ⧇āϛ⧇āύ āϕ⧀āĻ­āĻžāĻŦ⧇ UI breakdown āĻ•āϰāϤ⧇ āĻšāϝāĻŧ:

UI āĻĻ⧇āϖ⧇ āĻ āĻŋāĻ• āĻ•āϰ⧁āύ āϕ⧋āύ āϕ⧋āύ āĻ…āĻ‚āĻļ āφāϞāĻžāĻĻāĻž āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āϟ āĻšāĻŦ⧇āĨ¤ (āϝ⧇āĻŽāύ: Header, Footer, MovieCard, SearchBar, Sidebar)

ā§Ģ. āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āϟ āĻšāĻžāϝāĻŧāĻžāϰāĻžāĻ°ā§āĻ•āĻŋ — āϕ⧇ āĻ•āĻžāϰ āϭ⧇āϤāϰ⧇ āĻĨāĻžāĻ•āĻŦ⧇

Component Hierarchy āĻŽāĻžāύ⧇ āĻšāϞ⧋ — āϕ⧋āύ āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āĻŸā§‡āϰ āϭ⧇āϤāϰ⧇ āϕ⧋āύāϟāĻž āĻĨāĻžāĻ•āĻŦ⧇, āĻ…āĻ°ā§āĻĨāĻžā§Ž component tree-āϰ parent-child āϏāĻŽā§āĻĒāĻ°ā§āĻ• āĻ āĻŋāĻ• āĻ•āϰāĻžāĨ¤ āĻāϟāĻžāχ āĻĒāϰ⧇ āĻ āĻŋāĻ• āĻ•āϰ⧇ āĻĻ⧇āĻŦ⧇ data āϕ⧋āύ āĻĻāĻŋāĻ• āĻĨ⧇āϕ⧇ āϕ⧋āύ āĻĻāĻŋāϕ⧇ āϝāĻžāĻŦ⧇ — React-āĻ āĻĄā§‡āϟāĻž āϏāĻŦāϏāĻŽāϝāĻŧ unidirectional: āωāĻĒāϰ āĻĨ⧇āϕ⧇ āύāĻŋāĻšā§‡ props, āύāĻŋāϚ āĻĨ⧇āϕ⧇ āωāĻĒāϰ⧇ callback functionāĨ¤

component hierarchy

āϕ⧋āύ āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āĻŸā§‡āϰ āϭ⧇āϤāϰ⧇ āϕ⧋āύāϟāĻž āĻĨāĻžāĻ•āĻŦ⧇, āϏ⧇āϟāĻž āĻāĻ•āϟāĻž Tree āφāĻ•āĻžāϰ⧇ āϏāĻžāϜāĻŋāϝāĻŧ⧇ āĻĢ⧇āϞ⧁āύāĨ¤ (App → Header, Main → Sidebar, MovieList → MovieCard)

āϤāĻžāĻĒāϏ āĻ­āĻžāχ āĻĻ⧇āĻ–āĻŋāϝāĻŧ⧇āϛ⧇āύ āϕ⧀āĻ­āĻžāĻŦ⧇ Component Hierarchy āĻŦāĻžāύāĻžāϤ⧇ āĻšāϝāĻŧ:

ā§Ŧ. Data Flow / State Planning

āĻĒā§āϰāϤāĻŋāϟāĻž React āĻĒā§āϰāĻœā§‡āĻ•ā§āĻŸā§‡ State-āϕ⧇ āϤāĻŋāύ āĻ­āĻžāϗ⧇ āĻ­āĻžāĻ— āĻ•āϰ⧇ āĻ­āĻžāĻŦāĻž āωāϚāĻŋāϤ:

  • Local UI State — āĻļ⧁āϧ⧁ āĻāĻ•āϟāĻž āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āĻŸā§‡āϰ āϭ⧇āϤāϰ⧇ āĻĻāϰāĻ•āĻžāϰ (āϝ⧇āĻŽāύ: dropdown āĻ–ā§‹āϞāĻž āφāϛ⧇ āĻ•āĻŋāύāĻž)āĨ¤ useState āĻĻāĻŋāϝāĻŧ⧇ āϏāĻžāĻŽāϞāĻžāύ⧋ āϝāĻžāϝāĻŧāĨ¤
  • Shared/Global State — āĻāĻ•āϏāĻžāĻĨ⧇ āĻāĻ•āĻžāϧāĻŋāĻ•, āĻĻā§‚āϰ⧇ āĻĻā§‚āϰ⧇ āĻĨāĻžāĻ•āĻž āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āĻŸā§‡āϰ āĻĻāϰāĻ•āĻžāϰ (Cart Items, Active Theme)āĨ¤ āĻāĻ–āĻžāύ⧇ āφāĻŽāϰāĻž Context + Reducer āĻĒā§āϝāĻžāϟāĻžāĻ°ā§āύ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāĻŦ, āϝāĻžāϤ⧇ prop drilling āĻāĻĄāĻŧāĻžāύ⧋ āϝāĻžāϝāĻŧāĨ¤
  • Derived State — āĻ…āĻ¨ā§āϝ state āĻĨ⧇āϕ⧇ āĻšāĻŋāϏāĻžāĻŦ āĻ•āϰ⧇ āĻŦ⧇āϰ āĻ•āϰāĻž āϝāĻžāϝāĻŧ āĻāĻŽāύ āĻ­ā§āϝāĻžāϞ⧁, āϝ⧇āĻŽāύ āĻ•āĻžāĻ°ā§āĻŸā§‡āϰ āĻŽā§‹āϟ āĻĻāĻžāĻŽāĨ¤ āĻāϗ⧁āϞ⧋āϕ⧇ āφāϞāĻžāĻĻāĻž state āĻšāĻŋāϏ⧇āĻŦ⧇ āύāĻž āϰ⧇āϖ⧇ render-āĻāϰ āϏāĻŽāϝāĻŧ calculate āĻ•āϰāĻžāχ āĻ­āĻžāϞ⧋ āĻ…āĻ­ā§āϝāĻžāϏāĨ¤

āϕ⧋āύ Data āϕ⧋āύ āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āĻŸā§‡ āĻĻāϰāĻ•āĻžāϰ, āφāϰ MovieData āϕ⧀āĻ­āĻžāĻŦ⧇ Cart-āĻ āĻĒ⧌āρāĻ›āĻžāĻŦ⧇ — āϤāĻžāϰ āĻāĻ•āϟāĻž āϏāĻŽāĻ¸ā§āϝāĻž-āϚāĻŋāĻ¤ā§āϰ:

data passing

āφāĻŽāĻžāĻĻ⧇āϰ āĻ…ā§āϝāĻžāĻĒ⧇: Movies List āφāϰ Selected Movie Details āĻĨāĻžāĻ•āĻŦ⧇ component-local state āĻšāĻŋāϏ⧇āĻŦ⧇āĨ¤ āφāϰ Cart Items āĻ“ Theme āĻĨāĻžāĻ•āĻŦ⧇ global Context-āĻ — āĻ•āĻžāϰāĻŖ Navbar (āĻ•āĻžāĻ°ā§āϟ āφāχāĻ•āύ⧇āϰ āϜāĻ¨ā§āϝ), MovieCard (Add to Cart āĻŦāĻžāϟāύ⧇āϰ āϜāĻ¨ā§āϝ) āφāϰ CartPage — āϤāĻŋāύāϜāύ⧇āϰāχ āĻāĻ•āχ cart data āĻĻāϰāĻ•āĻžāϰ, āĻ…āĻĨāϚ component tree-āϤ⧇ āĻāϰāĻž āĻāϕ⧇ āĻ…āĻĒāϰ āĻĨ⧇āϕ⧇ āĻ…āύ⧇āĻ• āĻĻā§‚āϰ⧇āĨ¤

ā§­. Routes Planning (React Router)

āϕ⧋āύ āĻĒ⧇āĻœā§‡ āϕ⧀ āĻĨāĻžāĻ•āĻŦ⧇, āϤāĻžāϰ āĻāĻ•āϟāĻž āĻŽā§āϝāĻžāĻĒ āĻĨāĻžāĻ•āĻž āĻĻāϰāĻ•āĻžāϰ — Modal-based UI āĻšāϞ⧇āĻ“āĨ¤ āĻ•āĻžāϰāĻŖ deep-linking (āϏāϰāĻžāϏāϰāĻŋ āĻāĻ•āϟāĻž URL āĻļ⧇āϝāĻŧāĻžāϰ āĻ•āϰ⧇ āύāĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āϟ āĻŽā§āĻ­āĻŋāϰ āĻĄāĻŋāĻŸā§‡āχāϞāϏ āĻŦāĻž āĻ•āĻžāĻ°ā§āϟ āϖ⧁āϞ⧇ āϝāĻžāĻ“āϝāĻŧāĻž) āĻāĻ•āϟāĻž āϏāϞāĻŋāĻĄ UX āĻĒā§āĻ°ā§āϝāĻžāĻ•āϟāĻŋāϏāĨ¤

(Route map: /, /movies/:id — :id āĻĨāĻžāĻ•āϞ⧇ Movie Details Modal URL āĻĨ⧇āϕ⧇āχ āϖ⧁āϞ⧇ āϝāĻžāĻŦ⧇, /cart)

āĻāχ āϰāĻžāωāϟāĻŋāĻ‚ āφāĻŽāϰāĻž āĻĒāϰ⧇ React Router v8 āĻĻāĻŋāϝāĻŧ⧇ āĻŦāϏāĻžāĻŦā§‹ (āĻāĻ–āύ āĻĒā§āϝāĻžāϕ⧇āĻœā§‡āϰ āύāĻžāĻŽ āĻļ⧁āϧ⧁ react-router — āφāϞāĻžāĻĻāĻž āĻ•āϰ⧇ react-router-dom āχāĻ¨ā§āϏāϟāϞ āĻ•āϰāĻžāϰ āĻĻāϰāĻ•āĻžāϰ āύ⧇āχ)āĨ¤

ā§Ž. āĻĢā§‹āĻ˛ā§āĻĄāĻžāϰ āĻ¸ā§āĻŸā§āϰāĻžāĻ•āϚāĻžāϰ āĻĒā§āĻ˛ā§āϝāĻžāύ āĻ•āϰ⧁āύ

āĻĒā§āϰāĻœā§‡āĻ•ā§āĻŸā§‡āϰ āĻĢā§‹āĻ˛ā§āĻĄāĻžāϰ āϕ⧀āĻ­āĻžāĻŦ⧇ āϏāĻžāϜāĻžāĻŦ⧇āύ, āϏ⧇āϟāĻž āφāϗ⧇āχ āĻ āĻŋāĻ• āĻ•āϰ⧇ āύāĻŋāύāĨ¤ (components/, pages/, context/, data/, hooks/ āχāĻ¤ā§āϝāĻžāĻĻāĻŋ) — āĻĒ⧁āϰ⧋ āĻĢā§‹āĻ˛ā§āĻĄāĻžāϰ āĻ¸ā§āĻŸā§āϰāĻžāĻ•āϚāĻžāϰ āφāĻŽāϰāĻž Step 3-āĻ āĻĄāĻŋāĻŸā§‡āχāϞ⧇ āĻĻ⧇āĻ–āĻŦāĨ¤


⚡ āĻŦā§‹āύāĻžāϏ āϟāĻŋāĻĒāϏ

  • Version Control: Git āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧁āύāĨ¤ āĻŦāĻĄāĻŧ āϕ⧋āύ⧋ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ⧇āϰ āφāϗ⧇ commit āĻ•āϰ⧁āύ, āφāϰ āϏāĻŽā§āĻ­āĻŦ āĻšāϞ⧇ Conventional Commits āĻĢāϰāĻŽā§āϝāĻžāϟ (feat:, fix:, refactor:) āĻŽā§‡āύ⧇ āϚāϞ⧁āύ — āĻĒāϰ⧇ commit history āĻĒāĻĄāĻŧāϤ⧇ āϏ⧁āĻŦāĻŋāϧāĻž āĻšāĻŦ⧇āĨ¤
  • Documentation: āϕ⧋āĻĄā§‡āϰ āĻĒāĻžāĻļāĻžāĻĒāĻžāĻļāĻŋ āĻĄāϕ⧁āĻŽā§‡āĻ¨ā§āĻŸā§‡āĻļāύāĻ“ āϰāĻžāϖ⧁āύāĨ¤ (README.md, āϕ⧋āĻĄā§‡ JSDoc āĻ•āĻŽā§‡āĻ¨ā§āϟ)

āĻŦā§āϝāĻŦāĻšā§ƒāϤ āĻŸā§‡āĻ•āύ⧋āϞāϜāĻŋ āĻ“ āφāĻ°ā§āĻ•āĻŋāĻŸā§‡āĻ•āϚāĻžāϰ đŸ—ī¸

āĻāχ Movie Portal āĻŦāĻžāύāĻžāϤ⧇ āĻ—āĻŋāϝāĻŧ⧇ āφāĻŽāϰāĻž āφāϧ⧁āύāĻŋāĻ• React Development-āĻāϰ āĻ•āϝāĻŧ⧇āĻ•āϟāĻž āϗ⧁āϰ⧁āĻ¤ā§āĻŦāĻĒā§‚āĻ°ā§āĻŖ āϧāĻžāϰāĻŖāĻž āĻ•āĻžāĻœā§‡ āϞāĻžāĻ—āĻžāĻŦā§‹āĨ¤

ā§§. Component-Based Architecture

React-āĻāϰ āϏāĻŦāĻšā§‡āϝāĻŧ⧇ āĻļāĻ•ā§āϤāĻŋāĻļāĻžāϞ⧀ āφāχāĻĄāĻŋāϝāĻŧāĻžāϗ⧁āϞ⧋āϰ āĻāĻ•āϟāĻž āĻšāϞ⧋ Component-Based Architecture — āĻĒ⧁āϰ⧋ āĻ…ā§āϝāĻžāĻĒāϕ⧇ āϛ⧋āϟ āϛ⧋āϟ, āĻĒ⧁āύāσāĻŦā§āϝāĻŦāĻšāĻžāϰāϝ⧋āĻ—ā§āϝ āφāϰ āĻ¸ā§āĻŦāĻžāϧ⧀āύ UI āĻ…āĻ‚āĻļ⧇ āĻ­āĻžāĻ— āĻ•āϰ⧇ āĻĢ⧇āϞāĻžāĨ¤

āφāĻŽāĻžāĻĻ⧇āϰ Movie Portal-āĻ āϝ⧇āĻŽāύ āφāϞāĻžāĻĻāĻž āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āϟ āĻĨāĻžāĻ•āĻŦ⧇:

  • Navbar → āύ⧇āĻ­āĻŋāϗ⧇āĻļāύ āφāϰ āĻ•āĻžāĻ°ā§āϟ āφāχāĻ•āύ
  • MovieCard → āĻāĻ•āϟāĻž āϏāĻŋāύ⧇āĻŽāĻžāϰ āϤāĻĨā§āϝ āĻĻ⧇āĻ–āĻžāύ⧋āϰ āϜāĻ¨ā§āϝ
  • MovieGrid → āĻāĻ•āϏāĻžāĻĨ⧇ āĻ…āύ⧇āĻ• āϏāĻŋāύ⧇āĻŽāĻž āĻĻ⧇āĻ–āĻžāύ⧋āϰ āϜāĻ¨ā§āϝ
  • MovieDetailsModal → āĻāĻ•āϟāĻž āϏāĻŋāύ⧇āĻŽāĻžāϰ āĻŦāĻŋāĻ¸ā§āϤāĻžāϰāĻŋāϤ āϤāĻĨā§āϝ
  • SearchBar → āϏāĻŋāύ⧇āĻŽāĻž āĻ–ā§‹āρāϜāĻžāϰ āϜāĻ¨ā§āϝ
  • Cart → āĻ•āĻžāĻ°ā§āĻŸā§‡ āĻĨāĻžāĻ•āĻž āĻŽā§āĻ­āĻŋāϗ⧁āϞ⧋ āĻĻ⧇āĻ–āĻžāύ⧋āϰ āϜāĻ¨ā§āϝ

āĻĢāϞāĻžāĻĢāϞ:

✅ Code Maintain āĻ•āϰāĻž āϏāĻšāϜ āĻšāϝāĻŧ ✅ Component Reuse āĻ•āϰāĻž āϝāĻžāϝāĻŧ ✅ Project Structure āĻĒāϰāĻŋāĻˇā§āĻ•āĻžāϰ āĻĨāĻžāϕ⧇ ✅ Development āĻĻā§āϰ⧁āϤ āĻšāϝāĻŧ

⧍. Component Mind Map & UI Planning

āĻŦāĻĄāĻŧ React Application-āĻ āĻšāĻžāϤ āĻĻ⧇āĻ“āϝāĻŧāĻžāϰ āφāϗ⧇ Component Structure āĻĒā§āĻ˛ā§āϝāĻžāύ āĻ•āϰāĻžāϟāĻž āĻŽāĻžāĻ¸ā§āϟāĨ¤ Component Mind Map āĻĻāĻŋāϝāĻŧ⧇ āφāĻŽāϰāĻž āĻ āĻŋāĻ• āĻ•āϰāĻŋ — āϕ⧋āύ Component āϞāĻžāĻ—āĻŦ⧇, āĻ•āĻžāϰ āϭ⧇āϤāϰ⧇ āϕ⧇ āĻĨāĻžāĻ•āĻŦ⧇, āφāϰ āĻ•āĻžāϰ āĻĻāĻžāϝāĻŧāĻŋāĻ¤ā§āĻŦ āϕ⧀āĨ¤

MoviePortalApp
│
├── Navbar (Cart Icon, Theme Toggle)
│
├── HomePage
│   │
│   ├── SearchBar
│   │
│   └── MovieGrid
│       │
│       └── MovieCard
│
├── MovieDetailsModal
│   │
│   ├── MovieInfo
│   │
│   └── AddToCartButton
│
└── CartPage
    │
    └── CartItem

āĻāχ āĻŽā§āϝāĻžāĻĒāϟāĻžāχ āφāĻŽāĻžāĻĻ⧇āϰ UI āφāϰ Data Flow āφāϗ⧇ āĻĨ⧇āϕ⧇ āĻĒā§āĻ˛ā§āϝāĻžāύ āĻ•āϰāϤ⧇ āϏāĻžāĻšāĻžāĻ¯ā§āϝ āĻ•āϰ⧇āĨ¤

ā§Š. Context API — Prop Drilling-āĻāϰ āϝāĻ¨ā§āĻ¤ā§āϰāĻŖāĻž āĻĨ⧇āϕ⧇ āĻŽā§āĻ•ā§āϤāĻŋ

Context API āĻšāϞ⧋ React-āĻāϰ āĻŦāĻŋāĻ˛ā§āϟ-āχāύ State Management āϏāϞāĻŋāωāĻļāύāĨ¤ āϝāĻ–āύ āĻ…āύ⧇āĻ•āϗ⧁āϞ⧋ Component-āĻāϰ āĻāĻ•āχ Data āĻĻāϰāĻ•āĻžāϰ āĻšāϝāĻŧ, āϤāĻ–āύ āĻāϟāĻžāχ āĻŦāĻžāρāϚāĻžāϝāĻŧāĨ¤

āϏāĻžāϧāĻžāϰāĻŖāϤ Parent āĻĨ⧇āϕ⧇ Child-āĻ Data āĻĒāĻžāĻ āĻžāϤ⧇ āϗ⧇āϞ⧇ āĻŦāĻžāϰāĻŦāĻžāϰ Props āĻĒāĻžāϏ āĻ•āϰāϤ⧇ āĻšāϝāĻŧ — āĻāϕ⧇ āĻŦāϞ⧇ Prop Drilling, āφāϰ āĻāϟāĻž āϝāϤ āĻ—āĻ­ā§€āϰ⧇ āϝāĻžāϝāĻŧ, āϕ⧋āĻĄ āϤāϤ āĻāϞ⧋āĻŽā§‡āϞ⧋ āĻšāϝāĻŧ⧇ āĻ“āϠ⧇āĨ¤ Context API āĻāχ āϏāĻŽāĻ¸ā§āϝāĻžāϰ āϏāĻŽāĻžāϧāĻžāύāĨ¤

āφāĻŽāĻžāĻĻ⧇āϰ Movie Portal-āĻ Context API āĻĻāĻŋāϝāĻŧ⧇ āϝāĻž āϝāĻž āĻ—ā§āϞ⧋āĻŦāĻžāϞāĻŋ āϰāĻžāĻ–āĻŦ:

  • Cart Items āĻ“ Cart Actions
  • Theme Settings (Light/Dark)
  • Selected Movie (Modal-āĻāϰ āϜāĻ¨ā§āϝ)
  • Favorite Movies
  • Authentication Status
Context Provider
      │
      â–ŧ
Multiple Components
      │
      â–ŧ
Access Shared Data via useContext()

āĻĢāϞ⧇ āϝ⧇āϕ⧋āύ⧋ Component āĻĒā§āϰāĻĒ-āĻšā§‡āχāύ āύāĻž āϭ⧇āϙ⧇āχ āϏāϰāĻžāϏāϰāĻŋ āĻĻāϰāĻ•āĻžāϰāĻŋ Data āĻ…ā§āϝāĻžāĻ•ā§āϏ⧇āϏ āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇āĨ¤

ā§Ē. Reducer Pattern (useReducer) — āϜāϟāĻŋāϞ State-āϕ⧇ āĻļ⧃āĻ™ā§āĻ–āϞāĻžāϝāĻŧ āφāύāĻž

Reducer Pattern-āĻ Complex State Logic āĻāĻ•āϟāĻž āφāϞāĻžāĻĻāĻž pure function-āĻāϰ āĻšāĻžāϤ⧇ āϤ⧁āϞ⧇ āĻĻ⧇āĻ“āϝāĻŧāĻž āĻšāϝāĻŧāĨ¤ React-āĻāϰ useReducer Hook āĻĻāĻŋāϝāĻŧ⧇ āĻāϟāĻž implement āĻ•āϰāĻž āĻšāϝāĻŧ, āφāϰ āĻāϰ āĻŽā§‚āϞ āφāχāĻĄāĻŋāϝāĻŧāĻž Redux āĻĨ⧇āϕ⧇āχ āϧāĻžāϰ āĻ•āϰāĻž — State + Action + Reducer FunctionāĨ¤

Cart-āĻāϰ āϜāĻ¨ā§āϝ āφāĻŽāĻžāĻĻ⧇āϰ State shape āĻ“ Action:

const initialCartState = {
  items: [], // [{ id, title, poster, price, qty }]
};

Action:

{
  type: "ADD_TO_CART",
  payload: movie,
}

Reducer:

function cartReducer(state, action) {
  switch (action.type) {
    case "ADD_TO_CART": {
      const alreadyExists = state.items.some(
        (item) => item.id === action.payload.id,
      );
      if (alreadyExists) {
        return state; // duplicate āĻšāϞ⧇ state āĻ…āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāĻŋāϤ āĻĨāĻžāĻ•āĻŦ⧇, UI warning āĻĻ⧇āĻ–āĻžāĻŦ⧇
      }
      return {
        ...state,
        items: [...state.items, { ...action.payload, qty: 1 }],
      };
    }

    case "REMOVE_FROM_CART":
      return {
        ...state,
        items: state.items.filter((item) => item.id !== action.payload.id),
      };

    default:
      return state;
  }
}

Reducer āĻŦā§āϝāĻŦāĻšāĻžāϰ⧇āϰ āϏ⧁āĻŦāĻŋāϧāĻž:

✅ Complex State Logic āĻŽā§āϝāĻžāύ⧇āϜ āĻ•āϰāĻž āϏāĻšāϜ ✅ State Update Predictable āĻšāϝāĻŧ (pure function — same input, same output āϏāĻŦāϏāĻŽāϝāĻŧ) ✅ Code Scalable āĻšāϝāĻŧ ✅ Large Application Maintain āĻ•āϰāĻž āϏāĻšāϜ āĻšāϝāĻŧ

āĻāχ āĻĒā§āϰāĻœā§‡āĻ•ā§āĻŸā§‡ Component Architecture + Context API + Reducer Pattern — āĻāχ āϤāĻŋāύ⧇āϰ āĻŽāĻŋāĻļ⧇āϞ⧇āχ āφāĻŽāϰāĻž āĻŦāĻžāύāĻžāĻŦā§‹ āĻāĻ•āϟāĻž Scalable, Maintainable Movie PortalāĨ¤ āĻāĻ–āύ āϚāϞ⧁āύ, āĻāϟāĻžāϕ⧇ āϏāĻ¤ā§āϝāĻŋ āϏāĻ¤ā§āϝāĻŋ āϕ⧋āĻĄā§‡ āϰ⧂āĻĒ āĻĻ⧇āĻ“āϝāĻŧāĻž āϝāĻžāĻ• — Step 3āĨ¤


Step 3: āĻ…ā§āϝāĻžāĻ•āĻļāύ! āϕ⧋āĻĄ āϞ⧇āĻ–āĻž āĻļ⧁āϰ⧁ āĻ•āϰāĻŋ đŸŽŦ

HTML Template/UX āĻšāĻžāϤ⧇ āĻĒ⧇āϝāĻŧ⧇ āϗ⧇āϞ⧇, āĻĒā§āϰāĻĨāĻŽ āĻ•āĻžāϜ — āϏ⧇āχ markup-āϕ⧇ JSX-āĻ āϰ⧂āĻĒāĻžāĻ¨ā§āϤāϰ āĻ•āϰ⧇ āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āϟ āĻŦāĻžāύāĻžāύ⧋āĨ¤ āĻāχ āϧāĻžāĻĒ⧇ Step 2-āĻ āϝāĻž āĻĒā§āĻ˛ā§āϝāĻžāύ āĻ•āϰ⧇āĻ›āĻŋāϞāĻžāĻŽ (Component Breakdown, Context + Reducer, Routing), āϏāĻŦ āĻŦāĻžāĻ¸ā§āϤāĻŦ⧇ āϰ⧂āĻĒ āĻĻ⧇āĻŦ — āĻāĻ•āϟāĻž āĻĒā§āϰ⧋āĻĄāĻžāĻ•āĻļāύ-āĻ—ā§āϰ⧇āĻĄ āĻ¸ā§āĻŸā§āϝāĻžāĻ• āĻĻāĻŋāϝāĻŧ⧇: Vite 8 + React 19.2 + Tailwind CSS v4 + React Router v8āĨ¤

āϤāĻžāĻĒāϏ āĻ­āĻžāχ āύāĻŋāĻšā§‡āϰ āĻ­āĻŋāĻĄāĻŋāĻ“āϤ⧇ āĻĻ⧇āĻ–āĻŋāϝāĻŧ⧇āϛ⧇āύ āϕ⧀āĻ­āĻžāĻŦ⧇ HTML āĻĨ⧇āϕ⧇ JSX-āĻ āϰ⧂āĻĒāĻžāĻ¨ā§āϤāϰ āĻ•āϰāϤ⧇ āĻšāϝāĻŧ, āφāϰ āĻĢāĻŸā§‹/āφāχāĻ•āύ āϗ⧁āϞ⧋ JSX-āĻ āϕ⧀āĻ­āĻžāĻŦ⧇ āĻŦāϏāĻžāϤ⧇ āĻšāϝāĻŧ:

āĻāχ āϧāĻžāĻĒ⧇āϰ āĻĒ⧁āϰ⧋ āĻ“āϝāĻŧāĻžāĻ°ā§āĻ•āĻĢā§āϞ⧋

ā§§āĨ¤ Vite āĻĻāĻŋāϝāĻŧ⧇ React āĻĒā§āϰāĻœā§‡āĻ•ā§āϟ āĻŦ⧁āϟāĻ¸ā§āĻŸā§āĻ°ā§āϝāĻžāĻĒ āĻ•āϰāĻž āĻ“ Tailwind CSS v4 āχāĻ¨ā§āϏāϟāϞ āĻ•āϰāĻžāĨ¤ ⧍āĨ¤ HTML template āĻĨ⧇āϕ⧇ JSX āϰ⧂āĻĒāĻžāĻ¨ā§āϤāϰ, assets/icons āĻŽāĻžāχāĻ—ā§āϰ⧇āĻļāύāĨ¤ ā§ŠāĨ¤ Tailwind CSS v4-āĻāϰ CSS-first āĻ•āύāĻĢāĻŋāĻ—āĻžāϰ⧇āĻļāύ āϏ⧇āϟāφāĻĒ (vite.config.js āĻ“ @theme āĻĄāĻŋāϰ⧇āĻ•ā§āϟāĻŋāĻ­)āĨ¤ ā§ĒāĨ¤ āĻĢā§‹āĻ˛ā§āĻĄāĻžāϰ āφāĻ°ā§āĻ•āĻŋāĻŸā§‡āĻ•āϚāĻžāϰ āĻĄāĻŋāϜāĻžāχāύ āĻ•āϰ⧇ āĻāϕ⧇ āĻāϕ⧇ āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āϟ āĻŦāĻžāύāĻžāύ⧋āĨ¤ ā§ĢāĨ¤ data āĻĢā§‹āĻ˛ā§āĻĄāĻžāϰ āĻŦāĻžāύāĻŋāϝāĻŧ⧇ āĻŽā§āĻ­āĻŋ āĻĄā§‡āϟāĻž āĻšāĻžāĻ°ā§āĻĄāϕ⧋āĻĄ āϰāĻžāĻ–āĻž (āĻĒāϰ⧇ API āĻĻāĻŋāϝāĻŧ⧇ āϰāĻŋāĻĒā§āϞ⧇āϏ āĻ•āϰāĻžāϰ āϜāĻ¨ā§āϝ āĻāĻ•āχ shape āĻŽā§‡āύ⧇)āĨ¤ ā§ŦāĨ¤ CartContext āĻ“ useReducer āĻĻāĻŋāϝāĻŧ⧇ Cart āϏāĻŋāĻ¸ā§āĻŸā§‡āĻŽ implement āĻ•āϰāĻžāĨ¤ ā§­āĨ¤ MovieDetailsModal āĻŦāĻžāύāĻžāύ⧋ āĻāĻŦāĻ‚ (āϐāĻšā§āĻ›āĻŋāĻ•āĻ­āĻžāĻŦ⧇) React Router āĻĻāĻŋāϝāĻŧ⧇ URL-driven modal āĻŦāĻžāύāĻžāύ⧋āĨ¤ ā§ŽāĨ¤ ThemeContext āĻĻāĻŋāϝāĻŧ⧇ Light/Dark āĻĨāĻŋāĻŽ āϏ⧁āχāϚāĻŋāĻ‚ āĻŦāĻžāύāĻžāύ⧋āĨ¤ ⧝āĨ¤ ESLint/Prettier āĻĻāĻŋāϝāĻŧ⧇ āϕ⧋āĻĄ āϕ⧋āϝāĻŧāĻžāϞāĻŋāϟāĻŋ āύāĻŋāĻļā§āϚāĻŋāϤ āĻ•āϰāĻžāĨ¤

āϚāϞ⧁āύ, āĻāϕ⧇ āĻāϕ⧇ āĻĸ⧁āϕ⧇ āĻĒāĻĄāĻŧāĻŋ āĻĒā§āϰāϤāĻŋāϟāĻž āϧāĻžāĻĒ⧇āĨ¤


āϧāĻžāĻĒ ā§§: Vite + React āĻĒā§āϰāĻœā§‡āĻ•ā§āϟ āĻŦ⧁āϟāĻ¸ā§āĻŸā§āĻ°ā§āϝāĻžāĻĒ

Create React App (deprecated) āĻŦāĻžāĻĻ āĻĻāĻŋāϝāĻŧ⧇ āφāĻŽāϰāĻž Vite āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāĻŦ — āĻ•āĻžāϰāĻŖ Vite āĻĄā§‡āϭ⧇āϞāĻĒāĻŽā§‡āĻ¨ā§āĻŸā§‡ native ES modules āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧇ instant server start āφāϰ Hot Module Replacement (HMR) āĻĻ⧇āϝāĻŧāĨ¤ āĻĒā§āϰ⧋āĻĄāĻžāĻ•āĻļāύ āĻŦāĻŋāĻ˛ā§āĻĄā§‡ āĻāĻ–āύ Rolldown (Rust-based unified bundler, Vite 8 āĻĨ⧇āϕ⧇ āĻĄāĻŋāĻĢāĻ˛ā§āϟ) āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻšāϝāĻŧ, āϝāĻž āφāϗ⧇āϰ esbuild + Rollup dual-bundler āφāĻ°ā§āĻ•āĻŋāĻŸā§‡āĻ•āϚāĻžāϰāϕ⧇ āϰāĻŋāĻĒā§āϞ⧇āϏ āĻ•āϰ⧇ āĻŦāĻŋāĻ˛ā§āĻĄ āĻ¸ā§āĻĒāĻŋāĻĄ āĻŦāĻšā§āϗ⧁āĻŖ āĻŦāĻžāĻĄāĻŧāĻŋāϝāĻŧ⧇ āĻĻāĻŋāϝāĻŧ⧇āϛ⧇āĨ¤

# Node.js 20.19+ āĻ…āĻĨāĻŦāĻž 22.12+ āĻĒā§āϰāϝāĻŧā§‹āϜāύ
npm create vite@latest movie-portal -- --template react

cd movie-portal
npm install
npm run dev

TypeScript āϚāĻžāχāϞ⧇ --template react-ts āĻĻāĻŋāύāĨ¤ āĻŦāĻĄāĻŧ āĻĒā§āϰāĻœā§‡āĻ•ā§āĻŸā§‡ āϟāĻžāχāĻĒ āϏ⧇āĻĢāϟāĻŋ āĻ“ autocomplete-āĻāϰ āϜāĻ¨ā§āϝ TypeScript āϰāĻŋāĻ•āĻŽā§‡āĻ¨ā§āĻĄā§‡āĻĄ, āϤāĻŦ⧇ āĻāχ āϟāĻŋāωāĻŸā§‹āϰāĻŋāϝāĻŧāĻžāϞ⧇ āφāĻŽāϰāĻž plain JavaScript (JSX) āĻĻāĻŋāϝāĻŧ⧇ āĻāĻ—ā§‹āĻŦā§‹ — āϝāĻžāϤ⧇ āĻ•āύāϏ⧇āĻĒā§āϟāϗ⧁āϞ⧋ āĻĒāϰāĻŋāĻˇā§āĻ•āĻžāϰ āĻĨāĻžāϕ⧇, āĻ­āĻžāώāĻžāϰ āϜāϟāĻŋāϞāϤāĻžāϝāĻŧ āĻšāĻžāϰāĻŋāϝāĻŧ⧇ āύāĻž āϝāĻžāϝāĻŧāĨ¤


āϧāĻžāĻĒ ā§¨: Tailwind CSS v4 — āĻ•āύāĻĢāĻŋāĻ—āĻžāϰ⧇āĻļāύ⧇āϰ āύāϤ⧁āύ āύāĻŋāϝāĻŧāĻŽ

Tailwind CSS v4 āĻāĻ•āĻĻāĻŽ āĻ—ā§āϰāĻžāωāĻ¨ā§āĻĄ-āφāĻĒ āϰāĻŋāϰāĻžāχāϟ — āĻāĻ–āύ āĻāϟāĻŋ Lightning CSS (Rust-based parser/transformer)-āĻāϰ āωāĻĒāϰ āĻĻāĻžāρāĻĄāĻŧāĻžāύ⧋āĨ¤ āϏāĻŦāĻšā§‡āϝāĻŧ⧇ āĻŦāĻĄāĻŧ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ: tailwind.config.js āĻĢāĻžāχāϞ āφāϰ āϞāĻžāϗ⧇ āύāĻž! āĻ•āύāĻĢāĻŋāĻ—āĻžāϰ⧇āĻļāύ āĻāĻ–āύ āϏāϰāĻžāϏāϰāĻŋ CSS āĻĢāĻžāχāϞ⧇ @theme āĻĄāĻŋāϰ⧇āĻ•ā§āϟāĻŋāĻ­ āĻĻāĻŋāϝāĻŧ⧇ āĻšāϝāĻŧ (CSS-first configuration), āϝāĻž design token āϗ⧁āϞ⧋āϕ⧇ native CSS custom properties āĻšāĻŋāϏ⧇āĻŦ⧇ āĻāĻ•ā§āϏāĻĒā§‹āϜ āĻ•āϰ⧇ āĻĻ⧇āϝāĻŧāĨ¤

āĻĒā§āϰāĻĨāĻŽā§‡ first-party Vite āĻĒā§āϞāĻžāĻ—āĻŋāύāϏāĻš āχāĻ¨ā§āϏāϟāϞ āĻ•āϰ⧁āύ:

npm install tailwindcss @tailwindcss/vite

vite.config.js-āĻ āĻĒā§āϞāĻžāĻ—āĻŋāύ āϝ⧋āĻ— āĻ•āϰ⧁āύ:

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";

export default defineConfig({
  plugins: [react(), tailwindcss()],
});

āĻāϰāĻĒāϰ src/index.css-āĻ āĻāĻ•āϟāĻž āχāĻŽā§āĻĒā§‹āĻ°ā§āϟ āϞāĻžāχāύ āφāϰ āĻ•āĻžāĻ¸ā§āϟāĻŽ āĻĨāĻŋāĻŽ āĻŸā§‹āϕ⧇āύ āϝ⧋āĻ— āĻ•āϰ⧁āύ:

@import "tailwindcss";

@theme {
  /* āĻ•āĻžāĻ¸ā§āϟāĻŽ āĻ•āĻžāϞāĻžāϰ — āφāĻŽāĻžāĻĻ⧇āϰ āĻĄāĻŋāϜāĻžāχāύ āϏāĻŋāĻ¸ā§āĻŸā§‡āĻŽ āĻŸā§‹āϕ⧇āύ */
  --color-primary: #ff0000;
  --color-secondary: #00ff00;

  /* āĻ•āĻžāĻ¸ā§āϟāĻŽ āĻĢāĻ¨ā§āϟ āĻ“ āĻ¸ā§āĻĒ⧇āϏāĻŋāĻ‚ āĻ¸ā§āϕ⧇āϞ-āĻ“ āĻāĻ–āĻžāύ⧇āχ āϝ⧋āĻ— āĻ•āϰāĻž āϝāĻžāĻŦ⧇ */
  --font-display: "Hind Siliguri", sans-serif;
}

/* Dark mode variant — v4-āϤ⧇ darkMode āφāϰ JS config-āĻ āĻĨāĻžāϕ⧇ āύāĻž */
@custom-variant dark (&:where(.dark, .dark *));

āĻŽāϜāĻžāϰ āĻŦā§āϝāĻžāĻĒāĻžāϰ āĻšāϞ⧋ — --color-primary āĻĄāĻŋāĻĢāĻžāχāύ āĻ•āϰāĻžāϰ āϏāĻžāĻĨ⧇ āϏāĻžāĻĨ⧇āχ Tailwind āύāĻŋāĻœā§‡ āĻĨ⧇āϕ⧇ bg-primary, text-primary, border-primary āχāĻ¤ā§āϝāĻžāĻĻāĻŋ āĻ•ā§āϞāĻžāϏ āĻœā§‡āύāĻžāϰ⧇āϟ āĻ•āϰ⧇ āĻĻ⧇āϝāĻŧāĨ¤ āφāϞāĻžāĻĻāĻž āĻ•āϰ⧇ colors: { primary: ... } āϞāĻŋāϖ⧇ extend āĻ•āϰāĻžāϰ āĻĻāϰāĻ•āĻžāϰāχ āύ⧇āχāĨ¤

Container utility āĻ•āĻžāĻ¸ā§āϟāĻŽāĻžāχāĻœā§‡āĻļāύ: v3-āϤ⧇ container: { center: true, padding: "2rem" } āϝ⧇āĻ­āĻžāĻŦ⧇ JS āĻ…āĻŦāĻœā§‡āĻ•ā§āĻŸā§‡ āϞ⧇āĻ–āĻž āĻšāϤ⧋, v4-āϤ⧇ āϏ⧇āϟāĻž @utility āĻĄāĻŋāϰ⧇āĻ•ā§āϟāĻŋāĻ­ āĻĻāĻŋāϝāĻŧ⧇ override āĻ•āϰāϤ⧇ āĻšāϝāĻŧ:

@utility container {
  margin-inline: auto;
  padding-inline: 2rem;
}

v4 āĻĻā§āϰ⧁āϤ evolve āĻ•āϰāϛ⧇, āϤāĻžāχ āϏāĻ°ā§āĻŦāĻļ⧇āώ āϏāĻŋāύāĻŸā§āϝāĻžāĻ•ā§āϏ⧇āϰ āϜāĻ¨ā§āϝ āĻ…āĻĢāĻŋāϏāĻŋāϝāĻŧāĻžāϞ Tailwind CSS āĻĄāϕ⧁āĻŽā§‡āĻ¨ā§āĻŸā§‡āĻļāύ āĻāĻ•āĻŦāĻžāϰ āĻšā§‡āĻ• āĻ•āϰ⧇ āύ⧇āĻ“āϝāĻŧāĻžāχ āĻŦ⧁āĻĻā§āϧāĻŋāĻŽāĻžāύ⧇āϰ āĻ•āĻžāϜāĨ¤


āϧāĻžāĻĒ ā§Š: HTML Template āĻĨ⧇āϕ⧇ JSX — āĻ…āύ⧁āĻŦāĻžāĻĻ⧇āϰ āύāĻŋāϝāĻŧāĻŽāĻ•āĻžāύ⧁āύ

HTML markup-āϕ⧇ JSX-āĻ āϰ⧂āĻĒāĻžāĻ¨ā§āϤāϰ⧇āϰ āϏāĻŽāϝāĻŧ āĻ•āĻŋāϛ⧁ āϏāĻŋāύāĻŸā§āϝāĻžāĻ•ā§āϏ āύāĻŋāϝāĻŧāĻŽ āĻŽāύ⧇ āϰāĻžāĻ–āϤ⧇ āĻšāϝāĻŧ, āĻ•āĻžāϰāĻŖ JSX āφāϏāϞ⧇ HTML āύāϝāĻŧ — āĻāϟāĻž JavaScript-āĻāϰāχ āϏāĻŋāύāĻŸā§āϝāĻžāĻ•ā§āϟāĻŋāĻ• āϏ⧁āĻ—āĻžāϰ (āĻĒ⧇āĻ›āύ⧇ āĻ—āĻŋāϝāĻŧ⧇ React.createElement() āĻ•āϞ⧇ āĻ•āĻŽā§āĻĒāĻžāχāϞ āĻšāϝāĻŧ):

  • class → className (āĻ•āĻžāϰāĻŖ class JavaScript-āĻāϰ reserved keyword)
  • for → htmlFor (āϞ⧇āĻŦ⧇āϞ āĻāϞāĻŋāĻŽā§‡āĻ¨ā§āĻŸā§‡)
  • inline style āĻ¸ā§āĻŸā§āϰāĻŋāĻ‚ āύāĻž āĻšāϝāĻŧ⧇ JavaScript object āĻšāĻŦ⧇, āĻĒā§āϰāĻĒāĻžāĻ°ā§āϟāĻŋ āύ⧇āĻŽ camelCase: style={{ backgroundColor: "#000", marginTop: "10px" }}
  • āϏāĻŦ attribute camelCase: onclick → onClick, tabindex → tabIndex, readonly → readOnly
  • Self-closing void elements: <img>, <input>, <br> āĻ…āĻŦāĻļā§āϝāχ self-close āĻ•āϰāϤ⧇ āĻšāĻŦ⧇ — <img src="..." />
  • Comment syntax: HTML āĻ•āĻŽā§‡āĻ¨ā§āϟ (<!-- -->)-āĻāϰ āĻŦāĻĻāϞ⧇ {/* comment */}
  • JavaScript expression embedding: āĻ•āĻžāĻ°ā§āϞāĻŋ āĻŦā§āϰ⧇āϏ {} āĻĻāĻŋāϝāĻŧ⧇ dynamic āĻ­ā§āϝāĻžāϞ⧁ āĻŦāϏāĻžāύ⧋ āĻšāϝāĻŧ — <h1>{movie.title}</h1>
  • āĻāĻ•āϟāĻžāχ root element: āĻĒā§āϰāϤāĻŋāϟāĻž āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āϟ āĻāĻ•āϟāĻž single root return āĻ•āϰāĻŦ⧇ — āĻŦāĻžāĻĄāĻŧāϤāĻŋ wrapper <div> āĻāĻĄāĻŧāĻžāϤ⧇ <>...</> (Fragment) āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāĻž āϝāĻžāϝāĻŧ
  • List rendering-āĻ key prop: .map() āĻĻāĻŋāϝāĻŧ⧇ āϞ⧁āĻĒ āĻ•āϰāĻžāϰ āϏāĻŽāϝāĻŧ āĻĒā§āϰāϤāĻŋāϟāĻž child-āĻ āχāωāύāĻŋāĻ• key āĻĻāĻŋāϤ⧇āχ āĻšāĻŦ⧇ — movies.map((m) => <MovieCard key={m.id} movie={m} />)

Assets āĻ“ āφāχāĻ•āύ āĻŽāĻžāχāĻ—ā§āϰ⧇āĻļāύ:

HTML template-āĻāϰ assets/images, assets/fonts, assets/icons āĻĢā§‹āĻ˛ā§āĻĄāĻžāϰāϗ⧁āϞ⧋ src/assets-āĻ āĻ•āĻĒāĻŋ āĻ•āϰ⧁āύāĨ¤ Vite-āĻ āĻĻ⧁āχ āϰāĻ•āĻŽ asset handling āφāϛ⧇:

  1. src/assets-āĻ āϰāĻžāĻ–āĻž āĻĢāĻžāχāϞ import āĻ•āϰ⧇ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāϤ⧇ āĻšāϝāĻŧ — Vite āĻāϗ⧁āϞ⧋āϕ⧇ build-time-āĻ hash āĻ•āϰ⧇, optimize āĻ•āϰ⧇ bundle-āĻ āĻĸ⧁āĻ•āĻŋāϝāĻŧ⧇ āĻĻ⧇āϝāĻŧ:

    import heroBanner from "../assets/images/hero-banner.jpg";
    
    <img src={heroBanner} alt="Hero banner" />;
  2. public/ āĻĢā§‹āĻ˛ā§āĻĄāĻžāϰ⧇āϰ āĻĢāĻžāχāϞ āĻĒā§āϰāϏ⧇āϏ āĻšāϝāĻŧ āύāĻž, āϏāϰāĻžāϏāϰāĻŋ root path āĻĻāĻŋāϝāĻŧ⧇ āϰ⧇āĻĢāĻžāϰ āĻ•āϰāĻž āĻšāϝāĻŧ (favicon, robots.txt āχāĻ¤ā§āϝāĻžāĻĻāĻŋ)āĨ¤

āφāχāĻ•āύ⧇āϰ āĻ•ā§āώ⧇āĻ¤ā§āϰ⧇ raw SVG āĻĢāĻžāχāϞ āĻ•āĻĒāĻŋ āύāĻž āĻ•āϰ⧇ lucide-react-āĻāϰ āĻŽāϤ⧋ tree-shakeable, component-based icon library āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāĻž āĻ…āύ⧇āĻ• āĻŦ⧇āĻļāĻŋ āĻŽā§‡āχāύāĻŸā§‡āχāύ⧇āĻŦāϞ:

npm install lucide-react
import { ShoppingCart, Star, Sun, Moon } from "lucide-react";

<button>
  <ShoppingCart size={20} className="text-primary" />
</button>;

āϧāĻžāĻĒ ā§Ē: āĻĢā§‹āĻ˛ā§āĻĄāĻžāϰ āφāĻ°ā§āĻ•āĻŋāĻŸā§‡āĻ•āϚāĻžāϰ āĻ“ āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āϟ āϤ⧈āϰāĻŋ

āĻ¸ā§āϕ⧇āϞ⧇āĻŦāϞ āĻĒā§āϰāĻœā§‡āĻ•ā§āĻŸā§‡āϰ āϜāĻ¨ā§āϝ āφāĻŽāϰāĻž feature-based āĻĢā§‹āĻ˛ā§āĻĄāĻžāϰ āĻ¸ā§āĻŸā§āϰāĻžāĻ•āϚāĻžāϰ āĻĢāϞ⧋ āĻ•āϰāĻŦ:

src/
├── assets/          # images, fonts, raw svg
├── components/
│   ├── ui/          # Button, Badge, Modal — āĻĒ⧁āύāσāĻŦā§āϝāĻŦāĻšāĻžāϰāϝ⧋āĻ—ā§āϝ āĻĒā§āϰāĻŋāĻŽāĻŋāϟāĻŋāĻ­
│   ├── layout/      # Navbar, Footer
│   └── movies/      # MovieCard, MovieGrid, MovieDetailsModal
├── context/         # ThemeContext, CartContext
├── data/            # hardcoded mock data
├── hooks/           # useTheme, useCart, custom hooks
├── pages/           # HomePage, CartPage
├── lib/             # utils, helper functions
├── App.jsx
├── main.jsx
└── index.css

āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āϟ āĻŦāĻžāύāĻžāύ⧋āϰ āϏāĻŽāϝāĻŧ āφāĻŽāϰāĻž āĻ•āĻŋāϛ⧁ āύ⧀āϤāĻŋ āĻŽāĻžāĻĨāĻžāϝāĻŧ āϰāĻžāĻ–āĻŦ:

  • Single Responsibility — āĻĒā§āϰāϤāĻŋāϟāĻž āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āϟ āĻāĻ•āϟāĻžāχ āĻ•āĻžāϜ āĻ•āϰāĻŦ⧇ (MovieCard āĻļ⧁āϧ⧁ āĻāĻ•āϟāĻž āĻŽā§āĻ­āĻŋāϰ āĻ•āĻžāĻ°ā§āĻĄ āĻĻ⧇āĻ–āĻžāĻŦ⧇, cart logic āϤāĻžāϰ āĻĻāĻžāϝāĻŧāĻŋāĻ¤ā§āĻŦ āύāĻž)āĨ¤
  • Composition over prop drilling — āĻ—āĻ­ā§€āϰ component tree-āϤ⧇ āĻŦāĻžāϰāĻŦāĻžāϰ props āύāĻž āĻĒāĻžāĻ āĻŋāϝāĻŧ⧇ Context API āĻŦā§āϝāĻŦāĻšāĻžāϰāĨ¤
  • Presentational vs Container split — MovieCard āĻļ⧁āϧ⧁ UI āĻĻ⧇āĻ–āĻžāĻŦ⧇ (presentational), āφāϰ actual cart action āφāϏāĻŦ⧇ useCart() hook āĻĨ⧇āϕ⧇ (container logic āĻšā§āϕ⧇ āĻŦāĻ¨ā§āĻĻāĻŋ)āĨ¤
  • React 19.2-āĻāϰ React Compiler (āĻāĻ–āύ⧋ opt-in, @vitejs/plugin-react v6-āĻāϰ āϏāĻžāĻĨ⧇ babel/Oxc āĻĒā§āϰāĻŋāϏ⧇āϟ āĻĻāĻŋāϝāĻŧ⧇ āĻāύāĻžāĻŦāϞ āĻ•āϰāĻž āϝāĻžāϝāĻŧ) āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āϟāϗ⧁āϞ⧋āϕ⧇ āĻ…āĻŸā§‹āĻŽā§‡āϟāĻŋāĻ•ā§āϝāĻžāϞāĻŋ āĻŽā§‡āĻŽā§‹āϝāĻŧāĻžāχāϜ āĻ•āϰ⧇ āĻĻ⧇āϝāĻŧ — āĻĢāϞ⧇ āĻŦ⧇āĻļāĻŋāϰāĻ­āĻžāĻ— āĻ•ā§āώ⧇āĻ¤ā§āϰ⧇ āĻŽā§āϝāĻžāύ⧁āϝāĻŧāĻžāϞāĻŋ useMemo/useCallback āĻ›āĻĄāĻŧāĻŋāϝāĻŧ⧇ āĻĻ⧇āĻ“āϝāĻŧāĻžāϰ āĻĻāϰāĻ•āĻžāϰ āĻ•āĻŽā§‡ āφāϏ⧇āĨ¤ āϤāĻŦ⧇ āĻāϟāĻž āĻāĻ–āύ⧋ maturing āĻ¸ā§āĻŸā§‡āĻœā§‡, āϤāĻžāχ āĻĒā§āϰ⧋āĻĄāĻžāĻ•āĻļāύ⧇ āĻāύāĻžāĻŦāϞ āĻ•āϰāĻžāϰ āφāϗ⧇ āύāĻŋāĻœā§‡āϰ āϞāĻžāχāĻŦā§āϰ⧇āϰāĻŋāϗ⧁āϞ⧋āϰ āĻ•āĻŽā§āĻĒā§āϝāĻžāϟāĻŋāĻŦāĻŋāϞāĻŋāϟāĻŋ āĻāĻ•āĻŦāĻžāϰ āϝāĻžāϚāĻžāχ āĻ•āϰ⧇ āύāĻŋāύāĨ¤

āĻāϕ⧇ āĻāϕ⧇ āĻāχ āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āϟāϗ⧁āϞ⧋ āĻŦāĻžāύāĻžāĻŦā§‹: Navbar, MovieCard, MovieGrid, MovieDetailsModal, Cart, Footer — āĻāĻŦāĻ‚ āĻĒā§āϰāϤāĻŋāϟāĻž āĻŦāĻžāύāĻžāύ⧋āϰ āĻĒāϰ App.jsx-āĻ āĻœā§‹āĻĄāĻŧāĻž āϞāĻžāĻ—āĻŋāϝāĻŧ⧇ āĻĒ⧇āϜ āĻ…ā§āϝāĻžāϏ⧇āĻŽā§āĻŦāϞ āĻ•āϰāĻŦāĨ¤


āϧāĻžāĻĒ ā§Ģ: Data āĻĢā§‹āĻ˛ā§āĻĄāĻžāϰ — āĻŽā§āĻ­āĻŋ āĻĄā§‡āϟāĻž āĻšāĻžāĻ°ā§āĻĄāϕ⧋āĻĄ āϰāĻžāĻ–āĻž

API āχāĻ¨ā§āϟāĻŋāĻ—ā§āϰ⧇āĻļāύ⧇āϰ āφāϗ⧇ UI develop āĻ“ test āĻ•āϰāĻžāϰ āϜāĻ¨ā§āϝ hardcoded mock data layer āĻŦāĻžāύāĻžāύ⧋ āĻāĻ•āϟāĻž āĻ•āĻŽāύ āφāϰ āĻ¸ā§āĻŽāĻžāĻ°ā§āϟ āĻĒā§āĻ°ā§āϝāĻžāĻ•āϟāĻŋāϏāĨ¤ āĻ­āĻŦāĻŋāĻˇā§āϝāϤ⧇ āĻāχ array-āϕ⧇ āĻāĻ•āχ shape āĻŽā§‡āύ⧇ API response āĻĻāĻŋāϝāĻŧ⧇ āϰāĻŋāĻĒā§āϞ⧇āϏ āĻ•āϰāϞ⧇ āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āϟ āϕ⧋āĻĄā§‡ āĻāĻ• āϞāĻžāχāύāĻ“ āĻŦāĻĻāϞāĻžāϤ⧇ āĻšāĻŦ⧇ āύāĻžāĨ¤

// src/data/movies.js

/**
 * @typedef {Object} Movie
 * @property {number} id
 * @property {string} title
 * @property {string} poster
 * @property {number} rating
 * @property {string[]} genres
 * @property {number} price
 */

/** @type {Movie[]} */
export const movies = [
  {
    id: 1,
    title: "āχāĻ¨ā§āϟāĻžāϰāĻ¸ā§āĻŸā§‡āϞāĻžāϰ",
    poster: "/images/movies/interstellar.jpg",
    rating: 8.7,
    genres: ["Sci-Fi", "Drama"],
    price: 120,
  },
  {
    id: 2,
    title: "āχāύāϏ⧇āĻĒāĻļāύ",
    poster: "/images/movies/inception.jpg",
    rating: 8.8,
    genres: ["Action", "Sci-Fi"],
    price: 150,
  },
];

āĻāĻ–āĻžāύ⧇ JSDoc @typedef āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāĻžāϝāĻŧ plain JavaScript āĻĒā§āϰāĻœā§‡āĻ•ā§āĻŸā§‡āĻ“ VS Code-āĻ IntelliSense āφāϰ type-checking-āĻāϰ āϏ⧁āĻŦāĻŋāϧāĻž āĻĒāĻžāĻ“āϝāĻŧāĻž āϝāĻžāϝāĻŧ — āφāϰ āĻĒāϰāĻŦāĻ°ā§āϤ⧀āϤ⧇ TypeScript-āĻ āĻŽāĻžāχāĻ—ā§āϰ⧇āϟ āĻ•āϰāĻžāĻ“ āϏāĻšāϜ āĻšāϝāĻŧ⧇ āϝāĻžāϝāĻŧāĨ¤

āĻĒā§āϰāĻžāχāϏ āĻĢāϰāĻŽā§āϝāĻžāϟ āĻ•āϰāĻžāϰ āϜāĻ¨ā§āϝ hardcoded ā§ŗ āĻ¸ā§āĻŸā§āϰāĻŋāĻ‚ āĻœā§‹āĻĄāĻŧāĻž āĻĻ⧇āĻ“āϝāĻŧāĻžāϰ āĻŦāĻĻāϞ⧇ Intl.NumberFormat āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰ⧁āύ:

// src/lib/formatPrice.js
export function formatPrice(amount) {
  return new Intl.NumberFormat("bn-BD", {
    style: "currency",
    currency: "BDT",
  }).format(amount);
}

āϧāĻžāĻĒ ā§Ŧ: CartContext āĻ“ useReducer āĻĻāĻŋāϝāĻŧ⧇ Cart āϏāĻŋāĻ¸ā§āĻŸā§‡āĻŽ

Step 2-āĻ āĻĒā§āĻ˛ā§āϝāĻžāύ āĻ•āϰāĻž Reducer Pattern āĻāĻ–āύ āĻŦāĻžāĻ¸ā§āϤāĻŦ⧇ āύāĻžāĻŽāĻžāĻŦā§‹āĨ¤ cartReducer-āϕ⧇ āφāϞāĻžāĻĻāĻž āĻĢāĻžāχāϞ⧇ āϰāĻžāĻ–āĻŦ, āϝāĻžāϤ⧇ logic āφāϰ Context configuration āφāϞāĻžāĻĻāĻž āĻĨāĻžāϕ⧇ (separation of concerns):

// src/context/cartReducer.js
export const initialCartState = { items: [] };

export function cartReducer(state, action) {
  switch (action.type) {
    case "ADD_TO_CART": {
      const exists = state.items.some((item) => item.id === action.payload.id);
      if (exists) return state; // duplicate āĻšāϞ⧇ warning component āϞ⧇āϭ⧇āϞ⧇ āĻĻ⧇āĻ–āĻžāĻŦ
      return { items: [...state.items, action.payload] };
    }

    case "REMOVE_FROM_CART":
      return {
        items: state.items.filter((item) => item.id !== action.payload.id),
      };

    case "CLEAR_CART":
      return { items: [] };

    default:
      return state;
  }
}
// src/context/CartContext.jsx
import { createContext, useContext, useReducer, useMemo } from "react";
import { cartReducer, initialCartState } from "./cartReducer";

const CartContext = createContext(null);

export function CartProvider({ children }) {
  const [state, dispatch] = useReducer(cartReducer, initialCartState);

  // Derived state — āĻŽā§‹āϟ āĻĻāĻžāĻŽ āĻ“ āφāχāĻŸā§‡āĻŽ āϏāĻ‚āĻ–ā§āϝāĻž āφāϞāĻžāĻĻāĻž state āĻšāĻŋāϏ⧇āĻŦ⧇ āύāĻž āϰ⧇āϖ⧇ calculate āĻ•āϰāĻ›āĻŋ
  const totalPrice = useMemo(
    () => state.items.reduce((sum, item) => sum + item.price, 0),
    [state.items],
  );

  const value = {
    items: state.items,
    totalPrice,
    itemCount: state.items.length,
    addToCart: (movie) => dispatch({ type: "ADD_TO_CART", payload: movie }),
    removeFromCart: (id) =>
      dispatch({ type: "REMOVE_FROM_CART", payload: { id } }),
    clearCart: () => dispatch({ type: "CLEAR_CART" }),
    isInCart: (id) => state.items.some((item) => item.id === id),
  };

  return <CartContext.Provider value={value}>{children}</CartContext.Provider>;
}

export function useCart() {
  const context = useContext(CartContext);
  if (!context) throw new Error("useCart must be used within a CartProvider");
  return context;
}

MovieCard-āĻ duplicate-add āĻšāϞ⧇ āĻ“āϝāĻŧāĻžāĻ°ā§āύāĻŋāĻ‚ āĻĻ⧇āĻ–āĻžāύ⧋āϰ āϜāĻ¨ā§āϝ isInCart āĻšā§‡āĻ• āĻ•āϰ⧇ āĻ•āĻ¨ā§āĻĄāĻŋāĻļāύāĻžāϞāĻŋ āĻŽā§‡āϏ⧇āϜ āĻĻ⧇āĻ–āĻžāĻŦā§‹:

// src/components/movies/MovieCard.jsx
import { ShoppingCart } from "lucide-react";
import { useCart } from "../../context/CartContext";
import { formatPrice } from "../../lib/formatPrice";

export function MovieCard({ movie }) {
  const { addToCart, isInCart } = useCart();
  const alreadyAdded = isInCart(movie.id);

  function handleAddToCart() {
    if (alreadyAdded) {
      alert(`"${movie.title}" āφāϗ⧇ āĻĨ⧇āϕ⧇āχ āĻ•āĻžāĻ°ā§āĻŸā§‡ āϝ⧁āĻ•ā§āϤ āφāϛ⧇āĨ¤`); // āĻĒā§āϰ⧋āĻĄāĻžāĻ•āĻļāύ⧇ toast notification āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāĻž āĻ­āĻžāϞ⧋
      return;
    }
    addToCart(movie);
  }

  return (
    <div className="rounded-lg border border-secondary/20 p-4">
      <img src={movie.poster} alt={movie.title} className="rounded-md" />
      <h3 className="mt-2 font-display font-semibold">{movie.title}</h3>
      <p className="text-sm text-secondary">⭐ {movie.rating}</p>
      <button
        onClick={handleAddToCart}
        className="mt-3 flex items-center gap-2 rounded-md bg-primary px-3 py-2 text-white"
      >
        <ShoppingCart size={16} />
        {formatPrice(movie.price)}
      </button>
    </div>
  );
}

āϧāĻžāĻĒ ā§­: MovieDetailsModal — āĻ•ā§āϞ⧋āϜ āφāĻĒ āĻļāϟ

āĻŽā§āĻ­āĻŋ āĻ•āĻžāĻ°ā§āĻĄā§‡ āĻ•ā§āϞāĻŋāĻ• āĻ•āϰāϞ⧇ āϝ⧇ modal āϖ⧁āϞāĻŦ⧇, āϏ⧇āϟāĻžāϕ⧇ DOM hierarchy-āϤ⧇ MovieCard-āĻāϰ āϭ⧇āϤāϰ⧇ āύ⧇āĻ¸ā§āĻŸā§‡āĻĄ āύāĻž āϰ⧇āϖ⧇ createPortal āĻĻāĻŋāϝāĻŧ⧇ āϏāϰāĻžāϏāϰāĻŋ document.body-āĻāϰ āϚāĻžāχāĻ˛ā§āĻĄ āĻšāĻŋāϏ⧇āĻŦ⧇ āϰ⧇āĻ¨ā§āĻĄāĻžāϰ āĻ•āϰāĻžāχ āĻŦ⧁āĻĻā§āϧāĻŋāĻŽāĻžāύ⧇āϰ āĻ•āĻžāϜ — āĻāϤ⧇ overflow: hidden āĻŦāĻž z-index stacking context-āϜāύāĻŋāϤ āĻšā§āϝāĻžāĻĒāĻž āĻāĻĄāĻŧāĻžāύ⧋ āϝāĻžāϝāĻŧ:

// src/components/movies/MovieDetailsModal.jsx
import { createPortal } from "react-dom";
import { useEffect } from "react";
import { X } from "lucide-react";

export function MovieDetailsModal({ movie, onClose }) {
  // Escape āϕ⧀ āĻĻāĻŋāϝāĻŧ⧇ modal āĻŦāĻ¨ā§āϧ āĻ•āϰāĻžāϰ accessibility support
  useEffect(() => {
    function handleKeyDown(e) {
      if (e.key === "Escape") onClose();
    }
    window.addEventListener("keydown", handleKeyDown);
    return () => window.removeEventListener("keydown", handleKeyDown);
  }, [onClose]);

  if (!movie) return null;

  return createPortal(
    <div
      className="fixed inset-0 z-50 flex items-center justify-center bg-black/60"
      onClick={onClose}
    >
      <div
        className="relative max-w-lg rounded-lg bg-white p-6 dark:bg-zinc-900"
        onClick={(e) => e.stopPropagation()}
      >
        <button onClick={onClose} className="absolute right-4 top-4">
          <X size={20} />
        </button>
        <img src={movie.poster} alt={movie.title} className="rounded-md" />
        <h2 className="mt-4 text-xl font-bold">{movie.title}</h2>
        <p className="mt-2 text-sm">āϜāύāϰāĻž: {movie.genres.join(", ")}</p>
      </div>
    </div>,
    document.body,
  );
}

selected movie-āĻāϰ state āϰāĻžāĻ–āĻŦ HomePage-āĻ — āϞ⧋āĻ•āĻžāϞ state āĻšāĻŋāϏ⧇āĻŦ⧇, āĻ•āĻžāϰāĻŖ āĻāϟāĻž āĻļ⧁āϧ⧁ āĻāχ āĻĒ⧇āĻœā§‡āϰ modal-āĻāϰ āϜāĻ¨ā§āϝāχ āĻĻāϰāĻ•āĻžāϰ, āĻ—ā§āϞ⧋āĻŦāĻžāϞ āĻ•āϰāĻžāϰ āĻĻāϰāĻ•āĻžāϰ āύ⧇āχ:

// src/pages/HomePage.jsx
import { useState } from "react";
import { movies } from "../data/movies";
import { MovieCard } from "../components/movies/MovieCard";
import { MovieDetailsModal } from "../components/movies/MovieDetailsModal";

export function HomePage() {
  const [selectedMovie, setSelectedMovie] = useState(null);

  return (
    <div className="container grid grid-cols-2 gap-4 md:grid-cols-4">
      {movies.map((movie) => (
        <div key={movie.id} onClick={() => setSelectedMovie(movie)}>
          <MovieCard movie={movie} />
        </div>
      ))}
      <MovieDetailsModal
        movie={selectedMovie}
        onClose={() => setSelectedMovie(null)}
      />
    </div>
  );
}

āĻŦā§‹āύāĻžāϏ — URL-driven Modal (React Router v8): Deep-linking āϏāĻžāĻĒā§‹āĻ°ā§āϟ āϚāĻžāχāϞ⧇ /movies/:id āϰāĻžāωāĻŸā§‡ āĻŽāĻĄāĻžāϞ-āĻ­āĻŋāĻ¤ā§āϤāĻŋāĻ• āĻĄāĻŋāĻŸā§‡āχāϞāϏ āĻĒ⧇āϜ āĻŽā§āϝāĻžāĻĒ āĻ•āϰāĻž āϝāĻžāϝāĻŧ:

npm install react-router
import {
  BrowserRouter,
  Routes,
  Route,
  useParams,
  useNavigate,
} from "react-router";

function MovieDetailsRoute() {
  const { id } = useParams();
  const navigate = useNavigate();
  const movie = movies.find((m) => m.id === Number(id));
  return <MovieDetailsModal movie={movie} onClose={() => navigate(-1)} />;
}

āϞāĻ•ā§āώ āĻ•āϰ⧁āύ — āĻāĻ–āύ āĻĨ⧇āϕ⧇ āĻļ⧁āϧ⧁ react-router āĻĒā§āϝāĻžāϕ⧇āϜ āχāĻŽā§āĻĒā§‹āĻ°ā§āϟ āĻ•āϰāϞ⧇āχ āĻšāϝāĻŧāĨ¤ react-router-dom āĻāĻ–āύ react-router-āĻāϰāχ āĻāĻ•āϟāĻž re-export āĻŽāĻžāĻ¤ā§āϰāĨ¤


āϧāĻžāĻĒ ā§Ž: āϞāĻžāχāϟ āĻ…āĻĢ, āĻĄāĻžāĻ°ā§āĻ• āĻ…āύ — Theme Switch 🌗

āĻĨāĻŋāĻŽ āϏ⧁āχāϚāĻŋāĻ‚āϝāĻŧ⧇āϰ āϜāĻ¨ā§āϝ āφāϞāĻžāĻĻāĻž āĻāĻ•āϟāĻž ThemeContext āĻŦāĻžāύāĻžāĻŦā§‹, āϝāĻž āĻĒ⧁āϰ⧋ āĻ…ā§āϝāĻžāĻĒ⧇ theme state āĻļ⧇āϝāĻŧāĻžāϰ āĻ•āϰāĻŦ⧇ āĻāĻŦāĻ‚ localStorage-āĻ persist āĻ•āϰāĻŦ⧇ — āϝāĻžāϤ⧇ āĻĒ⧇āϜ āϰāĻŋāĻĢā§āϰ⧇āĻļ⧇āϰ āĻĒāϰāĻ“ āχāωāϜāĻžāϰ⧇āϰ āĻĒāĻ›āĻ¨ā§āĻĻ āĻŽāύ⧇ āĻĨāĻžāϕ⧇āĨ¤

// src/context/ThemeContext.jsx
import { createContext, useContext, useEffect, useState } from "react";

const ThemeContext = createContext(null);

export function ThemeProvider({ children }) {
  const [theme, setTheme] = useState(
    () => localStorage.getItem("theme") || "light",
  );

  useEffect(() => {
    const root = document.documentElement;
    root.classList.toggle("dark", theme === "dark");
    localStorage.setItem("theme", theme);
  }, [theme]);

  const toggleTheme = () =>
    setTheme((prev) => (prev === "light" ? "dark" : "light"));

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

export function useTheme() {
  const context = useContext(ThemeContext);
  if (!context) {
    throw new Error("useTheme must be used within a ThemeProvider");
  }
  return context;
}

main.jsx-āĻ āĻĒ⧁āϰ⧋ āĻ…ā§āϝāĻžāĻĒāϕ⧇ ThemeProvider āĻ“ CartProvider āĻĻāĻŋāϝāĻŧ⧇ wrap āĻ•āϰ⧇ āĻĻ⧇āĻŦ (Provider-āĻāϰ nesting order āĻŸā§‡āĻ•āύāĻŋāĻ•ā§āϝāĻžāϞāĻŋ āĻŽā§āϝāĻžāϟāĻžāϰ āĻ•āϰ⧇ āύāĻž, āϤāĻŦ⧇ readability-āϰ āϜāĻ¨ā§āϝ āϏāĻŦāĻšā§‡āϝāĻŧ⧇ āĻ—ā§āϞ⧋āĻŦāĻžāϞ context āĻŦāĻžāχāϰ⧇ āϰāĻžāĻ–āĻžāχ āĻ­āĻžāϞ⧋):

import { ThemeProvider } from "./context/ThemeContext";
import { CartProvider } from "./context/CartContext";

createRoot(document.getElementById("root")).render(
  <ThemeProvider>
    <CartProvider>
      <App />
    </CartProvider>
  </ThemeProvider>,
);

Tailwind v4-āĻāϰ dark variant āφāĻŽāϰāĻž āφāϗ⧇āχ āϧāĻžāĻĒ ā§¨-āĻ @custom-variant dark (&:where(.dark, .dark *)); āĻĻāĻŋāϝāĻŧ⧇ āĻ•āύāĻĢāĻŋāĻ—āĻžāϰ āĻ•āϰ⧇ āϰ⧇āϖ⧇āĻ›āĻŋāĨ¤ āĻĢāϞ⧇ dark:bg-black dark:text-white-āĻāϰ āĻŽāϤ⧋ āĻ•ā§āϞāĻžāϏāϗ⧁āϞ⧋ <html> āĻŸā§āϝāĻžāϗ⧇ .dark āĻ•ā§āϞāĻžāϏ āĻĨāĻžāĻ•āϞ⧇āχ āĻ…ā§āϝāĻžāĻ•ā§āϟāĻŋāĻ­ āĻšāϝāĻŧ⧇ āϝāĻžāĻŦ⧇ — āϝ⧇āϟāĻž āφāĻŽāĻžāĻĻ⧇āϰ ThemeContext āϟāĻ—āϞ āĻ•āϰ⧇ āĻĻāĻŋāĻšā§āϛ⧇āĨ¤

Flash of Unstyled Theme (FOUC) āϠ⧇āĻ•āĻžāύ: React hydrate āĻšāĻ“āϝāĻŧāĻžāϰ āφāϗ⧇āχ āϝ⧇āύ āϏāĻ āĻŋāĻ• āĻĨāĻŋāĻŽ apply āĻšāϝāĻŧ⧇ āϝāĻžāϝāĻŧ, āϤāĻžāϰ āϜāĻ¨ā§āϝ index.html-āĻ <body>-āĻāϰ āφāϗ⧇ āĻāĻ•āϟāĻž āϛ⧋āĻŸā§āϟ blocking script āĻŦāϏāĻŋāϝāĻŧ⧇ āĻĻāĻŋāύ:

<script>
  (function () {
    const theme = localStorage.getItem("theme") || "light";
    document.documentElement.classList.toggle("dark", theme === "dark");
  })();
</script>

āĻĨāĻŋāĻŽ āϏ⧁āχāϚāĻžāϰ āĻ¸ā§āϟāĻžāχāϞ⧇āϰ āϰ⧇āĻĢāĻžāϰ⧇āĻ¨ā§āϏ āĻ•ā§āϞāĻžāϏ — styles.css-āĻ āϝ⧋āĻ— āĻ•āϰāϤ⧇ āĻšāĻŦ⧇:

theme-switcher-class

āϧāĻžāĻĒ ā§¯: āϕ⧋āĻĄ āϕ⧋āϝāĻŧāĻžāϞāĻŋāϟāĻŋ — āĻļ⧇āώ āĻĒāĻžāϞāĻŋāĻļ

Vite-āĻāϰ React āĻŸā§‡āĻŽāĻĒā§āϞ⧇āĻŸā§‡ āĻĄāĻŋāĻĢāĻ˛ā§āϟ ESLint flat config (eslint.config.js) āφāϗ⧇ āĻĨ⧇āϕ⧇āχ āĻĨāĻžāϕ⧇, āϝāĻž React Hooks rules āφāϰ Fast Refresh āĻ•āύāϭ⧇āύāĻļāύ āĻāύāĻĢā§‹āĻ°ā§āϏ āĻ•āϰ⧇āĨ¤ āϏāĻžāĻĨ⧇ Prettier āϝ⧋āĻ— āĻ•āϰ⧇ āĻĻāĻŋāϞ⧇ āϕ⧋āĻĄ āĻĢāϰāĻŽā§āϝāĻžāϟāĻŋāĻ‚ āĻ•āύāϏāĻŋāĻ¸ā§āĻŸā§‡āĻ¨ā§āϟ āĻĨāĻžāϕ⧇:

npm install -D prettier eslint-config-prettier

āϟāĻŋāĻŽā§‡ āĻ•āĻžāϜ āĻ•āϰāϞ⧇ commit-āĻāϰ āφāϗ⧇ lint/format āύāĻŋāĻļā§āϚāĻŋāϤ āĻ•āϰāϤ⧇ husky + lint-staged āϏ⧇āϟāφāĻĒ āĻ•āϰ⧇ āύāĻŋāϤ⧇ āĻĒāĻžāϰ⧇āύ — āĻāϤ⧇ inconsistent āϕ⧋āĻĄ āĻŽā§‡āχāύ āĻŦā§āϰāĻžāĻžā§āĻšā§‡ āĻĸ⧁āĻ•āϤ⧇ āĻĒāĻžāϰāĻŦ⧇ āύāĻžāĨ¤


đŸŽŦ āĻ•āĻžāϟ! — āĻĒāϰ⧇āϰ āϧāĻžāĻĒ⧇ āϝāĻžāĻ“āϝāĻŧāĻžāϰ āφāϗ⧇ āĻšā§‡āĻ•āϞāĻŋāĻ¸ā§āϟ

  • Vite + React 19.2 āĻĒā§āϰāĻœā§‡āĻ•ā§āϟ āϰāĻžāύ āĻšāĻšā§āϛ⧇, HMR āĻ•āĻžāϜ āĻ•āϰāϛ⧇āĨ¤
  • Tailwind CSS v4 @theme āĻ•āύāĻĢāĻŋāĻ—āϏāĻš āχāĻ¨ā§āϏāϟāϞ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇; āĻ•āĻžāĻ¸ā§āϟāĻŽ āĻ•āĻžāϞāĻžāϰ āĻŸā§‹āϕ⧇āύ āĻ“ @custom-variant dark āϭ⧇āϰāĻŋāĻĢāĻžāχ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇āĨ¤
  • HTML template-āĻāϰ āϏāĻŦ āĻŽāĻžāĻ°ā§āĻ•āφāĻĒ JSX āϏāĻŋāύāĻŸā§āϝāĻžāĻ•ā§āϏ āĻ…āύ⧁āϝāĻžāϝāĻŧā§€ āϰ⧂āĻĒāĻžāĻ¨ā§āϤāϰāĻŋāϤ āĻšāϝāĻŧ⧇āϛ⧇, assets āĻ“ āφāχāĻ•āύ āĻŽāĻžāχāĻ—ā§āϰ⧇āϟ āĻšāϝāĻŧ⧇āϛ⧇āĨ¤
  • āĻĢā§‹āĻ˛ā§āĻĄāĻžāϰ āφāĻ°ā§āĻ•āĻŋāĻŸā§‡āĻ•āϚāĻžāϰ āĻ…āύ⧁āϝāĻžāϝāĻŧā§€ āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āϟāϗ⧁āϞ⧋ (Navbar, MovieCard, MovieGrid, Footer āχāĻ¤ā§āϝāĻžāĻĻāĻŋ) āϤ⧈āϰāĻŋ āĻ“ composed āĻšāϝāĻŧ⧇āϛ⧇āĨ¤
  • src/data/movies.js-āĻ mock āĻĄā§‡āϟāĻž āϤ⧈āϰāĻŋ āĻ“ āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āĻŸā§‡ wire āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇āĨ¤
  • CartContext + cartReducer āĻĻāĻŋāϝāĻŧ⧇ Add/Remove/Duplicate-warning āĻĢāĻŋāϚāĻžāϰ āĻ•āĻžāϜ āĻ•āϰāϛ⧇āĨ¤
  • MovieDetailsModal createPortal āĻĻāĻŋāϝāĻŧ⧇ āĻ•āĻžāϜ āĻ•āϰāϛ⧇, Escape āϕ⧀ āĻĻāĻŋāϝāĻŧ⧇ āĻŦāĻ¨ā§āϧ āĻšāĻšā§āϛ⧇āĨ¤
  • Theme Context āĻĻāĻŋāϝāĻŧ⧇ Light/Dark mode āϟāĻ—āϞ āĻ•āĻžāϜ āĻ•āϰāϛ⧇, āϰāĻŋāĻĢā§āϰ⧇āĻļ⧇āϰ āĻĒāϰāĻ“ persist āĻ•āϰāϛ⧇, FOUC āύ⧇āχāĨ¤
  • ESLint/Prettier āϏ⧇āϟāφāĻĒ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇āĨ¤

āϏāĻŦ āĻŦāĻ•ā§āϏ⧇ āϟāĻŋāĻ• āĻĒāĻĄāĻŧāϞ⧇ — āĻ•āĻžāϟ, āĻĒā§āϰāĻŋāĻ¨ā§āϟ! đŸŽĨ āφāĻĒāύāĻžāϰ Movie Portal-āĻāϰ Act 1 āĻļ⧇āώāĨ¤ āĻĒāϰ⧇āϰ āĻĒāĻ°ā§āĻŦ⧇ āφāĻŽāϰāĻž āϏāĻžāĻ°ā§āϚ, āĻĢāĻŋāĻ˛ā§āϟāĻžāϰ āφāϰ āϰāĻŋāϝāĻŧ⧇āϞ API āύāĻŋāϝāĻŧ⧇ āĻ•āĻĨāĻž āĻŦāϞāĻŦāĨ¤

On this page

Step 1: Movie Portal āφāϏāϞ⧇ āϕ⧀ āϜāĻŋāύāĻŋāϏ? đŸŽĨStep 2: āϕ⧋āĻĄ āϞ⧇āĻ–āĻžāϰ āφāϗ⧇ — āĻ¸ā§āĻ•ā§āϰāĻŋāĻĒā§āϟ āϰ⧇āĻĄāĻŋ āĻ•āϰ⧁āύ đŸ“ā§§. āĻĒā§āϰāĻœā§‡āĻ•ā§āĻŸā§‡āϰ āĻ¸ā§āϕ⧋āĻĒ āĻ āĻŋāĻ• āĻ•āϰ⧁āύ⧍. āĻĢāĻŋāϚāĻžāϰ āϞāĻŋāĻ¸ā§āϟ āĻ“ āχāωāϜāĻžāϰ āĻ¸ā§āĻŸā§‹āϰāĻŋā§Š. UI/UX āĻĄāĻŋāϜāĻžāχāύ āϰ⧇āĻĄāĻŋ āĻ•āϰ⧁āύā§Ē. āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āϟ āĻŦā§āϰ⧇āĻ•āĻĄāĻžāωāύ — UI-āϕ⧇ āϟ⧁āĻ•āϰ⧋ āϟ⧁āĻ•āϰ⧋ āĻ•āϰ⧁āύā§Ģ. āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āϟ āĻšāĻžāϝāĻŧāĻžāϰāĻžāĻ°ā§āĻ•āĻŋ — āϕ⧇ āĻ•āĻžāϰ āϭ⧇āϤāϰ⧇ āĻĨāĻžāĻ•āĻŦ⧇ā§Ŧ. Data Flow / State Planningā§­. Routes Planning (React Router)ā§Ž. āĻĢā§‹āĻ˛ā§āĻĄāĻžāϰ āĻ¸ā§āĻŸā§āϰāĻžāĻ•āϚāĻžāϰ āĻĒā§āĻ˛ā§āϝāĻžāύ āĻ•āϰ⧁āĻ¨âšĄ āĻŦā§‹āύāĻžāϏ āϟāĻŋāĻĒāϏāĻŦā§āϝāĻŦāĻšā§ƒāϤ āĻŸā§‡āĻ•āύ⧋āϞāϜāĻŋ āĻ“ āφāĻ°ā§āĻ•āĻŋāĻŸā§‡āĻ•āϚāĻžāϰ đŸ—ī¸ā§§. Component-Based Architecture⧍. Component Mind Map & UI Planningā§Š. Context API — Prop Drilling-āĻāϰ āϝāĻ¨ā§āĻ¤ā§āϰāĻŖāĻž āĻĨ⧇āϕ⧇ āĻŽā§āĻ•ā§āϤāĻŋā§Ē. Reducer Pattern (useReducer) — āϜāϟāĻŋāϞ State-āϕ⧇ āĻļ⧃āĻ™ā§āĻ–āϞāĻžāϝāĻŧ āφāύāĻžStep 3: āĻ…ā§āϝāĻžāĻ•āĻļāύ! āϕ⧋āĻĄ āϞ⧇āĻ–āĻž āĻļ⧁āϰ⧁ āĻ•āϰāĻŋ đŸŽŦāĻāχ āϧāĻžāĻĒ⧇āϰ āĻĒ⧁āϰ⧋ āĻ“āϝāĻŧāĻžāĻ°ā§āĻ•āĻĢā§āϞ⧋āϧāĻžāĻĒ ā§§: Vite + React āĻĒā§āϰāĻœā§‡āĻ•ā§āϟ āĻŦ⧁āϟāĻ¸ā§āĻŸā§āĻ°ā§āϝāĻžāĻĒāϧāĻžāĻĒ ā§¨: Tailwind CSS v4 — āĻ•āύāĻĢāĻŋāĻ—āĻžāϰ⧇āĻļāύ⧇āϰ āύāϤ⧁āύ āύāĻŋāϝāĻŧāĻŽāϧāĻžāĻĒ ā§Š: HTML Template āĻĨ⧇āϕ⧇ JSX — āĻ…āύ⧁āĻŦāĻžāĻĻ⧇āϰ āύāĻŋāϝāĻŧāĻŽāĻ•āĻžāύ⧁āύāϧāĻžāĻĒ ā§Ē: āĻĢā§‹āĻ˛ā§āĻĄāĻžāϰ āφāĻ°ā§āĻ•āĻŋāĻŸā§‡āĻ•āϚāĻžāϰ āĻ“ āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āϟ āϤ⧈āϰāĻŋāϧāĻžāĻĒ ā§Ģ: Data āĻĢā§‹āĻ˛ā§āĻĄāĻžāϰ — āĻŽā§āĻ­āĻŋ āĻĄā§‡āϟāĻž āĻšāĻžāĻ°ā§āĻĄāϕ⧋āĻĄ āϰāĻžāĻ–āĻžāϧāĻžāĻĒ ā§Ŧ: CartContext āĻ“ useReducer āĻĻāĻŋāϝāĻŧ⧇ Cart āϏāĻŋāĻ¸ā§āĻŸā§‡āĻŽāϧāĻžāĻĒ ā§­: MovieDetailsModal — āĻ•ā§āϞ⧋āϜ āφāĻĒ āĻļāϟāϧāĻžāĻĒ ā§Ž: āϞāĻžāχāϟ āĻ…āĻĢ, āĻĄāĻžāĻ°ā§āĻ• āĻ…āύ — Theme Switch 🌗āϧāĻžāĻĒ ā§¯: āϕ⧋āĻĄ āϕ⧋āϝāĻŧāĻžāϞāĻŋāϟāĻŋ — āĻļ⧇āώ āĻĒāĻžāϞāĻŋāĻļđŸŽŦ āĻ•āĻžāϟ! — āĻĒāϰ⧇āϰ āϧāĻžāĻĒ⧇ āϝāĻžāĻ“āϝāĻŧāĻžāϰ āφāϗ⧇ āĻšā§‡āĻ•āϞāĻŋāĻ¸ā§āϟ