diff --git a/.babelrc b/.babelrc new file mode 100644 index 000000000..8aa924d7c --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["@babel/preset-env"] +} \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 000000000..54b9a9b16 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "extends": ["airbnb", "prettier"], + "env": { + "browser": true, + "jest/globals": true, + "es2020": true + }, + "parser": "@babel/eslint-parser", + "parserOptions": { + "ecmaVersion": 12, + "sourceType": "module" + }, + "plugins": ["prettier", "jest", "@babel"], + "rules": { + "import/extensions": ["off"], + "lines-between-class-members": ["off"] + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..448cd77c1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.vscode/ +node_modules/ +package.json +package-lock.json diff --git a/README.md b/README.md index e97a1d649..6cd835035 100644 --- a/README.md +++ b/README.md @@ -1,114 +1,155 @@ # ๐Ÿš‡ ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ๋ฏธ์…˜ +## ์†Œ๊ฐœ + +๋‚˜๋งŒ์˜ ์—ญ์„ ๋งŒ๋“ค๊ณ , ๋งŒ๋“ค์–ด์ง„ ์—ญ๋“ค์„ ๋ฐ”ํƒ•์œผ๋กœ ๋‚˜๋งŒ์˜ ์ง€ํ•˜์ฒ  ๋…ธ์„ ๊ณผ ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„๋ฅผ ์ œ์ž‘ํ•  ์ˆ˜ ์žˆ๋Š” ํ”„๋กœ๊ทธ๋žจ์ž…๋‹ˆ๋‹ค. ์‹ค์ œ ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„์™€ ์œ ์‚ฌํ•œ ๋…ธ์„ ๋„๋ฅผ ์ œ์ž‘ํ•  ์ˆ˜ ์žˆ๋„๋ก ์—ฌ๋Ÿฌ ๊ธฐ๋Šฅ๊ณผ ์ œ์•ฝ์‚ฌํ•ญ์ด ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค. + +

+ ## ๐Ÿš€ ๊ธฐ๋Šฅ ์š”๊ตฌ์‚ฌํ•ญ +
+ ### ์ง€ํ•˜์ฒ  ์—ญ ๊ด€๋ จ ๊ธฐ๋Šฅ -- ์ง€ํ•˜์ฒ  ์—ญ์„ ๋“ฑ๋กํ•˜๊ณ  ์‚ญ์ œํ•  ์ˆ˜ ์žˆ๋‹ค. (๋‹จ, ๋…ธ์„ ์— ๋“ฑ๋ก๋œ ์—ญ์€ ์‚ญ์ œํ•  ์ˆ˜ ์—†๋‹ค) -- ์ค‘๋ณต๋œ ์ง€ํ•˜์ฒ  ์—ญ ์ด๋ฆ„์ด ๋“ฑ๋ก๋  ์ˆ˜ ์—†๋‹ค. -- ์ง€ํ•˜์ฒ  ์—ญ์€ 2๊ธ€์ž ์ด์ƒ์ด์–ด์•ผ ํ•œ๋‹ค. -- ์ง€ํ•˜์ฒ  ์—ญ์˜ ๋ชฉ๋ก์„ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค. + +- ์ง€ํ•˜์ฒ  ์—ญ์„ ์ถ”๊ฐ€ (add subway station) + - :exclamation: ์˜ˆ์™ธ#1 - ์ถ”๊ฐ€ํ•˜๋ ค๋Š” ์—ญ์ด ๋‹ค๋ฅธ ์—ญ๊ณผ ์ค‘๋ณต๋œ ์ด๋ฆ„์„ ๊ฐ€์งˆ ๊ฒฝ์šฐ + - :exclamation: ์˜ˆ์™ธ#2 - ์—ญ์˜ ์ด๋ฆ„์ด 2๊ธ€์ž ๋ฏธ๋งŒ์ผ ๊ฒฝ์šฐ(ํ•œ๊ธ€, ์˜์–ด ๋ชจ๋‘) +- ์ง€ํ•˜์ฒ  ์—ญ์„ ์‚ญ์ œ (delete subway station) + - :exclamation: ์˜ˆ์™ธ#3 - ์‚ญ์ œํ•˜๋ ค๋Š” ์—ญ์ด ๋…ธ์„ ์— ์ถ”๊ฐ€๋˜์–ด ์žˆ๋Š” ๊ฒฝ์šฐ +- ์ง€ํ•˜์ฒ  ์—ญ ์ถ”๊ฐ€ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ๊ฒ€์‚ฌ (check if the subway station can be added) + - :wrench: ํ•ด๊ฒฐ(์˜ˆ์™ธ #1,#2) - ์ถ”๊ฐ€ํ•˜๋ ค๋Š” ์—ญ์˜ ์ด๋ฆ„์ด ๋‹ค๋ฅธ ์—ญ๊ณผ ์ค‘๋ณต๋˜๋Š”์ง€, 2๊ธ€์ž ๋ฏธ๋งŒ์ธ์ง€๋ฅผ ๊ฒ€์‚ฌ +- ์ง€ํ•˜์ฒ  ์—ญ ์‚ญ์ œ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ๊ฒ€์‚ฌ (check if the subway station can be deleted) + - :wrench: ํ•ด๊ฒฐ(์˜ˆ์™ธ #3) - ์‚ญ์ œํ•  ์ˆ˜ ์—†๋Š” ์—ญ์„ ์‚ญ์ œํ•˜๋ ค๋Š” ๊ฒƒ์ธ์ง€๋ฅผ ๊ฒ€์‚ฌ + +
### ์ง€ํ•˜์ฒ  ๋…ธ์„  ๊ด€๋ จ ๊ธฐ๋Šฅ -- ์ง€ํ•˜์ฒ  ๋…ธ์„ ์„ ๋“ฑ๋กํ•˜๊ณ  ์‚ญ์ œํ•  ์ˆ˜ ์žˆ๋‹ค. -- ์ค‘๋ณต๋œ ์ง€ํ•˜์ฒ  ๋…ธ์„  ์ด๋ฆ„์ด ๋“ฑ๋ก๋  ์ˆ˜ ์—†๋‹ค. -- ๋…ธ์„  ๋“ฑ๋ก ์‹œ ์ƒํ–‰ ์ข…์ ์—ญ๊ณผ ํ•˜ํ–‰ ์ข…์ ์—ญ์„ ์ž…๋ ฅ๋ฐ›๋Š”๋‹ค. -- ์ง€ํ•˜์ฒ  ๋…ธ์„ ์˜ ๋ชฉ๋ก์„ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค. + +- ์ง€ํ•˜์ฒ  ๋…ธ์„ ์„ ์ถ”๊ฐ€ (add subway line) + - :exclamation: ์˜ˆ์™ธ#4 - ์ถ”๊ฐ€ํ•˜๋ ค๋Š” ๋…ธ์„ ์ด ๋‹ค๋ฅธ ๋…ธ์„ ๊ณผ ์ค‘๋ณต๋œ ์ด๋ฆ„์„ ๊ฐ€์งˆ ๊ฒฝ์šฐ + - :exclamation: ์˜ˆ์™ธ#5 - ์ถ”๊ฐ€ํ•  ๋•Œ ์„ค์ •ํ•˜๋Š” ์ƒํ–‰, ํ•˜ํ–‰ ์ข…์ ์—ญ์ด ๊ฐ™์„ ๊ฒฝ์šฐ +- ์ง€ํ•˜์ฒ  ๋…ธ์„ ์„ ์‚ญ์ œ (delete subway line) +- ์ง€ํ•˜์ฒ  ๋…ธ์„  ์ถ”๊ฐ€ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ๊ฒ€์‚ฌ (check if the subway line can be added) + - :wrench: ํ•ด๊ฒฐ(์˜ˆ์™ธ #4,#5) - ์ถ”๊ฐ€ํ•˜๋ ค๋Š” ๋…ธ์„ ์ด ๋‹ค๋ฅธ ๋…ธ์„ ๊ณผ ์ค‘๋ณต๋œ ์ด๋ฆ„์„ ๊ฐ€์ง€๋Š”์ง€, ํ•ด๋‹น ๋…ธ์„ ์˜ ์ƒํ–‰, ํ•˜ํ–‰ ์ข…์ ์—ญ์ด ๊ฐ™์€์ง€๋ฅผ ๊ฒ€์‚ฌ +- ์ง€ํ•˜์ฒ  ๋…ธ์„ ์˜ ์ƒํ–‰ ์ข…์ ๋ถ€ํ„ฐ ํ•˜ํ–‰ ์ข…์ ๊นŒ์ง€ ์—ฐ๊ฒฐ๋œ ์ˆœ์„œ๋Œ€๋กœ ์—ญ ๋ชฉ๋ก์„ ์กฐํšŒ (get all subway stations in subway line) + +
+ +### ์ง€ํ•˜์ฒ  ์ „์ฒด ์ •๋ณด ์กฐํšŒ ๊ธฐ๋Šฅ + +- ์ „์ฒด ์ง€ํ•˜์ฒ  ์—ญ์˜ ๋ชฉ๋ก ์กฐํšŒ (get all subway stations) +- ์ „์ฒด ์ง€ํ•˜์ฒ  ๋…ธ์„ ์˜ ๋ชฉ๋ก ์กฐํšŒ (get all subway lines) + +
### ์ง€ํ•˜์ฒ  ๊ตฌ๊ฐ„ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ -- ์ง€ํ•˜์ฒ  ๋…ธ์„ ์— ๊ตฌ๊ฐ„์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ธฐ๋Šฅ์€ ๋…ธ์„ ์— ์—ญ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋ผ๊ณ ๋„ ํ•  ์ˆ˜ ์žˆ๋‹ค. - - ์—ญ๊ณผ ์—ญ์‚ฌ์ด๋ฅผ ๊ตฌ๊ฐ„์ด๋ผ ํ•˜๊ณ  ์ด ๊ตฌ๊ฐ„๋“ค์˜ ๋ชจ์Œ์ด ๋…ธ์„ ์ด๋‹ค. -- ํ•˜๋‚˜์˜ ์—ญ์€ ์—ฌ๋Ÿฌ๊ฐœ์˜ ๋…ธ์„ ์— ์ถ”๊ฐ€๋  ์ˆ˜ ์žˆ๋‹ค. -- ์—ญ๊ณผ ์—ญ ์‚ฌ์ด์— ์ƒˆ๋กœ์šด ์—ญ์ด ์ถ”๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค. -- ๋…ธ์„ ์—์„œ ๊ฐˆ๋ž˜๊ธธ์€ ์ƒ๊ธธ ์ˆ˜ ์—†๋‹ค. + +- ์ง€ํ•˜์ฒ  ๋…ธ์„ ์— ๊ตฌ๊ฐ„์„ ์ถ”๊ฐ€, ์ฆ‰ ์ง€ํ•˜์ฒ  ๋…ธ์„  ์•ˆ์˜ ๋‘ ์—ญ ์‚ฌ์ด์— ์ƒˆ๋กœ์šด ์—ญ ๋ผ์›Œ๋„ฃ๊ธฐ(insert subway station in subway line) + - :exclamation: ์˜ˆ์™ธ#6 - ๋ผ์›Œ ๋„ฃ์œผ๋ ค๋Š” ์—ญ์ด ์ด๋ฏธ ๋…ธ์„  ์•ˆ์— ์žˆ๋Š” ๊ฒฝ์šฐ + - :exclamation: ์˜ˆ์™ธ#7 - ๋ผ์›Œ๋„ฃ์œผ๋ ค๋Š” ์—ญ์˜ ์ˆœ์„œ๊ฐ€ ์ˆซ์ž๋กœ ํ‘œํ˜„๋˜์–ด ์žˆ์ง€ ์•Š์„ ๊ฒฝ์šฐ +- ์ง€ํ•˜์ฒ  ๋…ธ์„  ๊ตฌ๊ฐ„ ์ถ”๊ฐ€ ๊ฐ€๋Šฅ์„ฑ ์—ฌ๋ถ€ ๊ฒ€์‚ฌ (check if the subway station can be inserted) + - :wrench: ํ•ด๊ฒฐ(์˜ˆ์™ธ #6) - ๋ผ์›Œ ๋„ฃ์œผ๋ ค๋Š” ์—ญ์ด ์ด๋ฏธ ๋…ธ์„  ์•ˆ์— ์žˆ๋Š”์ง€ ๊ฒ€์‚ฌ + - :wrench: ํ•ด๊ฒฐ(์˜ˆ์™ธ #7) - ๋ผ์›Œ ๋„ฃ์œผ๋ ค๋Š” ์—ญ์˜ ์ˆœ์„œ๊ฐ’์ด ์ˆซ์ž์ธ์ง€ ๊ฒ€์‚ฌ + +
+
+ ### ์ง€ํ•˜์ฒ  ๊ตฌ๊ฐ„ ์‚ญ์ œ ๊ธฐ๋Šฅ -- ๋…ธ์„ ์— ๋“ฑ๋ก๋œ ์—ญ์„ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ๋‹ค. -- ์ข…์ ์„ ์ œ๊ฑฐํ•  ๊ฒฝ์šฐ ๋‹ค์Œ ์—ญ์ด ์ข…์ ์ด ๋œ๋‹ค. -- ๋…ธ์„ ์— ํฌํ•จ๋œ ์—ญ์ด ๋‘๊ฐœ ์ดํ•˜์ผ ๋•Œ๋Š” ์—ญ์„ ์ œ๊ฑฐํ•  ์ˆ˜ ์—†๋‹ค. - +- ์ง€ํ•˜์ฒ  ๋…ธ์„ ์— ๊ตฌ๊ฐ„์„ ์‚ญ์ œ, ์ฆ‰ ์ง€ํ•˜์ฒ  ๋…ธ์„  ์•ˆ์—์„œ ํŠน์ • ์—ญ์„ ๋นผ๊ธฐ (pull out subway station in subway line) + - :exclamation: ์˜ˆ์™ธ#8 - ๋…ธ์„ ์— ํฌํ•จ๋œ ์—ญ์„ ์‚ญ์ œํ•˜๋ ค๋Š” ์‹œ์ ์— ๊ทธ ๋…ธ์„ ์— ํฌํ•จ๋œ ์—ญ์ด ๋‘๊ฐœ ์ดํ•˜์ผ ๊ฒฝ์šฐ +- ์ง€ํ•˜์ฒ  ๋…ธ์„  ๊ตฌ๊ฐ„ ์‚ญ์ œ ๊ฐ€๋Šฅ์„ฑ ์—ฌ๋ถ€ ๊ฒ€์‚ฌ (check if the subway station can be pulled out) + - :wrench: ํ•ด๊ฒฐ(์˜ˆ์™ธ #8) - ์‚ญ์ œ ํ›„ ๊ทธ ๋…ธ์„ ์— ํฌํ•จ๋œ ์—ญ์ด ๋‘๊ฐœ ๋ฏธ๋งŒ์ธ์ง€๋ฅผ ๊ฒ€์‚ฌ + +
+ +### ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€ ๊ธฐ๋Šฅ + +- ์ „์ฒด ์ง€ํ•˜์ฒ  ์—ญ, ๋…ธ์„  ๋ชฉ๋ก์„ ํฌํ•จํ•œ ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ์ •๋ณด๋ฅผ ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅ (save subway map info to local storage) +- ์ „์ฒด ์ง€ํ•˜์ฒ  ์—ญ, ๋…ธ์„  ๋ชฉ๋ก์„ ํฌํ•จํ•œ ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ์ •๋ณด๋ฅผ ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์—์„œ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ (load subway map info from local storage) + +
+ +### ์ธํ„ฐํŽ˜์ด์Šค ์ „ํ™˜ ๊ธฐ๋Šฅ + +- ๋ฒ„ํŠผ ํด๋ฆญ์œผ๋กœ ์ธํ„ฐํŽ˜์ด์Šค ์ „ํ™˜ (convert interface with button click) + +### ์ธํ„ฐํŽ˜์ด์Šค ๋ฐ์ดํ„ฐ ๋™๊ธฐํ™” ๊ธฐ๋Šฅ + +- ์ธํ„ฐํŽ˜์ด์Šค์— ์ž…๋ ฅ๋œ ์ •๋ณด ์ €์žฅํ•˜๊ธฐ (save interface data) +- ์ž…๋ ฅ ์ •๋ณด๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ (load interface data) +- ์ž…๋ ฅ ์ •๋ณด๋ฅผ ์ธํ„ฐํŽ˜์ด์Šค์™€ ๋™๊ธฐํ™” ์‹œํ‚ค๊ธฐ(sync interface data to interface) + +### ์—ญ๊ด€๋ฆฌ ์ธํ„ฐํŽ˜์ด์Šค ๊ธฐ๋Šฅ + +- ์—ญ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ์„ ์œ„ํ•œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ์— ๋”ฐ๋ฅธ ์•ˆ๋‚ด๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ (validation check before 'add subway station' with alert message) + - ์ž˜๋ชป๋œ ์ž…๋ ฅ์ด ๋“ค์–ด์™”์„ ๋•Œ, ์—ญ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์—†๋Š” ์ด์œ ๋ฅผ ์•Œ๋ ค์ฃผ์–ด ์žฌ์ž…๋ ฅ์„ ์œ ๋„ +- ์—ญ ์‚ญ์ œ ๊ธฐ๋Šฅ์„ ์œ„ํ•œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ์— ๋”ฐ๋ฅธ ์•ˆ๋‚ด๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ (validation check before 'delete subway station' with alert message) + - ์‚ญ์ œํ•  ์ˆ˜ ์—†๋Š” ์—ญ์„ ์‚ญ์ œํ•˜๋ ค ํ•  ๋•Œ, ์—ญ์„ ์‚ญ์ œํ•  ์ˆ˜ ์—†๋Š” ์ด์œ ๋ฅผ ์•Œ๋ ค์ฃผ์–ด ์žฌ์ž…๋ ฅ์„ ์œ ๋„ +- ์—ญ ์ถ”๊ฐ€ & ์‚ญ์ œ ๊ฒฐ๊ณผ ๋ณด์—ฌ์ฃผ๊ธฐ(show result of add & delete subway station) + +
+ +### ๋…ธ์„ ๊ด€๋ฆฌ ์ธํ„ฐํŽ˜์ด์Šค ๊ธฐ๋Šฅ -### ์ง€ํ•˜์ฒ  ๋…ธ์„ ์— ๋“ฑ๋ก๋œ ์—ญ ์กฐํšŒ ๊ธฐ๋Šฅ -- ๋…ธ์„ ์˜ ์ƒํ–‰ ์ข…์ ๋ถ€ํ„ฐ ํ•˜ํ–‰ ์ข…์ ๊นŒ์ง€ ์—ฐ๊ฒฐ๋œ ์ˆœ์„œ๋Œ€๋กœ ์—ญ ๋ชฉ๋ก์„ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค. +- ๋…ธ์„  ์ถ”๊ฐ€ ๊ธฐ๋Šฅ์„ ์œ„ํ•œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ์— ๋”ฐ๋ฅธ ์•ˆ๋‚ด๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ (validation check before 'add subway line' with alert message) + - ์ž˜๋ชป๋œ ์ž…๋ ฅ์ด ๋“ค์–ด์™”์„ ๋•Œ, ๋…ธ์„ ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์—†๋Š” ์ด์œ ๋ฅผ ์•Œ๋ ค์ฃผ์–ด ์žฌ์ž…๋ ฅ์„ ์œ ๋„ +- ๋…ธ์„  ์ถ”๊ฐ€ & ์‚ญ์ œ ๊ฒฐ๊ณผ ๋ณด์—ฌ์ฃผ๊ธฐ (show result of add & delete subway line)
+### ๊ตฌ๊ฐ„๊ด€๋ฆฌ ์ธํ„ฐํŽ˜์ด์Šค ๊ธฐ๋Šฅ + +- ๊ตฌ๊ฐ„ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ์„ ์œ„ํ•œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ์— ๋”ฐ๋ฅธ ์•ˆ๋‚ด๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ (validation check before 'insert & pull out subway station in subway line' with alert message) + - ๊ตฌ๊ฐ„์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์—†๋Š” ์ด์œ ๋ฅผ ์•Œ๋ ค์ฃผ์–ด ์žฌ์ž…๋ ฅ์„ ์œ ๋„ + - ์—ญ์„ ์‚ญ์ œํ•  ์ˆ˜ ์—†๋Š” ์ด์œ ๋ฅผ ์•Œ๋ ค์ฃผ๋ฉด์„œ ๋…ธ์„  ์ž์ฒด๋ฅผ ์ œ๊ฑฐํ•  ๋ฐฉ๋ฒ•์„ ์•ˆ๋‚ด +- ๊ตฌ๊ฐ„ ์ถ”๊ฐ€ & ์‚ญ์ œ ๊ฒฐ๊ณผ ๋ณด์—ฌ์ฃผ๊ธฐ (show result of insert & pull out subway station) + +
+ +### ๋…ธ์„ ๋„ ์ถœ๋ ฅ ์ธํ„ฐํŽ˜์ด์Šค ๊ธฐ๋Šฅ + +- ์ „์ฒด ์ง€ํ•˜์ฒ  ๋…ธ์„ ์˜ ๋ชฉ๋ก ์กฐํšŒ ๊ธฐ๋Šฅ ํ˜ธ์ถœ & ์กฐํšŒํ•œ ๋…ธ์„ ๋„ ๋ณด์—ฌ์ฃผ๊ธฐ (trigger 'get all subway lines' & show subway map) + +
+ +### ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€ ๋™๊ธฐํ™” + +- ๋‹ซ๊ธฐ, ์ƒˆ๋กœ๊ณ ์นจ ์ „ ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— ์ธํ„ฐํŽ˜์ด์Šค ์ •๋ณด, ๋…ธ์„ ๋„ ์ •๋ณด ์ €์žฅํ•˜๊ธฐ (save interface & subway Map data to local storage before exit or reload) +- ์ ‘์† ์‹œ ์ธํ„ฐํŽ˜์ด์Šค ์ •๋ณด, ๋…ธ์„ ๋„ ์ •๋ณด๋ฅผ ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€๋กœ๋ถ€ํ„ฐ ๋ฐ›์•„ ๋™๊ธฐํ™” ์‹œํ‚ค๊ธฐ (synchronize interface & subway Map data from local storage when user access) + +
+ + + +

+ ## ๐Ÿ’ป ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ๊ฒฐ๊ณผ +
+ ### ์—ญ๊ด€๋ฆฌ + -### ๋…ธ์„ ๊ด€๋ฆฌ - +
-### ๊ตฌ๊ฐ„๊ด€๋ฆฌ - +### ๋…ธ์„ ๊ด€๋ฆฌ -### ๋…ธ์„ ๋„ ์ถœ๋ ฅ - + +
-## โœ… ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์š”๊ตฌ์‚ฌํ•ญ +### ๊ตฌ๊ฐ„๊ด€๋ฆฌ -### ๋ฉ”๋‰ด ๋ฒ„ํŠผ -- ์—ญ ๊ด€๋ฆฌ button ํƒœ๊ทธ๋Š” `#station-manager-button` id๊ฐ’์„ ๊ฐ€์ง„๋‹ค. -- ๋…ธ์„  ๊ด€๋ฆฌ button ํƒœ๊ทธ๋Š” `#line-manager-button` id๊ฐ’์„ ๊ฐ€์ง„๋‹ค. -- ๊ตฌ๊ฐ„ ๊ด€๋ฆฌ button ํƒœ๊ทธ๋Š” `#section-manager-button` id๊ฐ’์„ ๊ฐ€์ง„๋‹ค. -- ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ์ถœ๋ ฅ ๊ด€๋ฆฌ button ํƒœ๊ทธ๋Š” `#map-print-manager-button` id๊ฐ’์„ ๊ฐ€์ง„๋‹ค. + -### ์ง€ํ•˜์ฒ  ์—ญ ๊ด€๋ จ ๊ธฐ๋Šฅ -- ์ง€ํ•˜์ฒ  ์—ญ์„ ์ž…๋ ฅํ•˜๋Š” input ํƒœ๊ทธ๋Š” `#station-name-input` id๊ฐ’์„ ๊ฐ€์ง„๋‹ค. -- ์ง€ํ•˜์ฒ  ์—ญ์„ ์ถ”๊ฐ€ํ•˜๋Š” button ํƒœ๊ทธ๋Š” `#station-add-button` id๊ฐ’์„ ๊ฐ€์ง„๋‹ค. -- ์ง€ํ•˜์ฒ  ์—ญ์„ ์‚ญ์ œํ•˜๋Š” button ํƒœ๊ทธ๋Š” `.station-delete-button` class๊ฐ’์„ ๊ฐ€์ง„๋‹ค. +
-### ์ง€ํ•˜์ฒ  ๋…ธ์„  ๊ด€๋ จ ๊ธฐ๋Šฅ -- ์ง€ํ•˜์ฒ  ๋…ธ์„ ์˜ ์ด๋ฆ„์„ ์ž…๋ ฅํ•˜๋Š” input ํƒœ๊ทธ๋Š” `#line-name-input` id๊ฐ’์„ ๊ฐ€์ง„๋‹ค. -- ์ง€ํ•˜์ฒ  ๋…ธ์„ ์˜ ์ƒํ–‰ ์ข…์ ์„ ์„ ํƒํ•˜๋Š” select ํƒœ๊ทธ๋Š” `#line-start-station-selector` id๊ฐ’์„ ๊ฐ€์ง„๋‹ค. -- ์ง€ํ•˜์ฒ  ๋…ธ์„ ์˜ ํ•˜ํ–‰ ์ข…์ ์„ ์„ ํƒํ•˜๋Š” select ํƒœ๊ทธ๋Š” `#line-end-station-selector` id๊ฐ’์„ ๊ฐ€์ง„๋‹ค. -- ์ง€ํ•˜์ฒ  ๋…ธ์„ ์„ ์ถ”๊ฐ€ํ•˜๋Š” button ํƒœ๊ทธ๋Š” `#line-add-button` id๊ฐ’์„ ๊ฐ€์ง„๋‹ค. -- ์ง€ํ•˜์ฒ  ๋…ธ์„ ์„ ์‚ญ์ œํ•˜๋Š” button ํƒœ๊ทธ๋Š” `.line-delete-button` class๊ฐ’์„ ๊ฐ€์ง„๋‹ค. +### ๋…ธ์„ ๋„ ์ถœ๋ ฅ -### ์ง€ํ•˜์ฒ  ๊ตฌ๊ฐ„ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ -- ์ง€ํ•˜์ฒ  ๋…ธ์„ ์„ ์„ ํƒํ•˜๋Š” button ํƒœ๊ทธ๋Š” `.section-line-menu-button` class๊ฐ’์„ ๊ฐ€์ง„๋‹ค. -- ์ง€ํ•˜์ฒ  ๊ตฌ๊ฐ„์„ ์„ค์ •ํ•  ์—ญ select ํƒœ๊ทธ๋Š” `#section-station-selector` id๊ฐ’์„ ๊ฐ€์ง„๋‹ค. -- ์ง€ํ•˜์ฒ  ๊ตฌ๊ฐ„์˜ ์ˆœ์„œ๋ฅผ ์ž…๋ ฅํ•˜๋Š” input ํƒœ๊ทธ๋Š” `#section-order-input` id๊ฐ’์„ ๊ฐ€์ง„๋‹ค. -- ์ง€ํ•˜์ฒ  ๊ตฌ๊ฐ„์„ ๋“ฑ๋กํ•˜๋Š” button ํƒœ๊ทธ๋Š” `#section-add-button` id๊ฐ’์„ ๊ฐ€์ง„๋‹ค. -- ์ง€ํ•˜์ฒ  ๊ตฌ๊ฐ„์„ ์ œ๊ฑฐํ•˜๋Š” button ํƒœ๊ทธ๋Š” `.section-delete-button` class๊ฐ’์„ ๊ฐ€์ง„๋‹ค. - -### ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ์ถœ๋ ฅ ๊ธฐ๋Šฅ -- ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ์ถœ๋ ฅ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด `
` ํƒœ๊ทธ๋ฅผ ๋งŒ๋“ค๊ณ  ํ•ด๋‹น ํƒœ๊ทธ ๋‚ด๋ถ€์— ๋…ธ์„ ๋„๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค. - -### ๊ธฐ์กด ์š”๊ตฌ์‚ฌํ•ญ - -- ์‚ฌ์šฉ์ž๊ฐ€ ์ž˜๋ชป๋œ ์ž…๋ ฅ ๊ฐ’์„ ์ž‘์„ฑํ•œ ๊ฒฝ์šฐ `alert`์„ ์ด์šฉํ•ด ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด์—ฌ์ฃผ๊ณ , ์žฌ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค. -- ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(jQuery, Lodash ๋“ฑ)๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ , ์ˆœ์ˆ˜ Vanilla JS๋กœ๋งŒ ๊ตฌํ˜„ํ•œ๋‹ค. -- **์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ ์ปจ๋ฒค์…˜์„ ์ง€ํ‚ค๋ฉด์„œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ** ํ•œ๋‹ค - - [https://google.github.io/styleguide/jsguide.html](https://google.github.io/styleguide/jsguide.html) - - [https://ui.toast.com/fe-guide/ko_CODING-CONVENSION/](https://ui.toast.com/fe-guide/ko_CODING-CONVENTION) -- **indent(์ธ๋ดํŠธ, ๋“ค์—ฌ์“ฐ๊ธฐ) depth๋ฅผ 3์ด ๋„˜์ง€ ์•Š๋„๋ก ๊ตฌํ˜„ํ•œ๋‹ค. 2๊นŒ์ง€๋งŒ ํ—ˆ์šฉ**ํ•œ๋‹ค. - - ์˜ˆ๋ฅผ ๋“ค์–ด while๋ฌธ ์•ˆ์— if๋ฌธ์ด ์žˆ์œผ๋ฉด ๋“ค์—ฌ์“ฐ๊ธฐ๋Š” 2์ด๋‹ค. - - ํžŒํŠธ: indent(์ธ๋ดํŠธ, ๋“ค์—ฌ์“ฐ๊ธฐ) depth๋ฅผ ์ค„์ด๋Š” ์ข‹์€ ๋ฐฉ๋ฒ•์€ ํ•จ์ˆ˜(๋˜๋Š” ๋ฉ”์†Œ๋“œ)๋ฅผ ๋ถ„๋ฆฌํ•˜๋ฉด ๋œ๋‹ค. -- **ํ•จ์ˆ˜(๋˜๋Š” ๋ฉ”์†Œ๋“œ)์˜ ๊ธธ์ด๊ฐ€ 15๋ผ์ธ์„ ๋„˜์–ด๊ฐ€์ง€ ์•Š๋„๋ก ๊ตฌํ˜„ํ•œ๋‹ค.** - - ํ•จ์ˆ˜(๋˜๋Š” ๋ฉ”์†Œ๋“œ)๊ฐ€ ํ•œ ๊ฐ€์ง€ ์ผ๋งŒ ์ž˜ ํ•˜๋„๋ก ๊ตฌํ˜„ํ•œ๋‹ค. -- ๋ณ€์ˆ˜ ์„ ์–ธ์‹œ `var` ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค. `const` ์™€ `let` ์„ ์‚ฌ์šฉํ•œ๋‹ค. - - [const](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/const) - - [let](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/let) -- `import` ๋ฌธ์„ ์ด์šฉํ•ด ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋ชจ๋“ˆํ™”ํ•˜๊ณ  ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“ ๋‹ค. - - [https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/import](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/import) -- `template literal`์„ ์ด์šฉํ•ด ๋ฐ์ดํ„ฐ์™€ html string์„ ๊ฐ€๋…์„ฑ ์ข‹๊ฒŒ ํ‘œํ˜„ํ•œ๋‹ค. - - [https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Template_literals](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Template_literals) - -### ์ถ”๊ฐ€๋œ ์š”๊ตฌ์‚ฌํ•ญ -- [data](https://developer.mozilla.org/ko/docs/Learn/HTML/Howto/%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%86%8D%EC%84%B1_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0)์†์„ฑ์„ ํ™œ์šฉํ•˜์—ฌ html ํƒœ๊ทธ์— ์—ญ, ๋…ธ์„ , ๊ตฌ๊ฐ„์˜ ์œ ์ผํ•œ ๋ฐ์ดํ„ฐ ๊ฐ’๋“ค์„ ๊ด€๋ฆฌํ•œ๋‹ค. -- [localStorage](https://developer.mozilla.org/ko/docs/Web/API/Window/localStorage)๋ฅผ ์ด์šฉํ•˜์—ฌ, ์ƒˆ๋กœ๊ณ ์นจํ•˜๋”๋ผ๋„ ๊ฐ€์žฅ ์ตœ๊ทผ์— ์ž‘์—…ํ•œ ์ •๋ณด๋“ค์„ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค. - -
- -## ๐Ÿ“ ๋ฏธ์…˜ ์ €์žฅ์†Œ ๋ฐ ์ง„ํ–‰ ์š”๊ตฌ์‚ฌํ•ญ - -- ๋ฏธ์…˜์€ [https://github.com/woowacourse/javascript-subway-map-precours](https://github.com/woowacourse/javascript-subway-map-precourse) ์ €์žฅ์†Œ๋ฅผ fork/cloneํ•ด ์‹œ์ž‘ํ•œ๋‹ค. -- **๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์ „์— javascript-subway-precourse/docs/README.md ํŒŒ์ผ์— ๊ตฌํ˜„ํ•  ๊ธฐ๋Šฅ ๋ชฉ๋ก**์„ ์ •๋ฆฌํ•ด ์ถ”๊ฐ€ํ•œ๋‹ค. -- **git์˜ commit ๋‹จ์œ„๋Š” ์•ž ๋‹จ๊ณ„์—์„œ README.md ํŒŒ์ผ์— ์ •๋ฆฌํ•œ ๊ธฐ๋Šฅ ๋ชฉ๋ก ๋‹จ์œ„๋กœ ์ถ”๊ฐ€**ํ•œ๋‹ค. -- [ํ”„๋ฆฌ์ฝ”์Šค ๊ณผ์ œ ์ œ์ถœ](https://github.com/woowacourse/woowacourse-docs/tree/master/precourse) ๋ฌธ์„œ ์ ˆ์ฐจ๋ฅผ ๋”ฐ๋ผ ๋ฏธ์…˜์„ ์ œ์ถœํ•œ๋‹ค. + diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 000000000..14906bb61 --- /dev/null +++ b/babel.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: [ + '@babel/plugin-proposal-private-methods', + '@babel/plugin-proposal-class-properties', + ], +}; diff --git a/index.css b/index.css new file mode 100644 index 000000000..432019fe9 --- /dev/null +++ b/index.css @@ -0,0 +1,11 @@ +.content { + display: none; +} + +#station-register { + display: none; +} + +#registered-station-item-table { + display: none; +} diff --git a/index.html b/index.html index fc99deac2..24eb6c15b 100644 --- a/index.html +++ b/index.html @@ -3,10 +3,87 @@ ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ๊ด€๋ฆฌ +
-

๐Ÿš‡ ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ๊ด€๋ฆฌ

+

๐Ÿš‡ ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ๊ด€๋ฆฌ

+
+
+ + + + +
+
+
+

์—ญ ์ด๋ฆ„

+ + +
+
+

🚉์ง€ํ•˜์ฒ  ์—ญ ๋ชฉ๋ก

+ + + + + + + +
์—ญ ์ด๋ฆ„์„ค์ •
+
+
+
+
+

๋…ธ์„  ์ด๋ฆ„

+ +
+
+ ์ƒํ–‰ ์ข…์  + + ํ•˜ํ–‰ ์ข…์  + +
+ +
+

🚉์ง€ํ•˜์ฒ  ๋…ธ์„  ๋ชฉ๋ก

+ + + + + + + + + + +
๋…ธ์„  ์ด๋ฆ„์ƒํ–‰ ์ข…์ ์—ญํ•˜ํ–‰ ์ข…์ ์—ญ์„ค์ •
+
+
+
+

๊ตฌ๊ฐ„์„ ์ˆ˜์ •ํ•  ๋…ธ์„ ์„ ์„ ํƒํ•ด์ฃผ์„ธ์š”

+
+
+
+

1ํ˜ธ์„  ๊ด€๋ฆฌ

+

๊ตฌ๊ฐ„ ๋“ฑ๋ก

+ + + +
+ + + + + + + + + +
์ˆœ์„œ์ด๋ฆ„์„ค์ •
+
+
+
diff --git a/src/classes/classes.test.js b/src/classes/classes.test.js new file mode 100644 index 000000000..eed3f5944 --- /dev/null +++ b/src/classes/classes.test.js @@ -0,0 +1,81 @@ +import SubWayStation from './subwayStation.js'; +import SubwayLine from './subwayLine.js'; +import SubwayMap from './subwayMap.js'; + +describe('SubWayStation', () => { + const station1Name = 'station1'; + const station2Name = 'station2'; + const station3Name = 'station3'; + const station1 = new SubWayStation(); + const station2 = new SubWayStation(); + const station3 = new SubWayStation(); + const subwayMap = new SubwayMap(); + subwayMap.addStation(station1, station1Name); + subwayMap.addStation(station2, station2Name); + subwayMap.addStation(station3, station3Name); + it('add subway station', () => { + expect(subwayMap.allStations).toHaveProperty(station1Name); + expect(subwayMap.allStations).toHaveProperty(station2Name); + expect(subwayMap.allStations).toHaveProperty(station3Name); + }); + it('delete subway station', () => { + subwayMap.deleteStationByName(station3Name); + expect(subwayMap.allStations).toHaveProperty(station1Name); + expect(subwayMap.allStations).toHaveProperty(station2Name); + expect(subwayMap.allStations).not.toHaveProperty(station3Name); + }); +}); + +describe('SubwayLine', () => { + const station1Name = 'station1'; + const station2Name = 'station2'; + const station3Name = 'station3'; + const station1 = new SubWayStation(); + const station2 = new SubWayStation(); + const station3 = new SubWayStation(); + const subwayMap = new SubwayMap(); + subwayMap.addStation(station1, station1Name); + subwayMap.addStation(station2, station2Name); + subwayMap.addStation(station3, station3Name); + const line1 = new SubwayLine(station1Name, station2Name); + const line2 = new SubwayLine(station2Name, station3Name); + const line1Name = 'line1'; + const line2Name = 'line2'; + subwayMap.addLine(line1, line1Name); + subwayMap.addLine(line2, line2Name); + it('add subway line', () => { + expect(subwayMap.allLines).toHaveProperty(line1Name); + expect(subwayMap.allLines).toHaveProperty(line2Name); + }); + it('delete subway line', () => { + subwayMap.deleteLineByName(line2Name); + expect(subwayMap.allLines).toHaveProperty(line1Name); + expect(subwayMap.allLines).not.toHaveProperty(line2Name); + }); + it('add station to line', () => { + line1.addStationToLineByName(station3Name); + expect(line1.allStationsInLine).toContain(station3Name); + }); +}); + +describe('SubwaySection', () => { + const station1Name = 'station1'; + const station2Name = 'station2'; + const station3Name = 'station3'; + const station1 = new SubWayStation(); + const station2 = new SubWayStation(); + const station3 = new SubWayStation(); + const subwayMap = new SubwayMap(); + subwayMap.addStation(station1, station1Name); + subwayMap.addStation(station2, station2Name); + subwayMap.addStation(station3, station3Name); + const line1 = new SubwayLine(station1Name, station2Name); + it('insert subway station in subway line', () => { + line1.insertStationToLineByNameAndIndex(station3Name, 1); + expect(line1.allStationsInLine).toContain(station3Name); + }); + it('pull out subway station in subway line', () => { + line1.pullOutStationFromLineByName(station3Name); + expect(line1.allStationsInLine).not.toContain(station3Name); + }); +}); diff --git a/src/classes/subwayLine.js b/src/classes/subwayLine.js new file mode 100644 index 000000000..ba031aedb --- /dev/null +++ b/src/classes/subwayLine.js @@ -0,0 +1,45 @@ +import { SUBWAY_STATION_IN_LINE_DELETE_LENGTH_LIMIT } from '../constants/configuration.js'; + +export default class SubwayLine { + allStationsInLine = []; + + static checkIsStationsSame(startStationName, endStationName) { + return startStationName === endStationName; + } + + static checkIsIndexNumberCorrect(index) { + return typeof index === 'number' && Number.isNaN(index) === false; + } + + constructor(startStationName, endStationName) { + this.allStationsInLine.push(startStationName); + this.allStationsInLine.push(endStationName); + } + + addStationToLineByName(stationName) { + if (stationName in this.allStationsInLine === false) { + this.allStationsInLine.push(stationName); + } + } + + insertStationToLineByNameAndIndex({ stationName, index }) { + if (stationName in this.allStationsInLine === false) { + this.allStationsInLine.splice(index, 0, stationName); + } + } + + pullOutStationFromLineByIndex(stationIndex) { + return this.allStationsInLine.splice(stationIndex, 1); + } + + checkIsStationNameExistInLine(stationName) { + return this.allStationsInLine.includes(stationName); + } + + checkIsAllStationsInLineLengthSameAsLimit() { + return ( + this.allStationsInLine.length <= + SUBWAY_STATION_IN_LINE_DELETE_LENGTH_LIMIT + ); + } +} diff --git a/src/classes/subwayMap.js b/src/classes/subwayMap.js new file mode 100644 index 000000000..d0e8d2911 --- /dev/null +++ b/src/classes/subwayMap.js @@ -0,0 +1,44 @@ +export default class SubwayMap { + #allStations = {}; + #allLines = {}; + + get allStations() { + return this.#allStations; + } + + get allLines() { + return this.#allLines; + } + + addStation(station, stationName) { + if (stationName in this.#allStations === false) { + this.#allStations[stationName] = station; + } + } + + checkIsStationNameExist(stationName) { + return stationName in this.#allStations; + } + + deleteStationByName(stationName) { + if (stationName in this.#allStations) { + delete this.#allStations[stationName]; + } + } + + addLine(line, lineName) { + if (lineName in this.#allLines === false) { + this.#allLines[lineName] = line; + } + } + + checkIsLineNameExist(lineName) { + return lineName in this.#allLines; + } + + deleteLineByName(lineName) { + if (lineName in this.#allLines) { + delete this.#allLines[lineName]; + } + } +} diff --git a/src/classes/subwayStation.js b/src/classes/subwayStation.js new file mode 100644 index 000000000..43399e306 --- /dev/null +++ b/src/classes/subwayStation.js @@ -0,0 +1,24 @@ +import { SUBWAY_STATION_NAME_LENGTH_LIMIT } from '../constants/configuration.js'; + +export default class SubwayStation { + static checkIsStationNameShort(stationName) { + return stationName.length < SUBWAY_STATION_NAME_LENGTH_LIMIT; + } + + static checkIsStationBelongToLine(station) { + return station.belongingLineNames.length > 0; + } + + constructor() { + this.belongingLineNames = []; + } + + addBeloningLineByLineName(lineName) { + this.belongingLineNames.push(lineName); + } + + deleteBeloningLineByLineName(lineName) { + const deleteLineIndex = this.belongingLineNames.indexOf(lineName); + this.belongingLineNames.splice(deleteLineIndex, 1); + } +} diff --git a/src/constants/configuration.js b/src/constants/configuration.js new file mode 100644 index 000000000..966ae8585 --- /dev/null +++ b/src/constants/configuration.js @@ -0,0 +1,29 @@ +export const SUBWAY_STATION_NAME_LENGTH_LIMIT = 2; +export const SUBWAY_STATION_IN_LINE_DELETE_LENGTH_LIMIT = 2; +export const SUBWAY_MAP_ITEM_NAME = 'Subway-Map'; +export const INTERFACE_DATA_ITEM_NAME = 'Data'; +export const SHORT_STATION_NAME_ALERT_MESSAGE = + '์—ญ์˜ ์ด๋ฆ„์ด ๋„ˆ๋ฌด ์งง์Šต๋‹ˆ๋‹ค. 2๊ธ€์ž ์ด์ƒ์˜ ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”'; +export const SAME_STATION_NAME_EXIST_MESSAGE = + '์ด๋ฏธ ๋™์ผํ•œ ์ด๋ฆ„์˜ ์—ญ์ด ๋“ฑ๋ก๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”'; +export const STATION_REGISTERED_IN_LINE_MESSAGE = + '์ด ์—ญ์€ ๋…ธ์„ ์˜ ๊ตฌ๊ฐ„์œผ๋กœ ๋“ฑ๋ก๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ญ์ œ๋ฅผ ์›ํ•˜์‹ ๋‹ค๋ฉด ํ•ด๋‹น ๋…ธ์„  ๊ตฌ๊ฐ„์—์„œ ์—ญ์„ ๋นผ์ฃผ์„ธ์š”.'; +export const SAME_LINE_NAME_EXIST_MESSAGE = + '์ด๋ฏธ ๋™์ผํ•œ ์ด๋ฆ„์˜ ๋…ธ์„ ์ด ๋“ฑ๋ก๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”'; +export const END_AND_START_STATION_NAME_SAME_MESSAGE = + '์ƒํ–‰ ์ข…์ ์—ญ๊ณผ ํ•˜ํ–‰ ์ข…์ ์—ญ์ด ๊ฐ™์Šต๋‹ˆ๋‹ค. ์„œ๋กœ ๋‹ค๋ฅธ ์ข…์ ์—ญ๋“ค์„ ์„ ํƒํ•ด์ฃผ์„ธ์š”.'; +export const SAME_STATION_REGISTER_TRY_MESSAGE = + '์ด ์—ญ์€ ์ด๋ฏธ ๋…ธ์„ ์˜ ์ด ๋…ธ์„ ์— ๋“ฑ๋ก๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์—ญ์„ ์„ ํƒํ•ด์ฃผ์„ธ์š”'; +export const LESS_THAN_DELETE_LENGTH_LIMIT_MESSAGE = `์ด ์—ญ์„ ๋นผ๋ฉด ๋…ธ์„ ์˜ ๊ฐœ์ˆ˜๊ฐ€ ${SUBWAY_STATION_IN_LINE_DELETE_LENGTH_LIMIT}๊ฐœ ์ดํ•˜๊ฐ€ ๋˜๋ฏ€๋กœ ๋บ„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค`; +export const INDEX_IS_NOT_NUMBER_MESSAGE = '์ˆœ์„œ๋กœ ๋„ฃ์€ ๊ฐ’์ด ์ˆซ์ž๋กœ ๋ณด์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”' + +export default { + SUBWAY_STATION_NAME_LENGTH_LIMIT, + SUBWAY_STATION_IN_LINE_DELETE_LENGTH_LIMIT, + SUBWAY_MAP_ITEM_NAME, + SAME_LINE_NAME_EXIST_MESSAGE, + END_AND_START_STATION_NAME_SAME_MESSAGE, + SAME_STATION_REGISTER_TRY_MESSAGE, + LESS_THAN_DELETE_LENGTH_LIMIT_MESSAGE, + INDEX_IS_NOT_NUMBER_MESSAGE +}; diff --git a/src/data/data.js b/src/data/data.js new file mode 100644 index 000000000..dfaef22d0 --- /dev/null +++ b/src/data/data.js @@ -0,0 +1,69 @@ +import { setItemWithKey, getItemByKey } from '../utils/localStorage.js'; +import { stationNameInputElement } from '../elements/stationManager.js'; +import { + lineEndStationSelectorElement, + lineStartStationSelectorElement, + lineNameInputElement, +} from '../elements/lineManager.js'; +import { + sectionOrderInputElement, + sectionStationSelectorElement, + sectionLineNameElement, +} from '../elements/sectionManager.js'; +import { INTERFACE_DATA_ITEM_NAME } from '../constants/configuration.js'; + +const data = { + stationNameInputValue: '', + lineNameInputValue: '', + lineStartStationSelectorValue: '', + lineEndStationSelectorValue: '', + sectionLineNameValue: '', + sectionStationSelectorValue: '', + sectionOrderInputNumberValue: '', +}; + +export const syncDataToLocalStorage = () => { + setItemWithKey(data, INTERFACE_DATA_ITEM_NAME); +}; + +export const loadDataToLocalStorage = () => { + const loadedData = getItemByKey(INTERFACE_DATA_ITEM_NAME); + if (loadedData) { + data.stationNameInputValue = loadedData.stationNameInputValue; + data.lineNameInputValue = loadedData.lineNameInputValue; + data.upTerminatingStationNameValue = + loadedData.upTerminatingStationNameValue; + data.downTerminatingStationNameValue = + loadedData.downTerminatingStationNameValue; + data.sectionLineValue = loadedData.sectionLineValue; + data.sectionStationSelectorValue = loadedData.sectionStationSelectorValue; + data.sectionOrderInputNumberValue = loadedData.sectionOrderInputNumberValue; + } +}; + +export const syncDataFromAllElements = () => { + data.stationNameInputValue = stationNameInputElement.value; + data.lineNameInputValue = lineNameInputElement.value; + data.lineStartStationSelectorValue = lineStartStationSelectorElement.value; + data.lineEndStationSelectorValue = lineEndStationSelectorElement.value; + data.sectionOrderInputNumberValue = sectionOrderInputElement.value; + data.sectionLineNameValue = sectionLineNameElement.value; + data.sectionStationSelectorValue = sectionStationSelectorElement.value; +}; + +export const syncDataToAllElements = () => { + stationNameInputElement.value = data.stationNameInputValue; + lineNameInputElement.value = data.lineNameInputValue; + lineStartStationSelectorElement.value = data.lineStartStationSelectorValue; + lineEndStationSelectorElement.value = data.lineEndStationSelectorValue; + sectionOrderInputElement.value = data.sectionOrderInputNumberValue; + sectionLineNameElement.value = data.sectionLineNameValue; + sectionStationSelectorElement.value = data.sectionStationSelectorValue; +}; + +export default { + syncDataToLocalStorage, + loadDataToLocalStorage, + syncDataFromAllElements, + syncDataToAllElements, +}; diff --git a/src/elements/contentConvertButtons.js b/src/elements/contentConvertButtons.js new file mode 100644 index 000000000..972fa947f --- /dev/null +++ b/src/elements/contentConvertButtons.js @@ -0,0 +1,17 @@ +export const lineManagerButtonElement = document.getElementById( + 'line-manager-button' +); + +export const sectionManagerButtonElement = document.getElementById( + 'section-manager-button' +); + +export const mapPrintManagerButtonElement = document.getElementById( + 'map-print-manager-button' +); + +export default { + lineManagerButtonElement, + sectionManagerButtonElement, + mapPrintManagerButtonElement, +}; diff --git a/src/elements/contents.js b/src/elements/contents.js new file mode 100644 index 000000000..c7f394331 --- /dev/null +++ b/src/elements/contents.js @@ -0,0 +1,5 @@ +export const contentElements = document.querySelectorAll('.content'); + +export default { + contentElements, +}; diff --git a/src/elements/lineManager.js b/src/elements/lineManager.js new file mode 100644 index 000000000..d2d1a7311 --- /dev/null +++ b/src/elements/lineManager.js @@ -0,0 +1,23 @@ +export const lineNameInputElement = document.getElementById('line-name-input'); +export const lineStartStationSelectorElement = document.getElementById( + 'line-start-station-selector' +); +export const lineEndStationSelectorElement = document.getElementById( + 'line-end-station-selector' +); +export const lineAddButtonElement = document.getElementById('line-add-button'); +export const lineDeleteButtonElements = document.querySelectorAll( + '.line-delete-button' +); +export const resultLineItemsElement = document.getElementById( + 'result-line-items' +); + +export default { + lineNameInputElement, + lineStartStationSelectorElement, + lineEndStationSelectorElement, + lineAddButtonElement, + lineDeleteButtonElements, + resultLineItemsElement, +}; diff --git a/src/elements/mapPrint.js b/src/elements/mapPrint.js new file mode 100644 index 000000000..4931c5570 --- /dev/null +++ b/src/elements/mapPrint.js @@ -0,0 +1,5 @@ +export const mapPrintWrapperElement = document.getElementById('map-print'); + +export default { + mapPrintWrapperElement +} \ No newline at end of file diff --git a/src/elements/sectionManager.js b/src/elements/sectionManager.js new file mode 100644 index 000000000..2c78d13cd --- /dev/null +++ b/src/elements/sectionManager.js @@ -0,0 +1,39 @@ +export const sectionLineMenuButtonListElement = document.getElementById( + 'section-line-menu-button-list' +); +export const sectionLineNameElement = document.getElementById( + 'section-line-name' +); +export const stationRegisterWrapperElement = document.getElementById( + 'station-register' +); +export const registeredStationItemTableElement = document.getElementById( + 'registered-station-item-table' +); +export const registeredStationItemsElement = document.getElementById( + 'registered-station-items' +); +export const sectionStationSelectorElement = document.getElementById( + 'section-station-selector' +); +export const sectionOrderInputElement = document.getElementById( + 'section-order-input' +); +export const sectionAddButtonElement = document.getElementById( + 'section-add-button' +); +export const sectionDeleteButtonElements = document.querySelectorAll( + '.section-delete-button' +); + +export default { + sectionLineMenuButtonListElement, + sectionLineNameElement, + sectionStationSelectorElement, + registeredStationItemTableElement, + registeredStationItemsElement, + sectionOrderInputElement, + sectionAddButtonElement, + sectionDeleteButtonElements, + stationRegisterWrapperElement, +}; diff --git a/src/elements/stationManager.js b/src/elements/stationManager.js new file mode 100644 index 000000000..4e504dcd8 --- /dev/null +++ b/src/elements/stationManager.js @@ -0,0 +1,16 @@ +export const stationNameInputElement = document.getElementById( + 'station-name-input' +); +export const stationAddButtonElement = document.getElementById( + 'station-add-button' +); +export const stationDeleteButtonsElement = document.querySelectorAll( + '.station-delete-button' +); +export const resultStationItemsElement = document.getElementById('result-station-items'); + +export default { + stationNameInputElement, + stationAddButtonElement, + stationDeleteButtonsElement, +}; diff --git a/src/handlers/lineManager.js b/src/handlers/lineManager.js new file mode 100644 index 000000000..ca76a9466 --- /dev/null +++ b/src/handlers/lineManager.js @@ -0,0 +1,103 @@ +import { + lineNameInputElement, + lineStartStationSelectorElement, + lineEndStationSelectorElement, + resultLineItemsElement, +} from '../elements/lineManager.js'; +import { subwayMap } from '../store/store.js'; +import SubwayLine from '../classes/subwayLine.js'; +import { + SAME_LINE_NAME_EXIST_MESSAGE, + END_AND_START_STATION_NAME_SAME_MESSAGE, +} from '../constants/configuration.js'; +import { getTableRowsTemplate } from '../templates/table.js'; +import { getSelectorOptionsTemplate } from '../templates/selector.js'; + +const getAddLineAlertMessage = ({ + lineName, + startStationName, + endStationName, +}) => { + let alertMessage = ''; + if (subwayMap.checkIsLineNameExist(lineName)) { + alertMessage += `${SAME_LINE_NAME_EXIST_MESSAGE}\n`; + } + if (SubwayLine.checkIsStationsSame(startStationName, endStationName)) { + alertMessage += END_AND_START_STATION_NAME_SAME_MESSAGE; + } + + return alertMessage; +}; + +export const showLineManagerResultTable = () => { + const lineTableRows = []; + const allLineNames = Object.keys(subwayMap.allLines); + allLineNames.forEach((lineName) => { + const line = subwayMap.allLines[lineName]; + const lineStartStation = line.allStationsInLine[0]; + const lineEndStationIndex = line.allStationsInLine.length - 1; + const lineEndStation = line.allStationsInLine[lineEndStationIndex]; + console.log(lineStartStation, lineEndStation); + const lineTableRow = [lineName, lineStartStation, lineEndStation]; + lineTableRows.push(lineTableRow); + }); + const deleteTargetCellIndex = 0; + const deleteButtonClass = 'line-delete-button'; + resultLineItemsElement.innerHTML = getTableRowsTemplate({ + rows: lineTableRows, + deleteTargetCellIndex, + deleteButtonClass, + }); +}; + +export const onConverToLineContent = () => { + const allStationNames = Object.keys(subwayMap.allStations); + lineStartStationSelectorElement.innerHTML = getSelectorOptionsTemplate( + allStationNames + ); + lineEndStationSelectorElement.innerHTML = getSelectorOptionsTemplate( + allStationNames + ); +}; + +export const onAddLine = () => { + const lineName = lineNameInputElement.value; + const startStationName = lineStartStationSelectorElement.value; + const endStationName = lineEndStationSelectorElement.value; + subwayMap.allStations[startStationName].addBeloningLineByLineName(lineName); + subwayMap.allStations[endStationName].addBeloningLineByLineName(lineName); + const line = new SubwayLine(startStationName, endStationName); + const alertMessage = getAddLineAlertMessage({ + lineName, + startStationName, + endStationName, + }); + if (alertMessage === '') { + subwayMap.addLine(line, lineName); + showLineManagerResultTable(); + } else { + alert(alertMessage); + } +}; + +export const onDeleteLine = (event) => { + const targetElement = event.target; + if (targetElement.className !== 'line-delete-button') { + return; + } + const deleteTargetName = targetElement.dataset.deleteTarget; + const targetLine = subwayMap.allLines[deleteTargetName]; + targetLine.allStationsInLine.forEach((stationName) => { + const station = subwayMap.allStations[stationName]; + station.deleteBeloningLineByLineName(deleteTargetName); + }); + subwayMap.deleteLineByName(deleteTargetName); + showLineManagerResultTable(); +}; + +export default { + onAddLine, + onConverToLineContent, + onDeleteLine, + showLineManagerResultTable, +}; diff --git a/src/handlers/mapPrint.js b/src/handlers/mapPrint.js new file mode 100644 index 000000000..6a9583516 --- /dev/null +++ b/src/handlers/mapPrint.js @@ -0,0 +1,11 @@ +import { mapPrintWrapperElement } from '../elements/mapPrint.js'; +import { getSubwayMapTemplate } from '../templates/list.js'; +import { subwayMap } from '../store/store.js'; + +export const printMap = () => { + mapPrintWrapperElement.innerHTML = getSubwayMapTemplate(subwayMap.allLines); +}; + +export default { + printMap, +}; diff --git a/src/handlers/sectionManager.js b/src/handlers/sectionManager.js new file mode 100644 index 000000000..2fae8fce9 --- /dev/null +++ b/src/handlers/sectionManager.js @@ -0,0 +1,127 @@ +import { + sectionLineMenuButtonListElement, + sectionStationSelectorElement, + sectionLineNameElement, + stationRegisterWrapperElement, + registeredStationItemTableElement, + registeredStationItemsElement, + sectionOrderInputElement, +} from '../elements/sectionManager.js'; +import { subwayMap } from '../store/store.js'; +import { + SAME_STATION_REGISTER_TRY_MESSAGE, + LESS_THAN_DELETE_LENGTH_LIMIT_MESSAGE, + INDEX_IS_NOT_NUMBER_MESSAGE, +} from '../constants/configuration.js'; +import { getTableRowsTemplate } from '../templates/table.js'; +import { getSelectorOptionsTemplate } from '../templates/selector.js'; +import { getSectionLineMenuButtonsTemplate } from '../templates/button.js'; +import SubwayLine from '../classes/subwayLine.js'; + +const getInsertStationAlertMessage = ({ line, stationName, index }) => { + let alertMessage = ''; + if (line.checkIsStationNameExistInLine(stationName)) { + alertMessage += `${SAME_STATION_REGISTER_TRY_MESSAGE}\n`; + } + if (SubwayLine.checkIsIndexNumberCorrect(index) === false) { + alertMessage += INDEX_IS_NOT_NUMBER_MESSAGE; + } + + return alertMessage; +}; + +const getPullOutStationAlertMessage = (line) => { + let alertMessage = ''; + if (line.checkIsAllStationsInLineLengthSameAsLimit()) { + alertMessage += LESS_THAN_DELETE_LENGTH_LIMIT_MESSAGE; + } + + return alertMessage; +}; + +export const showSectionManagerResultTable = () => { + const lineName = sectionLineNameElement.innerText; + const line = subwayMap.allLines[lineName]; + if (line) { + const stationInLineRows = []; + line.allStationsInLine.forEach((stationName, index) => { + stationInLineRows.push([index, stationName]); + }); + registeredStationItemsElement.innerHTML = getTableRowsTemplate({ + rows: stationInLineRows, + deleteTargetCellIndex: 0, + deleteButtonClass: 'section-delete-button', + deleteButtonText: '๋…ธ์„ ์—์„œ ์ œ๊ฑฐ', + }); + } +}; + +export const onClickSectionLineButton = (event) => { + const targetElement = event.target; + if (targetElement.className === 'section-line-menu-button') { + const lineName = targetElement.innerText; + sectionLineNameElement.innerText = lineName; + stationRegisterWrapperElement.setAttribute('style', 'display: block;'); + registeredStationItemTableElement.setAttribute('style', 'display: block;'); + showSectionManagerResultTable(); + } +}; + +export const onConverToSectionContent = () => { + const allLineNames = Object.keys(subwayMap.allLines); + const allStationNames = Object.keys(subwayMap.allStations); + sectionLineMenuButtonListElement.innerHTML = getSectionLineMenuButtonsTemplate( + allLineNames + ); + sectionStationSelectorElement.innerHTML = getSelectorOptionsTemplate( + allStationNames + ); +}; + +export const onInsertStation = () => { + const lineName = sectionLineNameElement.innerText; + const stationName = sectionStationSelectorElement.value; + const index = Number(sectionOrderInputElement.value); + const line = subwayMap.allLines[lineName]; + const alertMessage = getInsertStationAlertMessage({ + line, + stationName, + index, + }); + if (alertMessage === '') { + const insertingStation = subwayMap.allStations[stationName]; + insertingStation.addBeloningLineByLineName(lineName); + line.insertStationToLineByNameAndIndex({ stationName, index }); + showSectionManagerResultTable(line.allStationsInLine); + } else { + alert(alertMessage); + } +}; + +export const onPullOutStation = (event) => { + const targetElement = event.target; + if (targetElement.className !== 'section-delete-button') { + return; + } + const lineName = sectionLineNameElement.innerText; + const targetIndex = targetElement.dataset.deleteTarget; + const line = subwayMap.allLines[lineName]; + const alertMessage = getPullOutStationAlertMessage(line); + if (alertMessage === '') { + const pulledOutStationName = line.pullOutStationFromLineByIndex( + targetIndex + ); + const pulledOutStation = subwayMap.allStations[pulledOutStationName]; + pulledOutStation.deleteBeloningLineByLineName(lineName); + showSectionManagerResultTable(line.allStationsInLine); + } else { + alert(alertMessage); + } +}; + +export default { + onInsertStation, + onConverToSectionContent, + onClickSectionLineButton, + showSectionManagerResultTable, +}; diff --git a/src/handlers/stationManager.js b/src/handlers/stationManager.js new file mode 100644 index 000000000..5878475e7 --- /dev/null +++ b/src/handlers/stationManager.js @@ -0,0 +1,79 @@ +import { + stationNameInputElement, + resultStationItemsElement, +} from '../elements/stationManager.js'; +import SubwayStation from '../classes/subwayStation.js'; +import { subwayMap } from '../store/store.js'; +import { + SAME_STATION_NAME_EXIST_MESSAGE, + SHORT_STATION_NAME_ALERT_MESSAGE, + STATION_REGISTERED_IN_LINE_MESSAGE, +} from '../constants/configuration.js'; +import { getTableRowsTemplate } from '../templates/table.js'; + +const getAddStationAlertMessage = (stationName) => { + let alertMessage = ''; + if (subwayMap.checkIsStationNameExist(stationName)) { + alertMessage += `${SAME_STATION_NAME_EXIST_MESSAGE}\n`; + } + if (SubwayStation.checkIsStationNameShort(stationName)) { + alertMessage += SHORT_STATION_NAME_ALERT_MESSAGE; + } + + return alertMessage; +}; + +const getDeleteStationAlertMessage = (stationName) => { + let alertMessage = ''; + const station = subwayMap.allStations[stationName]; + if (SubwayStation.checkIsStationBelongToLine(station)) { + alertMessage += STATION_REGISTERED_IN_LINE_MESSAGE; + } + + return alertMessage; +}; + +export const showStationManagerResultTable = () => { + const registerdStationNames = Object.keys(subwayMap.allStations); + const resultRows = registerdStationNames.map((stationName) => [stationName]); + const deleteTargetCellIndex = 0; + const deleteButtonClass = 'station-delete-button'; + resultStationItemsElement.innerHTML = getTableRowsTemplate({ + rows: resultRows, + deleteTargetCellIndex, + deleteButtonClass, + }); +}; + +export const onAddStation = () => { + const stationName = stationNameInputElement.value; + const alertMessage = getAddStationAlertMessage(stationName); + if (alertMessage === '') { + const station = new SubwayStation(); + subwayMap.addStation(station, stationName); + showStationManagerResultTable(); + stationNameInputElement.value = ''; + } else { + alert(alertMessage); + } +}; + +export const onDeleteStation = (event) => { + const targetElement = event.target; + if (targetElement.className !== 'station-delete-button') { + return; + } + const deleteTargetName = targetElement.dataset.deleteTarget; + const alertMessage = getDeleteStationAlertMessage(deleteTargetName); + if (alertMessage === '') { + subwayMap.deleteStationByName(deleteTargetName); + showStationManagerResultTable(); + } else { + alert(alertMessage); + } +}; + +export default { + onAddStation, + showStationManagerResultTable +}; diff --git a/src/index.js b/src/index.js index e69de29bb..5e62e7185 100644 --- a/src/index.js +++ b/src/index.js @@ -0,0 +1,19 @@ +import { setRouterWithElements } from './routes/routes.js'; +import { contentElements } from './elements/contents.js'; +import { + addLineMangerEventListeners, + addMapPrintEventListeners, + addSectionManagerEventListeners, + addStationManagerEventListeners, + addSyncDataBeforeOnloadEventListener, + addSyncDataBeforeUnloadEventListener, +} from './listeners/listeners.js'; + +setRouterWithElements(contentElements); + +addLineMangerEventListeners(); +addMapPrintEventListeners(); +addSectionManagerEventListeners(); +addStationManagerEventListeners(); +addSyncDataBeforeOnloadEventListener(contentElements, contentElements[0]); +addSyncDataBeforeUnloadEventListener(); diff --git a/src/listeners/listeners.js b/src/listeners/listeners.js new file mode 100644 index 000000000..c1e3f2d51 --- /dev/null +++ b/src/listeners/listeners.js @@ -0,0 +1,112 @@ +import { + stationAddButtonElement, + resultStationItemsElement, +} from '../elements/stationManager.js'; +import { + lineAddButtonElement, + resultLineItemsElement, +} from '../elements/lineManager.js'; +import { + sectionLineMenuButtonListElement, + sectionAddButtonElement, + registeredStationItemsElement, +} from '../elements/sectionManager.js'; +import { + lineManagerButtonElement, + sectionManagerButtonElement, + mapPrintManagerButtonElement, +} from '../elements/contentConvertButtons.js'; + +import { + onAddStation, + onDeleteStation, + showStationManagerResultTable, +} from '../handlers/stationManager.js'; +import { + onAddLine, + onConverToLineContent, + onDeleteLine, + showLineManagerResultTable, +} from '../handlers/lineManager.js'; +import { + onConverToSectionContent, + onClickSectionLineButton, + onInsertStation, + onPullOutStation, + showSectionManagerResultTable, +} from '../handlers/sectionManager.js'; +import { printMap } from '../handlers/mapPrint.js'; +import { convertContent } from '../routes/routes.js'; +import { + loadDataToLocalStorage, + syncDataToAllElements, + syncDataToLocalStorage, + syncDataFromAllElements, +} from '../data/data.js'; +import { + syncSubwayMapFromLocalStorage, + syncSubwayMapToLocalStorage, +} from '../store/store.js'; + +export const addStationManagerEventListeners = () => { + stationAddButtonElement.addEventListener('click', onAddStation); + resultStationItemsElement.addEventListener('click', onDeleteStation); +}; + +export const addLineMangerEventListeners = () => { + lineAddButtonElement.addEventListener('click', onAddLine); + lineManagerButtonElement.addEventListener('click', onConverToLineContent); + resultLineItemsElement.addEventListener('click', onDeleteLine); +}; + +export const addSectionManagerEventListeners = () => { + sectionManagerButtonElement.addEventListener( + 'click', + onConverToSectionContent + ); + sectionLineMenuButtonListElement.addEventListener( + 'click', + onClickSectionLineButton + ); + sectionAddButtonElement.addEventListener('click', onInsertStation); + registeredStationItemsElement.addEventListener('click', onPullOutStation); +}; + +export const addMapPrintEventListeners = () => { + mapPrintManagerButtonElement.addEventListener('click', printMap); +}; + +export const addSyncDataBeforeUnloadEventListener = () => { + window.onbeforeunload = () => { + syncDataFromAllElements(); + syncDataToLocalStorage(); + syncSubwayMapToLocalStorage(); + }; +}; + +export const addSyncDataBeforeOnloadEventListener = ( + contentElements, + defaultContentElement +) => { + window.onload = () => { + const contentName = window.location.hash.substr(1); + if (contentName) { + convertContent(contentElements, contentName); + } else { + convertContent(contentElements, defaultContentElement.id); + } + loadDataToLocalStorage(); + syncDataToAllElements(); + syncSubwayMapFromLocalStorage(); + showStationManagerResultTable(); + showLineManagerResultTable(); + showSectionManagerResultTable(); + }; +}; + +export default { + addStationManagerEventListeners, + addLineMangerEventListeners, + addSectionManagerEventListeners, + addMapPrintEventListeners, +}; diff --git a/src/routes/routes.js b/src/routes/routes.js new file mode 100644 index 000000000..342c31867 --- /dev/null +++ b/src/routes/routes.js @@ -0,0 +1,23 @@ +export const convertContent = (contentElements, contentName) => { + contentElements.forEach((element) => { + if (element.id === contentName) { + element.setAttribute('style', 'display: block;'); + } else { + element.setAttribute('style', 'display: none;'); + } + }); +}; + +export const setRouterWithElements = ( + contentElements, +) => { + window.onhashchange = () => { + const contentName = window.location.hash.substr(1); + convertContent(contentElements, contentName); + }; +}; + +export default { + setRouterWithElements, + convertContent +}; diff --git a/src/store/store.js b/src/store/store.js new file mode 100644 index 000000000..37271c88e --- /dev/null +++ b/src/store/store.js @@ -0,0 +1,58 @@ +import StationMap from '../classes/subwayMap.js'; +import { getItemByKey, setItemWithKey } from '../utils/localStorage.js'; +import { SUBWAY_MAP_ITEM_NAME } from '../constants/configuration.js'; +import SubwayStation from '../classes/subwayStation.js'; +import SubwayLine from '../classes/subwayLine.js'; + +export const subwayMap = new StationMap(); + +export const syncSubwayMapToLocalStorage = () => { + const subwayMapItem = { + allStations: subwayMap.allStations, + allLines: subwayMap.allLines, + }; + setItemWithKey(subwayMapItem, SUBWAY_MAP_ITEM_NAME); +}; + +const copyAllStations = (allStations) => { + Object.keys(allStations).forEach((stationName) => { + const loadedStation = allStations[stationName]; + const station = new SubwayStation(); + loadedStation.belongingLineNames.forEach((belongingLineName) => { + station.addBeloningLineByLineName(belongingLineName); + }); + subwayMap.addStation(station, stationName); + }); +}; + +const copyAllLines = (allLines) => { + Object.keys(allLines).forEach((lineName) => { + const loadedLine = allLines[lineName]; + const loadedLineEndIndex = loadedLine.allStationsInLine.length - 1; + const line = new SubwayLine( + loadedLine.allStationsInLine[0], + loadedLine.allStationsInLine[loadedLineEndIndex] + ); + for (let i = loadedLine.length - 2; i > 0; i -= 1) { + line.insertStationToLineByNameAndIndex( + loadedLine.allStationsInLine[i], + 1 + ); + } + subwayMap.addLine(line, lineName); + }); +}; + +export const syncSubwayMapFromLocalStorage = () => { + const subwayMapItem = getItemByKey(SUBWAY_MAP_ITEM_NAME); + const { allStations, allLines } = subwayMapItem; + copyAllStations(allStations); + copyAllLines(allLines); + console.log(subwayMap); +}; + +export default { + subwayMap, + syncSubwayMapToLocalStorage, + syncSubwayMapFromLocalStorage, +}; diff --git a/src/templates/button.js b/src/templates/button.js new file mode 100644 index 000000000..deeeacb9d --- /dev/null +++ b/src/templates/button.js @@ -0,0 +1,18 @@ +const getSectionLineMenuButtonTemplate = (lineName) => { + return ``; +}; + +export const getSectionLineMenuButtonsTemplate = (lineNames) => { + let targetLineSetterButtonsTemplate = ''; + lineNames.forEach((lineName) => { + targetLineSetterButtonsTemplate += getSectionLineMenuButtonTemplate( + lineName + ); + }); + + return targetLineSetterButtonsTemplate; +}; + +export default { + getSectionLineMenuButtonsTemplate, +}; diff --git a/src/templates/list.js b/src/templates/list.js new file mode 100644 index 000000000..a18db0157 --- /dev/null +++ b/src/templates/list.js @@ -0,0 +1,32 @@ +const getSubwayLineTemplate = (lineName, stationNamesInLine) => { + let stationItemsTemplate = ''; + stationNamesInLine.forEach((stationName) => { + stationItemsTemplate += `
  • ${stationName}
  • `; + }); + + return ` +

    ${lineName}

    + + `; +}; + +export const getSubwayMapTemplate = (allLines) => { + const allLineNames = Object.keys(allLines); + let subwayMapTemplate = ''; + allLineNames.forEach((lineName) => { + const { allStationsInLine } = allLines[lineName]; + subwayMapTemplate += getSubwayLineTemplate(lineName, allStationsInLine); + }); + + return ` +
    + ${subwayMapTemplate} +
    + `; +}; + +export default { + getSubwayMapTemplate, +}; diff --git a/src/templates/selector.js b/src/templates/selector.js new file mode 100644 index 000000000..1d776517e --- /dev/null +++ b/src/templates/selector.js @@ -0,0 +1,16 @@ +const getSelectorOptionTemplate = (option) => { + return ``; +}; + +export const getSelectorOptionsTemplate = (options) => { + let selectorOptionsTemplate = ''; + options.forEach((option) => { + selectorOptionsTemplate += getSelectorOptionTemplate(option); + }); + + return selectorOptionsTemplate; +}; + +export default { + getSelectorOptionsTemplate, +}; diff --git a/src/templates/table.js b/src/templates/table.js new file mode 100644 index 000000000..c7bfb36a8 --- /dev/null +++ b/src/templates/table.js @@ -0,0 +1,45 @@ +const getTableRowTemplate = ({ + row, + deleteTarget, + deleteButtonClass, + deletebuttonText, +}) => { + let tableCellsTemplate = ''; + row.forEach((cell) => { + tableCellsTemplate += `${cell}`; + }); + return ` + + ${tableCellsTemplate} + + + `; +}; + +export const getTableRowsTemplate = ({ + rows, + deleteTargetCellIndex, + deleteButtonClass, + deleteButtonText, +}) => { + let rowItemsTemplate = ''; + let defaultDeleteButtonText = '์‚ญ์ œ'; + if (deleteButtonText) { + defaultDeleteButtonText = deleteButtonText; + } + rows.forEach((row) => { + const deleteTarget = row[deleteTargetCellIndex]; + rowItemsTemplate += getTableRowTemplate({ + row, + deleteTarget, + deleteButtonClass, + deletebuttonText: defaultDeleteButtonText, + }); + }); + + return rowItemsTemplate; +}; + +export default { + getTableRowsTemplate, +}; diff --git a/src/utils/localStorage.js b/src/utils/localStorage.js new file mode 100644 index 000000000..0987a7fe1 --- /dev/null +++ b/src/utils/localStorage.js @@ -0,0 +1,14 @@ +export const setItemWithKey = (item, key) => { + const stringifiedItem = JSON.stringify(item); + localStorage.setItem(key, stringifiedItem); +}; + +export const getItemByKey = (key) => { + const stringifiedItem = localStorage.getItem(key); + return JSON.parse(stringifiedItem); +}; + +export default { + setItemWithKey, + getItemByKey, +};