/tsuber-eats-frontend

Tsuber Eats Clone Frontend. Typescript, GraphQL, Jest, Cypress, React Testing Library

Primary LanguageCSS

Tsuber Eats Frontend

The Frontend of Tsuber Eats

๐Ÿ‘‰ The Backend of Tsuber Eats

Description

Cloning User Eats by Using React, TypeScript and GraphQL Apollo

+ Testing with React Testing Library(Unit Test) and Cypress(E2E Test)

Demo

Tsuber Eats

Preview



Technology Stack

Frontend Technology Description
01 React CRA
02 TypeScript Add Type
02 TailwindCSS Styling Method
03 GraphQL Apollo Pull Data
04 React Testing Library Unit Test
05 Cypress E2E Test
Backend Technology Description
01 NestJS Node Framework
02 GraphQL Resolver
03 TypeScript Add Type
04 TypeORM Database
05 JsonWebToken Authentication
06 Mailgun Mail Service
07 Jest Unit / E2E TEST

Directory Structure

coverage
cypress
node_modules
public
src
|-- __generated__
|-- components
|-- hooks
|-- images
|-- pages
|   |-- client
|   |-- driver
|   |-- owner
|   |-- user
|-- routers
|-- styles
...

Project Screen Function

  • User
    • Home
      • ๋กœ๊ทธ์ธ | ๋กœ๊ทธ์•„์›ƒ ๋ผ์šฐํ„ฐ ๋ถ„๋ฆฌ
    • Show
      • User ์ •๋ณดํ™•์ธ
    • Edit
      • User ์ •๋ณด์ˆ˜์ •
      • Navigation Geolocation์„ ์‚ฌ์šฉํ•ด ์œ ์ € ์œ„์น˜ ์—…๋ฐ์ดํŠธ
  • Client
    • Home
      • Restaurants ๋ฆฌ์ŠคํŠธ ๋ณด๊ธฐ
    • Restaurant
      • Menu ๋ฆฌ์ŠคํŠธ ๋ณด๊ธฐ
      • Order ์ƒ์„ฑํ•˜๊ธฐ
    • Order
      • ์‹ค์‹œ๊ฐ„ Order Status ํ™•์ธํ•˜๊ธฐ
  • Owner
    • Home
      • Owner Restaurants ๋ฆฌ์ŠคํŠธ ๋ณด๊ธฐ
    • Restaurant
      • Menu ๋ฆฌ์ŠคํŠธ ๋ณด๊ธฐ
      • Victory ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•œ ๋งค์ถœํ‘œ ๋ณด๊ธฐ
    • Menu
      • Menu ์ƒ์„ฑ | ์ˆ˜์ • | ์‚ญ์ œํ•˜๊ธฐ
    • Order
      • ์‹ค์‹œ๊ฐ„ Order Status ํ™•์ธํ•˜๊ธฐ
      • Client ์ธก์—์„œ Order ์ƒ์„ฑ ์‹œ, Order ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ
  • Driver
    • Home
      • Order Dashboard ๋ณด๊ธฐ
      • Owner ์ธก์—์„œ Menu ์ค€๋น„ ์™„๋ฃŒ ์‹œ, Google Map API๋ฅผ ํ™œ์šฉํ•œ ๋ผ์šฐํŒ… ๋ณด์—ฌ์ง€๊ธฐ
    • Order
      • ์‹ค์‹œ๊ฐ„ Order Status ํ™•์ธํ•˜๊ธฐ
      • Order ํŒŒํŠธ ๋งˆ๋ฌด๋ฆฌํ•˜๊ธฐ

Project Purpose

๋ณธ ํ”„๋กœ์ ํŠธ๋Š” ์•„๋ž˜์˜ ๋ช‡๊ฐ€์ง€ ์ด์œ ๋ฅผ ์ถฉ์กฑ์‹œํ‚ค๊ธฐ ์œ„ํ•ด ํด๋ก ์ฝ”๋”ฉํ•œ ๊ฒƒ ์ž…๋‹ˆ๋‹ค.

  • TypeScript๋ฅผ ์ ๋Š” ๋ฐฉ์‹์— ์ต์ˆ™ํ•ด์ง€๊ณ  JavaScript์— Type์„ ๊ณ๋“ค์ด๋ฉด ์™œ ์ข‹์€์ง€ ๋Š๊ปด๋ณด๊ธฐ
  • GraphQL์„ ์™„์ „ํžˆ ์‚ฌ์šฉํ•ด๋ณด๊ณ  REST API์™€ ์–ด๋–ค ์ฐจ์ด์ ์ด ์žˆ๋Š”์ง€ ์ƒ๊ฐํ•ด๋ณด๊ธฐ
  • ๋ฐฑ์—”๋“œ ์Šคํƒ์œผ๋กœ NodeJS์™€ NestJS ์ค‘ ๋ฌด์—‡์ด ๋‚˜์—๊ฒŒ ์•Œ๋งž์€์ง€ ๊ฒฝํ—˜ํ•˜๊ธฐ
  • ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ์„ ํ•ด๋ด„์œผ๋กœ์จ ์•ˆ์ •๋œ ํ”„๋กœ์ ํŠธ ๋นŒ๋“œ

Memoir

  • JavaScript vs TypeScript

    ์ด๋ฒˆ ํ”„๋กœ์ ํŠธ์—์„œ ์ฒ˜์Œ์œผ๋กœ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ „๋ถ€ ์ ์šฉํ•ด๋ดค๋Š”๋ฐ ๊ฐœ์ธ์ ์ธ ์ƒ๊ฐ์œผ๋กœ๋Š” ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ๋นŒ๋“œ ๊ฒฝํ—˜์ด ๋งค์šฐ ์ข‹์•˜๋‹ค๊ณ  ๋Š๊ปด์ง‘๋‹ˆ๋‹ค.

    ํƒ€์ž…์„ ์ถ”๋ก ํ•˜๊ฑฐ๋‚˜ ํƒ€์ž…์„ ์ง์ ‘ ์ž‘์„ฑํ•˜๋Š” ์ผ์€ ๋•Œ๋•Œ๋กœ ์‹œ๊ฐ„์ด ๋งŽ์ด ๊ฑธ๋ฆฌ๋Š” ๊ฒฝ์šฐ๋„ ์žˆ์—ˆ์œผ๋‚˜ ํƒ€์ž…์„ ์ ๊ณ ๋‚œ ํ›„, VSC์—์„œ ์ง€์›ํ•˜๋Š” auto complete๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด์„œ ํƒ€์ž…์ด ์กด์žฌํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๋ฐ”๋กœ๋ฐ”๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๊ณ  ๊ทธ ๋•๋ถ„์— ์ค‘์š”ํ•œ ์ž‘์—…๋“ค์ด ์—๋Ÿฌ๋ฅผ ๊ฑฐ์น˜์ง€ ์•Š๊ณ  ๋ฐ”๋กœ๋ฐ”๋กœ ์‹คํ–‰๋˜๋Š” ๊ฒฝํ—˜์„ ํ•  ์ˆ˜๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

    ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ๋Š” ์ ˆ๋Œ€ ๋ถˆ๊ฐ€๋Šฅํ•œ ์ผ์ด์—ˆ๋‹ค. ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ ๋ถ„๋ช…ํžˆ ์–ด๋”˜๊ฐ€์— ์‹ค์ˆ˜๋ฅผ ์œ ๋ฐœํ•ด ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ณ  ๊ฐ€๋”์€ ์–ด๋””์„œ ๋ฐœ์ƒํ•œ ์—๋Ÿฌ์ธ์ง€ ์•Œ๊ธฐ ์–ด๋ ค์šธ ๋•Œ๋„ ์กด์žฌํ•œ ์ ๋„ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

    ์ด๋Ÿฌํ•œ ์—๋Ÿฌ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๊ณ  ๋…ธ๋ ฅํ•˜๋Š” ์‹œ๊ฐ„์— ๋น„ํ•ด ํƒ€์ž…์„ ์ ๋Š” ์ผ์€ ์ ˆ๋ฐ˜๋„ ์ฑ„ ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋ฐ˜๋“œ์‹œ ์‹œ๊ฐ„์„ ๋‚ญ๋น„ํ•˜๋Š” ์ผ๋งŒ์€ ์•„๋‹Œ ๊ฒƒ ๊ฐ™๋‹ค.

    ์•ž์œผ๋กœ ์ „์ž์™€ ํ›„์ž ์ค‘ ๋ฌด์—‡์„ ์„ ํƒํ•  ๊ฒƒ์ธ์ง€ ๋”ฐ์ ธ๋ณธ๋‹ค๋ฉด ํŠน๋ณ„ํ•œ ์ด์œ ๊ฐ€ ์—†๋‹ค๊ณ  ๊ฐ€์ •ํ–ˆ์„ ๋•Œ ํ›„์ž๋ฅผ ํƒํ•  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • GraphQL vs REST API

    GraphQL์„ ์‚ฌ์šฉํ•ด๋ณด๋ฉด์„œ ์„œ๋ฒ„์— ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•˜์ง€ ์•Š๊ณ  ์ž์‹ ์˜ ์ƒํ™ฉ์— ๋งž์ถฐ ์›ํ•˜๋Š” ํ•„๋“œ๋“ค๋งŒ ์š”์ฒญํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ๋” ์ข‹๊ฒŒ ๋งŒ๋“ค์–ด ์ค„ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

    ํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ ๋” ์ข‹์•˜๋˜ ๋ถ€๋ถ„์€ Apollo Client Cache๋ฅผ ์ ๊ทน ํ™œ์šฉํ–ˆ์„ ๋•Œ ์ž…๋‹ˆ๋‹ค.

    Apollo๋Š” ๋ฐฑ์—”๋“œ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•˜๊ธฐ ์ „์— Cache์— ๋ฐ์ดํ„ฐ๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ๋จผ์ € ํ™•์ธํ•˜๊ฒŒ ๋˜๋Š”๋ฐ ์ด ์ ์„ ์ด์šฉํ•ด API ์š”์ฒญ ํšŸ์ˆ˜๋ฅผ ์ค„์ด๋Š” ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

    Mutation์ด ๋ฐœ์ƒํ•œ ํ›„ refetchQueries ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด query ์š”์ฒญ์„ ๋‹ค์‹œ ํ•œ ๋ฒˆ ํ•˜์ง€์•Š๊ณ  cache data๋ฅผ ์ง์ ‘ ์ˆ˜์ •ํ•˜์—ฌ data๋ฅผ ๋ณ€๊ฒฝํ•ด์ฃผ๋Š” ์‹œ๋„๋ฅผ ํ–ˆ๋Š”๋ฐ ๊ฒฐ๊ณผ์ ์œผ๋กœ ๋งค์šฐ ๋น ๋ฅธ ์ƒํ˜ธ์ž‘์šฉ์„ ๋ณด์—ฌ์คฌ์Šต๋‹ˆ๋‹ค.

    ์ด๋Š” GraphQL์—์„œ ๋ฐœ๊ฒฌํ•œ ๊ฐ€์žฅ ๋ฉ‹์ง„ ๋ถ€๋ถ„์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

  • NodeJS vs NestJS

    NestJS๋Š” NodeJS์™€ ๋‹ค๋ฅด๊ฒŒ ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

    NodeJS์—์„œ๋Š” ์–ด๋””์— ์–ด๋–ค ํŒŒ์ผ์„ ์œ„์น˜ํ•˜์—ฌ๋„ ์ƒ๊ด€์ด ์—†์ง€๋งŒ NestJS์—์„œ๋Š” ๋ชจ๋“  ๊ฒƒ์ด Moudle๋กœ ์ด๋ฃจ์–ด์ง€๋ฉฐ ์ด๋Š” ์บก์Šํ™”๋ฅผ ํ†ตํ•ด ์ฒ ์ €ํžˆ ๋ถ„๋ฆฌํ•˜๋Š” ์ž‘์—…์„ ํ•ฉ๋‹ˆ๋‹ค.

    ๊ทธ๋ ‡๋‹ค๊ณ  ์„œ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๊ณ  ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•จ์œผ๋กœ์จ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ด๋กœ ์ธํ•ด ๋ถ„๋ฆฌํ™”๊ฐ€ ์ด๋ฃจ์–ด์ ธ๋„ ์„œ๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋Š” ๋Š๋‚Œ์„ ๋ฐ›์Šต๋‹ˆ๋‹ค.

    ์ด๊ฒƒ์€ ๊ต‰์žฅํžˆ ํŠผํŠผํ•œ ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง€๊ฒŒ ํ•˜๋ฉฐ NodeJS์—์„œ๋Š” ์ฐพ์•„๋ณผ ์ˆ˜ ์—†๋Š” ๋ฉ‹์ง„ ์žฅ์  ์ค‘ ํ•˜๋‚˜๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

    ๋˜๋Š” TypeScript ๊ธฐ๋ฐ˜์œผ๋กœ ๋œ NestJS๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด์„œ ์•ˆ์ •๋œ ์ฝ”๋“œ ์ž‘์„ฑ์„ ํ•  ์ˆ˜ ์žˆ๋Š” ์ ๋„ ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    ๊ทธ ์™ธ์— DTO -> Resolver -> Service ํŒจํ„ด์œผ๋กœ ๋ฐ˜๋ณต์ ์ธ ์ž‘์—…์„ ํ•˜๋ฉด์„œ ๊ต‰์žฅํžˆ ๋น ๋ฅด๊ฒŒ ๋ฐฑ์—”๋“œ๋ฅผ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ๊ณผ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์™€ ๋ชจ๋“ˆ์„ ๋™์ ์œผ๋กœ ์ƒ์„ฑํ•ด ๋‹ค์–‘ํ•˜๊ฒŒ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ๋„ NestJS๋งŒ์˜ ๋ฉ‹์ง„ ์ด์œ ์ธ ๋“ฏ ํ•ฉ๋‹ˆ๋‹ค.

    ๊ฐœ์ธ์ ์œผ๋กœ๋Š” ์ž์œ ๋ถ„๋ฐฉํ•œ ๋Š๋‚Œ์„ ์ฃผ๋Š” NodeJS๋ณด๋‹ค ์ผ์ •ํ•œ ๊ทœ์น™๊ณผ ํŒจํ„ด์„ ๊ฐ€์ง„ NestJS๊ฐ€ ๊ต‰์žฅํžˆ ๋งค๋ ฅ์ ์œผ๋กœ ๋‹ค๊ฐ€์™”์Šต๋‹ˆ๋‹ค.

  • Testing


    Unit Test | E2E Test ๋ชจ๋‘ ์ง„ํ–‰ํ•ด ๋ณด์•˜๊ณ  ์œ„์™€ ๊ฐ™์ด ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ…Œ์ŠคํŒ… ํ•ด๋ดค์Šต๋‹ˆ๋‹ค.

    ๊ฐœ์ธ์ ์œผ๋กœ Unit Test๋ณด๋‹ค๋Š” E2E Test์—์„œ ํ•„์š”์„ฑ์„ ๋Š๊ผˆ๋Š”๋ฐ ํŠนํžˆ Cypress๋ฅผ ์‚ฌ์šฉํ•ด Front Part๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋ฉด์„œ ์˜ค๋ฅ˜๋ฅผ ๊ฒ€์ถœํ•œ ๊ฒฝํ—˜์ด ์žˆ์–ด Test์˜ ํ•„์š”์„ฑ์„ ๋Š๋ผ๊ฒŒ ๋˜์—ˆ๋‹ค.

    ์ตœ๊ทผ์—๋Š” StoryBook์ด๋ผ๋Š” library์— ๋Œ€ํ•ด์„œ๋„ ์•Œ๊ฒŒ ๋˜์—ˆ๋Š”๋ฐ ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง์„ ์ œ์™ธํ•˜๊ณ  UI ๋ถ€๋ถ„์„ ํ…Œ์ŠคํŠธํ•˜๋ฉด์„œ Cypress๋„ ๊ฐ™์ด ์‚ฌ์šฉํ•ด๋ณด๋ฉด ์ข‹๊ฒ ๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค.

Code Challenge

  • Restaurant Hook์„ ๋งŒ๋“ค์–ด Page ๋ณ„๋„์˜ Pagination ๊ตฌํ˜„
  • Create Dish ๊ธฐ๋Šฅ์—์„œ Dish Option ์ค‘ Sub Option ๊ตฌํ˜„
  • Edit Dish ๊ตฌํ˜„
  • User Location Field ์ถ”๊ฐ€
  • Edit User Page์—์„œ Navigator Location์„ ์‚ฌ์šฉํ•ด ์‚ฌ์šฉ์ž ์œ„์น˜์ •๋ณด ์—…๋ฐ์ดํŠธ
  • Driver์™€ Customer ๊ฐ„, latitude | longitude ๋น„๊ต ํ›„ Google Map์— Route ํ‘œ์‹œํ•˜๊ธฐ

Move Forward

  • Gatsby๋ฅผ ์‚ฌ์šฉํ•ด ์ •์  ๋ธ”๋กœ๊ทธ ๋ฐ ํฌํŠธํด๋ฆฌ์˜ค ๋นŒ๋“œ
  • NestJS์™€ React๋ฅผ ์‚ฌ์šฉํ•ด ๊ฐœ์ธ ํ”„๋กœ์ ํŠธ(๋งˆํ”ผ์•„ ๊ฒŒ์ž„) ๋นŒ๋“œ