diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 000000000..3a2021c21 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,28 @@ +{ + "env": { + "browser": true, + "es2021": true, + "node": true + }, + "extends": [ + "eslint:recommended", + "airbnb-base", + "prettier" + ], + "parserOptions": { + "ecmaVersion": 2015, + "sourceType": "module" + }, + "rules": { + "no-console": "off", + "no-plusplus": "off", + "class-methods-use-this": "off", + "radix": "off", + "no-restricted-properties": "off", + "max-depth" : ["error", 2], + "no-return-assign" : "off", + "no-continue" : "off", + "no-param-reassign" : "off", + "import/extensions" : "off" + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..ae7194bd3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.ieda +.DS_Store diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..13a6d0595 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,8 @@ +{ + "singleQuote": true, + "printWidth": 100, + "tabWidth": 2, + "useTabs": false, + "semi": true, + "arrowParens": "always" +} diff --git a/README.md b/README.md index e97a1d649..a7a818659 100644 --- a/README.md +++ b/README.md @@ -1,114 +1,38 @@ # πŸš‡ μ§€ν•˜μ²  노선도 λ―Έμ…˜ +μ§€ν•˜μ²  역을 μΆ”κ°€ 및 μ‚­μ œν•˜κ³ , μƒμ„±λœ 노선에 역을 μΆ”κ°€ν•˜κ³  μ‚­μ œν•  수 μžˆλŠ” ν”„λ‘œκ·Έλž¨μ΄λ‹€. -## πŸš€ κΈ°λŠ₯ μš”κ΅¬μ‚¬ν•­ +## πŸš€ κΈ°λŠ₯ κ΅¬ν˜„ λͺ©λ‘ +1. μ‚¬μš©μžλŠ” λ²„νŠΌ 4개(μ—­ 관리, λ…Έμ„  관리, ꡬ간 관리, μ§€ν•˜μ²  노선도 좜λ ₯)λ₯Ό 선택할 수 μžˆλ‹€. ### μ§€ν•˜μ²  μ—­ κ΄€λ ¨ κΈ°λŠ₯ -- μ§€ν•˜μ²  역을 λ“±λ‘ν•˜κ³  μ‚­μ œν•  수 μžˆλ‹€. (단, 노선에 λ“±λ‘λœ 역은 μ‚­μ œν•  수 μ—†λ‹€) -- μ€‘λ³΅λœ μ§€ν•˜μ²  μ—­ 이름이 등둝될 수 μ—†λ‹€. -- μ§€ν•˜μ²  역은 2κΈ€μž 이상이어야 ν•œλ‹€. -- μ§€ν•˜μ²  μ—­μ˜ λͺ©λ‘μ„ μ‘°νšŒν•  수 μžˆλ‹€. +2. μ‚¬μš©μžλŠ” 역을 등둝할 수 μžˆλ‹€. + - [μ˜ˆμ™Έμ²˜λ¦¬] 2κΈ€μž μ΄μƒμ˜ 이름인지 검증해야 ν•œλ‹€. + - [μ˜ˆμ™Έμ²˜λ¦¬] μ€‘λ³΅λœ 이름이 μžˆλŠ”μ§€ 검증해야 ν•œλ‹€. +3. μ‚¬μš©μžλŠ” 역을 μ‚­μ œν•  수 μžˆλ‹€. + - [μ˜ˆμ™Έμ²˜λ¦¬] 노선에 μžˆλŠ”μ§€ κ²€μ¦ν•˜κ³ , 노선에 μžˆλ‹€λ©΄ μ‚­μ œν•  수 μ—†λ‹€. +4. μ‚¬μš©μž μ§€ν•˜μ²  μ—­μ˜ λͺ©λ‘μ„ μ‘°νšŒν•  수 μžˆλ‹€. ### μ§€ν•˜μ²  λ…Έμ„  κ΄€λ ¨ κΈ°λŠ₯ -- μ§€ν•˜μ²  노선을 λ“±λ‘ν•˜κ³  μ‚­μ œν•  수 μžˆλ‹€. -- μ€‘λ³΅λœ μ§€ν•˜μ²  λ…Έμ„  이름이 등둝될 수 μ—†λ‹€. -- λ…Έμ„  등둝 μ‹œ 상행 쒅점역과 ν•˜ν–‰ 쒅점역을 μž…λ ₯λ°›λŠ”λ‹€. -- μ§€ν•˜μ²  λ…Έμ„ μ˜ λͺ©λ‘μ„ μ‘°νšŒν•  수 μžˆλ‹€. - -### μ§€ν•˜μ²  ꡬ간 μΆ”κ°€ κΈ°λŠ₯ -- μ§€ν•˜μ²  노선에 ꡬ간을 μΆ”κ°€ν•˜λŠ” κΈ°λŠ₯은 노선에 역을 μΆ”κ°€ν•˜λŠ” κΈ°λŠ₯이라고도 ν•  수 μžˆλ‹€. - - μ—­κ³Ό 역사이λ₯Ό ꡬ간이라 ν•˜κ³  이 κ΅¬κ°„λ“€μ˜ λͺ¨μŒμ΄ 노선이닀. -- ν•˜λ‚˜μ˜ 역은 μ—¬λŸ¬κ°œμ˜ 노선에 좔가될 수 μžˆλ‹€. -- μ—­κ³Ό μ—­ 사이에 μƒˆλ‘œμš΄ 역이 μΆ”κ°€ 될 수 μžˆλ‹€. -- λ…Έμ„ μ—μ„œ κ°ˆλž˜κΈΈμ€ 생길 수 μ—†λ‹€. - - - -### μ§€ν•˜μ²  ꡬ간 μ‚­μ œ κΈ°λŠ₯ -- 노선에 λ“±λ‘λœ 역을 μ œκ±°ν•  수 μžˆλ‹€. -- 쒅점을 μ œκ±°ν•  경우 λ‹€μŒ 역이 쒅점이 λœλ‹€. -- 노선에 ν¬ν•¨λœ 역이 λ‘κ°œ μ΄ν•˜μΌ λ•ŒλŠ” 역을 μ œκ±°ν•  수 μ—†λ‹€. - - +5. μ‚¬μš©μžλŠ” μ§€ν•˜μ²  노선을 등둝할 수 μžˆλ‹€. + - [쑰건] λ…Έμ„  등둝 μ‹œ 상행 쒅점역과 ν•˜ν–‰ 쒅점역을 μž…λ ₯λ°›λŠ”λ‹€. + - [μ˜ˆμ™Έμ²˜λ¦¬] μ€‘λ³΅λœ λ…Έμ„  이름이 μžˆλŠ”μ§€ 검증해야 ν•œλ‹€. + - [μ˜ˆμ™Έμ²˜λ¦¬] ~μ„  ν˜•νƒœμ˜ 이름인지 검증해야 ν•œλ‹€. + - [μ˜ˆμ™Έμ²˜λ¦¬] μ‹œμž‘ 쒅점과 ν•˜ν–‰ 쒅점이 같은 노선은 등둝할 수 μ—†λ‹€. + - [μ˜ˆμ™Έμ²˜λ¦¬] 상행 쒅점과 ν•˜ν–‰ 쒅점이 λ™μΌν•œ 기쑴의 노선이 μžˆλŠ”μ§€ 검증해야 ν•œλ‹€. + - [μ˜ˆμ™Έμ²˜λ¦¬] λ…Έμ„  이름은 무쑰건 μž…λ ₯ν•΄μ•Ό ν•œλ‹€. +6. μ‚¬μš©μžλŠ” μ§€ν•˜μ²  노선을 μ‚­μ œν•  수 μžˆλ‹€. +7. μ‚¬μš©μžλŠ” μ§€ν•˜μ²  λ…Έμ„ μ˜ λͺ©λ‘μ„ μ‘°νšŒν•  수 μžˆλ‹€. + +### μ§€ν•˜μ²  ꡬ간 κ΄€λ ¨ κΈ°λŠ₯ +8. μ‚¬μš©μžλŠ” 노선에 역을 μΆ”κ°€ν•  수 μžˆλ‹€. + - [μ˜ˆμ™Έμ²˜λ¦¬] μ€‘λ³΅λœ 역이 μžˆλŠ”μ§€ 검증해야 ν•œλ‹€. + - [쑰건] ν•˜λ‚˜μ˜ 역은 μ—¬λŸ¬κ°œμ˜ 노선에 좔가될 수 μžˆλ‹€. + - [쑰건] μ—­κ³Ό μ—­ 사이에 μƒˆλ‘œμš΄ 역이 μΆ”κ°€ 될 수 μžˆλ‹€. + - [쑰건] λ…Έμ„ μ—μ„œ κ°ˆλž˜κΈΈμ€ 생길 수 μ—†λ‹€. +9. μ‚¬μš©μžλŠ” λ…Έμ„ μ˜ 역을 μ‚­μ œν•  수 μžˆλ‹€. + - [μ˜ˆμ™Έμ²˜λ¦¬] 노선에 역이 2개 μ΄ν•˜μΈμ§€ κ²€μ¦ν•˜κ³ , 2개 μ΄ν•˜λ©΄ μ‚­μ œν•  수 μ—†λ‹€. + - [쑰건] 쒅점을 μ œκ±°ν•  경우 λ‹€μŒ 역이 쒅점이 λœλ‹€. +10. μ‚¬μš©μžλŠ” λ…Έμ„  λ³„λ‘œ μ—­μ˜ λͺ©λ‘μ„ λ³Ό 수 μžˆλ‹€. ### μ§€ν•˜μ²  노선에 λ“±λ‘λœ μ—­ 쑰회 κΈ°λŠ₯ -- λ…Έμ„ μ˜ 상행 쒅점뢀터 ν•˜ν–‰ μ’…μ κΉŒμ§€ μ—°κ²°λœ μˆœμ„œλŒ€λ‘œ μ—­ λͺ©λ‘μ„ μ‘°νšŒν•  수 μžˆλ‹€. - -
- -## πŸ’» ν”„λ‘œκ·Έλž¨ μ‹€ν–‰ κ²°κ³Ό - -### 역관리 - - -### 노선관리 - - -### ꡬ간관리 - - -### 노선도 좜λ ₯ - - - -## βœ… ν”„λ‘œκ·Έλž˜λ° μš”κ΅¬μ‚¬ν•­ - -### 메뉴 λ²„νŠΌ -- μ—­ 관리 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) λ¬Έμ„œ 절차λ₯Ό 따라 λ―Έμ…˜μ„ μ œμΆœν•œλ‹€. +11. μ‚¬μš©μž λ…Έμ„ μ˜ 상행 쒅점뢀터 ν•˜ν–‰ μ’…μ κΉŒμ§€ μ—°κ²°λœ μˆœμ„œλŒ€λ‘œ 전체 λ…Έμ„ κ³Ό μ—­ λͺ©λ‘μ„ μ‘°νšŒν•  수 μžˆλ‹€. diff --git a/index.html b/index.html index fc99deac2..b0d5daab9 100644 --- a/index.html +++ b/index.html @@ -3,10 +3,52 @@ μ§€ν•˜μ²  노선도 관리 +

πŸš‡ μ§€ν•˜μ²  노선도 관리

+ +
diff --git a/src/components/template/lineManagerTemplate.js b/src/components/template/lineManagerTemplate.js new file mode 100644 index 000000000..815ac02d3 --- /dev/null +++ b/src/components/template/lineManagerTemplate.js @@ -0,0 +1,57 @@ +import stationStorage from '../../storage/stationStorage.js'; + +const LINE_MANAGER_PAGE_TEMPLATE = `
+

λ…Έμ„  이름

+ +
+ + +
+ + +
+ +
+
+ +

πŸš‰ μ§€ν•˜μ²  λ…Έμ„  λͺ©λ‘

+ + + + + + + + + +
λ…Έμ„  이름상행 μ’…μ μ—­ν•˜ν–‰ 쒅점역섀정
+
`; + +const ALL_STATION_OPTION_LIST = (stations) => { + return stations + .map( + (station) => + `` + ) + .join(''); +}; + +const LINE_TABLE_TEMPLATE = (line) => { + const lastStationId = line.stationIds[line.stationIds.length - 1]; + const firstStationId = line.stationIds[0]; + + return ` + ${line.name} + ${ + stationStorage().getStationById(firstStationId).name + } + ${ + stationStorage().getStationById(lastStationId).name + } + + `; +}; + +export { LINE_MANAGER_PAGE_TEMPLATE, ALL_STATION_OPTION_LIST, LINE_TABLE_TEMPLATE }; diff --git a/src/components/template/mapPrintManagerTemplate.js b/src/components/template/mapPrintManagerTemplate.js new file mode 100644 index 000000000..b96ac3494 --- /dev/null +++ b/src/components/template/mapPrintManagerTemplate.js @@ -0,0 +1,24 @@ +import stationStorage from '../../storage/stationStorage.js'; +import lineStorage from '../../storage/lineStorage.js'; + +const STATION_LIST_TEMPLATE = (stationId) => { + const station = stationStorage().getStationById(stationId); + return `
  • ${station.name}
  • `; +}; + +const MAP_MANAGER_PAGE_TEMPLATE = () => { + const lines = lineStorage().getLines(); + return `
    + ${lines + .map( + (line) => + `

    ${line.name}

    + ${line.stationIds + .map(STATION_LIST_TEMPLATE) + .join('')}
    ` + ) + .join('')} +
    `; +}; + +export default MAP_MANAGER_PAGE_TEMPLATE; diff --git a/src/components/template/sectionManagerTemplate.js b/src/components/template/sectionManagerTemplate.js new file mode 100644 index 000000000..7a5123daf --- /dev/null +++ b/src/components/template/sectionManagerTemplate.js @@ -0,0 +1,52 @@ +import stationStorage from '../../storage/stationStorage.js'; + +const SECTION_MANAGER_PAGE_MENU_TEMPLATE = `
    +

    ꡬ간을 μˆ˜μ •ν•  노선을 μ„ νƒν•΄μ£Όμ„Έμš”

    + +
    +
    +
    `; + +const SECTION_LINE_MENU_BTN = (line) => { + return ``; +}; + +const SECTION_MANAGER_PAGE_SELECTOR_TEMPLATE = `

    +

    ꡬ간 등둝

    + + + `; + +const SECTION_MANAGER_PAGE_TABLE_TEMPLATE = ` + + + + + + + + +
    μˆœμ„œμ΄λ¦„μ„€μ •
    `; + +const SECTION_TABLE_TEMPLATE = ({ id, stationIds }) => { + const stations = stationIds.map(stationStorage().getStationById); + + return stations + .map( + (station, index) => + ` + ${index} + ${station.name} + + ` + ) + .join(''); +}; + +export { + SECTION_MANAGER_PAGE_MENU_TEMPLATE, + SECTION_MANAGER_PAGE_SELECTOR_TEMPLATE, + SECTION_MANAGER_PAGE_TABLE_TEMPLATE, + SECTION_LINE_MENU_BTN, + SECTION_TABLE_TEMPLATE, +}; diff --git a/src/components/template/stationManagerTemplate.js b/src/components/template/stationManagerTemplate.js new file mode 100644 index 000000000..209f21d6b --- /dev/null +++ b/src/components/template/stationManagerTemplate.js @@ -0,0 +1,24 @@ +const STATION_MANAGER_PAGE_TEMPLATE = `

    μ—­ 이름

    + + +
    + +

    πŸš‰ μ§€ν•˜μ²  μ—­ λͺ©λ‘

    + + + + + + + +
    μ—­ 이름섀정
    +
    `; + +const STATION_TABLE_TEMPLATE = (station) => { + return ` + ${station.name} + + `; +}; + +export { STATION_MANAGER_PAGE_TEMPLATE, STATION_TABLE_TEMPLATE }; diff --git a/src/components/views/SectionManagerPages/sectionManagerPage.js b/src/components/views/SectionManagerPages/sectionManagerPage.js new file mode 100644 index 000000000..d5f0cb7a1 --- /dev/null +++ b/src/components/views/SectionManagerPages/sectionManagerPage.js @@ -0,0 +1,26 @@ +import { + SECTION_MANAGER_PAGE_MENU_TEMPLATE, + SECTION_LINE_MENU_BTN, +} from '../../template/sectionManagerTemplate.js'; +import lineStorage from '../../../storage/lineStorage.js'; +import singleSectionManager from './singleSectionManager.js'; + +export default function sectionManagerPage($element) { + const lines = lineStorage().getLines(); + + $element.innerHTML = SECTION_MANAGER_PAGE_MENU_TEMPLATE; + const $listMenuBtn = $element.querySelector('.line-buttons'); + $listMenuBtn.innerHTML = lines.map(SECTION_LINE_MENU_BTN).join(''); + const $sectionSelectorContainer = $element.querySelector('#section-selector-container'); + const $sectionTable = $element.querySelector('#section-table'); + + const onMenuFilterHandler = (e) => { + if (!e.target.classList.contains('section-line-menu-button')) { + return; + } + const currentLine = lineStorage().getOneLine(e.target.dataset.lineid); + singleSectionManager($sectionSelectorContainer, $sectionTable, currentLine); + }; + + $listMenuBtn.addEventListener('click', onMenuFilterHandler); +} diff --git a/src/components/views/SectionManagerPages/singleSectionManager.js b/src/components/views/SectionManagerPages/singleSectionManager.js new file mode 100644 index 000000000..c6af11abe --- /dev/null +++ b/src/components/views/SectionManagerPages/singleSectionManager.js @@ -0,0 +1,115 @@ +import { + sectionIndexValidator, + sectionStationNameValidator, + sectionDeleteValidator, +} from '../../../utils/validator/sectionValidator.js'; +import { + SECTION_MANAGER_PAGE_SELECTOR_TEMPLATE, + SECTION_MANAGER_PAGE_TABLE_TEMPLATE, + SECTION_TABLE_TEMPLATE, +} from '../../template/sectionManagerTemplate.js'; +import { ALL_STATION_OPTION_LIST } from '../../template/lineManagerTemplate.js'; +import stationStorage from '../../../storage/stationStorage.js'; +import lineStorage from '../../../storage/lineStorage.js'; + +export default function singleSectionManager($container, $table, line) { + const stations = stationStorage().getStations(); + const lines = lineStorage().getLines(); + + $container.innerHTML = SECTION_MANAGER_PAGE_SELECTOR_TEMPLATE; + const $lineTitle = $container.querySelector('#line-title'); + $lineTitle.innerText = `${line.name} 관리`; + + const $sectionSelector = $container.querySelector('#section-station-selector'); + $sectionSelector.innerHTML = ALL_STATION_OPTION_LIST(stations); + + $table.innerHTML = SECTION_MANAGER_PAGE_TABLE_TEMPLATE; + const $sectionTableBody = $table.querySelector('.section-table-tbody'); + $sectionTableBody.innerHTML = SECTION_TABLE_TEMPLATE(line); + + const $userSectionIndexInput = $container.querySelector('#section-order-input'); + const $userSelectStationBtn = $container.querySelector('#section-station-selector'); + const $userSectionSubmitBtn = $container.querySelector('#section-add-button'); + + const renderSection = (newLine) => { + $sectionTableBody.innerHTML = SECTION_TABLE_TEMPLATE(newLine); + }; + + const getStationById = (stationIds) => { + return stations.filter((station) => station.id === stationIds)[0]; + }; + + const removeStationInLine = (stationId) => { + const deleteIndex = line.stationIds.findIndex((id) => id === stationId); + line.stationIds.splice(deleteIndex, 1); + for (let i = 0; i < lines.length; i++) { + if (lines[i].id === line.id) { + lines[i] = line; + } + } + lineStorage().setLine(lines); + return line; + }; + + const removeLineInStation = (stationId, lineId) => { + const station = getStationById(stationId); + const deleteIndex = station.line.findIndex((lineNum) => lineNum === lineId); + station.line.splice(deleteIndex, 1); + stationStorage().setStation(stations); + }; + + const removeStationInSection = (stationId, lineId) => { + removeLineInStation(stationId, lineId); + renderSection(removeStationInLine(stationId)); + }; + + const onRemoveSubmitHandler = (e) => { + const stationId = parseInt(e.target.dataset.stationid); + const lineId = parseInt(e.target.closest('tr').id); // line.id + if (Number.isNaN(stationId)) { + return; + } + + if (sectionDeleteValidator(lineId) && confirm('μ •λ§λ‘œ λ…Έμ„ μ—μ„œ μ‚­μ œν•˜μ‹œκ² μŠ΅λ‹ˆκΉŒ?')) { + removeStationInSection(stationId, lineId); + } + }; + + const updateLineState = (stationId, stationIndex) => { + line.stationIds.splice(stationIndex, 0, stationId); + for (let i = 0; i < lines.length; i++) { + if (lines[i].id === line.id) { + lines[i] = line; + } + } + lineStorage().setLine(lines); + return line; + }; + + const updateStationState = (stationId) => { + getStationById(stationId).line.push(line.id); + stationStorage().setStation(stations); + }; + + const updateSection = (stationName, stationIndex) => { + const stationId = stationStorage().getStationIdByName(stationName); + updateStationState(stationId); + renderSection(updateLineState(stationId, stationIndex)); + }; + + const onSectionSubmitHandler = () => { + const userSelectStationName = $userSelectStationBtn.value; + const userSectionIndex = parseInt($userSectionIndexInput.value); + + if ( + sectionStationNameValidator(line, stations, userSelectStationName) && + sectionIndexValidator(line.stationIds.length, userSectionIndex) + ) { + updateSection(userSelectStationName, userSectionIndex); + } + $userSectionIndexInput.value = ''; + }; + + $userSectionSubmitBtn.addEventListener('click', onSectionSubmitHandler); + $sectionTableBody.addEventListener('click', onRemoveSubmitHandler); +} diff --git a/src/components/views/lineManagerPage.js b/src/components/views/lineManagerPage.js new file mode 100644 index 000000000..6eea2a0fb --- /dev/null +++ b/src/components/views/lineManagerPage.js @@ -0,0 +1,109 @@ +import { + LINE_MANAGER_PAGE_TEMPLATE, + ALL_STATION_OPTION_LIST, + LINE_TABLE_TEMPLATE, +} from '../template/lineManagerTemplate.js'; +import { lineNameValidator, lineStationsValidator } from '../../utils/validator/lineValidator.js'; +import stationStorage from '../../storage/stationStorage.js'; +import lineStorage from '../../storage/lineStorage.js'; +import Line from '../../utils/Line.js'; + +export default function stationManagerPage($element) { + $element.innerHTML = LINE_MANAGER_PAGE_TEMPLATE; + const $userInputLine = $element.querySelector('#line-name-input'); + const $startStation = $element.querySelector('#line-start-station-selector'); + const $endStation = $element.querySelector('#line-end-station-selector'); + const $userLineSubmitBtn = $element.querySelector('#line-add-button'); + const $lineTableBody = $element.querySelector('.line-table-tbody'); + + const stations = stationStorage().getStations(); + let lines = lineStorage().getLines(); + + $startStation.innerHTML = ALL_STATION_OPTION_LIST(stations); + $endStation.innerHTML = ALL_STATION_OPTION_LIST(stations); + + const renderLines = () => { + $lineTableBody.innerHTML = lines.map(LINE_TABLE_TEMPLATE).join(''); + }; + + const getNewId = () => { + if (!lines || lines.length === 0) { + return 0; + } + return lines[lines.length - 1].id + 1; + }; + + const getStationById = (stationIds) => { + return stations.filter((station) => station.id === stationIds)[0]; + }; + + const removeLineInStation = (currentLineId) => { + const stationsInLine = lines + .filter((line) => line.id === parseInt(currentLineId))[0] + .stationIds.map(getStationById); + + for (let i = 0; i < stationsInLine.length; i++) { + const deleteIndex = stationsInLine[i].line.indexOf(parseInt(currentLineId)); + stationsInLine[i].line.splice(deleteIndex, 1); + } + stationStorage().setStation(stations); + }; + + const removeLine = (currentLineId) => { + removeLineInStation(currentLineId); + lines = lines.filter((line) => line.id !== parseInt(currentLineId)); + lineStorage().setLine(lines); + renderLines(); + }; + + const onLineDeleteHandler = (e) => { + if (!e.target.classList.contains('line-delete-button')) { + return; + } + if (confirm('μ •λ§λ‘œ μ‚­μ œν•˜μ‹œκ² μŠ΅λ‹ˆκΉŒ?')) { + removeLine(e.target.closest('tr').id); + } + }; + + const addLine = (newLine) => { + lines.push(newLine); + lineStorage().setLine(lines); + renderLines(); + }; + + const getStation = (stationName) => { + return stations.filter((station) => station.name === stationName)[0]; + }; + + const addLineInStation = (lineId, stationName) => { + getStation(stationName).line.push(lineId); + stationStorage().setStation(stations); + }; + + const createLine = (newLineName, startStationName, endStationName) => { + const newLine = new Line(getNewId(), newLineName); + newLine.setLine(stationStorage().getStationIdByName(startStationName), 0); + newLine.setLine(stationStorage().getStationIdByName(endStationName), 1); + + addLineInStation(newLine.id, startStationName); + addLineInStation(newLine.id, endStationName); + addLine(newLine); + }; + + const onLineSubmitHandler = () => { + const newLineName = $userInputLine.value; + + if ( + lineNameValidator(lines, newLineName) && + lineStationsValidator($startStation.value, $endStation.value) + ) { + createLine(newLineName, $startStation.value, $endStation.value); + } + + $userInputLine.value = ''; + }; + + $userLineSubmitBtn.addEventListener('click', onLineSubmitHandler); + $lineTableBody.addEventListener('click', onLineDeleteHandler); + renderLines(); +} diff --git a/src/components/views/mapPrintManagerPage.js b/src/components/views/mapPrintManagerPage.js new file mode 100644 index 000000000..71938c49e --- /dev/null +++ b/src/components/views/mapPrintManagerPage.js @@ -0,0 +1,5 @@ +import MAP_MANAGER_PAGE_TEMPLATE from '../template/mapPrintManagerTemplate.js'; + +export default function mapPrintManagerPage($element) { + $element.innerHTML = MAP_MANAGER_PAGE_TEMPLATE(); +} diff --git a/src/components/views/stationManagerPage.js b/src/components/views/stationManagerPage.js new file mode 100644 index 000000000..17762faac --- /dev/null +++ b/src/components/views/stationManagerPage.js @@ -0,0 +1,70 @@ +import { + STATION_MANAGER_PAGE_TEMPLATE, + STATION_TABLE_TEMPLATE, +} from '../template/stationManagerTemplate.js'; +import { + stationNameValidator, + stationDeleteValidation, +} from '../../utils/validator/stationValidator.js'; +import stationStorage from '../../storage/stationStorage.js'; +import Station from '../../utils/Station.js'; + +export default function stationManagerPage($element) { + $element.innerHTML = STATION_MANAGER_PAGE_TEMPLATE; + const $userStationInput = $element.querySelector('#station-name-input'); + const $userStationSubmit = $element.querySelector('#station-add-button'); + const $stationTableBody = $element.querySelector('.station_manager_tbody'); + + let stations = stationStorage().getStations(); + + const renderStationTable = () => { + $stationTableBody.innerHTML = stations.map(STATION_TABLE_TEMPLATE).join(''); + }; + + const deleteStation = (stationTag) => { + if (!stationDeleteValidation(stationTag)) { + return; + } + stations = stations.filter((station) => station.id !== parseInt(stationTag.id)); + stationStorage().setStation(stations); + renderStationTable(); + }; + + const onStationDeleteHandler = (e) => { + if (!e.target.classList.contains('station-delete-button')) { + return false; + } + if (confirm('μ •λ§λ‘œ μ‚­μ œν•˜μ‹œκ² μŠ΅λ‹ˆκΉŒ?')) { + deleteStation(e.target.closest('tr')); + } + }; + + const addStations = (newStations) => { + stations.push(newStations); + stationStorage().setStation(stations); + renderStationTable(); + }; + + const getNewId = () => { + if (!stations || stations.length === 0) { + return 0; + } + return stations[stations.length - 1].id + 1; + }; + + const createStation = (newStationName) => { + addStations(new Station(getNewId(), newStationName)); + }; + + const onStationSubmitHandler = () => { + const newStationName = $userStationInput.value; + if (stationNameValidator(stations, newStationName)) { + createStation(newStationName); + } + $userStationInput.value = ''; + }; + + $userStationSubmit.addEventListener('click', onStationSubmitHandler); + $stationTableBody.addEventListener('click', onStationDeleteHandler); + renderStationTable(); +} diff --git a/src/index.js b/src/index.js index e69de29bb..646aeb386 100644 --- a/src/index.js +++ b/src/index.js @@ -0,0 +1,4 @@ +import subwayMapApp from './subwayMapApp.js'; + +const $app = document.querySelector('#app'); +subwayMapApp($app); diff --git a/src/storage/lineStorage.js b/src/storage/lineStorage.js new file mode 100644 index 000000000..4d9fcdbec --- /dev/null +++ b/src/storage/lineStorage.js @@ -0,0 +1,35 @@ +import { LINE_STORAGE_NAME } from '../utils/constant.js'; + +export default function lineStorage() { + const getLines = () => { + if (!localStorage.getItem(LINE_STORAGE_NAME)) { + return []; + } + const storedItems = localStorage.getItem(LINE_STORAGE_NAME); + return JSON.parse(storedItems); + }; + + const setLine = (line) => { + localStorage.setItem(LINE_STORAGE_NAME, JSON.stringify(line)); + }; + + const getStartPointsId = () => { + return getLines().map((line) => line.stationIds[0]); + }; + + const getEndPointsId = () => { + return getLines().map((line) => line.stationIds[line.stationIds.length - 1]); + }; + + const getOneLine = (lineId) => { + return getLines().filter((line) => line.id === parseInt(lineId))[0]; + }; + + return { + getLines, + setLine, + getStartPointsId, + getEndPointsId, + getOneLine, + }; +} diff --git a/src/storage/stationStorage.js b/src/storage/stationStorage.js new file mode 100644 index 000000000..e6b1b9891 --- /dev/null +++ b/src/storage/stationStorage.js @@ -0,0 +1,30 @@ +import { STATION_STORAGE_NAME } from '../utils/constant.js'; + +export default function stationStorage() { + const getStations = () => { + if (!localStorage.getItem(STATION_STORAGE_NAME)) { + return []; + } + const storedItems = localStorage.getItem(STATION_STORAGE_NAME); + return JSON.parse(storedItems); + }; + + const setStation = (station) => { + localStorage.setItem(STATION_STORAGE_NAME, JSON.stringify(station)); + }; + + const getStationIdByName = (stationName) => { + return getStations().filter((station) => station.name === stationName)[0].id; + }; + + const getStationById = (stationId) => { + return getStations().filter((station) => station.id === stationId)[0]; + }; + + return { + getStations, + setStation, + getStationIdByName, + getStationById, + }; +} diff --git a/src/subwayMapApp.js b/src/subwayMapApp.js new file mode 100644 index 000000000..31c00ff79 --- /dev/null +++ b/src/subwayMapApp.js @@ -0,0 +1,21 @@ +import stationManagerPage from './components/views/stationManagerPage.js'; +import lineManagerPage from './components/views/lineManagerPage.js'; +import sectionManagerPage from './components/views/SectionManagerPages/sectionManagerPage.js'; +import mapPrintManagerPage from './components/views/mapPrintManagerPage.js'; + +export default function subwayMapApp($element) { + const init = () => { + const $stationManagerBtn = $element.querySelector('#station-manager-button'); + const $lineManagerBtn = $element.querySelector('#line-manager-button'); + const $sectionManagerBtn = $element.querySelector('#section-manager-button'); + const $mapPrintManagerBtn = $element.querySelector('#map-print-manager-button'); + const $contentSection = $element.querySelector('.content-container'); + + $stationManagerBtn.addEventListener('click', () => stationManagerPage($contentSection)); + $lineManagerBtn.addEventListener('click', () => lineManagerPage($contentSection)); + $sectionManagerBtn.addEventListener('click', () => sectionManagerPage($contentSection)); + $mapPrintManagerBtn.addEventListener('click', () => mapPrintManagerPage($contentSection)); + }; + + init(); +} diff --git a/src/utils/Line.js b/src/utils/Line.js new file mode 100644 index 000000000..c82eb4369 --- /dev/null +++ b/src/utils/Line.js @@ -0,0 +1,12 @@ +export default function Line(id, name) { + this.id = id; + this.name = name; + this.stationIds = []; + + this.setLine = (stationId, index) => { + if (this.stationIds.includes(stationId)) { + alert('이미 λ“±λ‘λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€'); + } + this.stationIds.splice(index, 0, stationId); + }; +} diff --git a/src/utils/Station.js b/src/utils/Station.js new file mode 100644 index 000000000..07c1baf13 --- /dev/null +++ b/src/utils/Station.js @@ -0,0 +1,5 @@ +export default function Station(id, name) { + this.id = id; + this.name = name; + this.line = []; +} diff --git a/src/utils/constant.js b/src/utils/constant.js new file mode 100644 index 000000000..98c0788fe --- /dev/null +++ b/src/utils/constant.js @@ -0,0 +1,6 @@ +const STATION_STORAGE_NAME = 'STATIONS'; +const LINE_STORAGE_NAME = 'LINES'; +const NAME_MIN_LENGTH = 2; +const SECTION_MIN_LENGTH = 2; + +export { STATION_STORAGE_NAME, LINE_STORAGE_NAME, NAME_MIN_LENGTH, SECTION_MIN_LENGTH }; diff --git a/src/utils/validator/lineValidator.js b/src/utils/validator/lineValidator.js new file mode 100644 index 000000000..bc338d0bd --- /dev/null +++ b/src/utils/validator/lineValidator.js @@ -0,0 +1,64 @@ +import lineStorage from '../../storage/lineStorage.js'; +import stationStorage from '../../storage/stationStorage.js'; + +const isEqualName = (lines, lineName) => { + return lines.some((line) => line.name === lineName) ? alert('μ€‘λ³΅λœ λ…Έμ„  μ΄λ¦„μž…λ‹ˆλ‹€.') : true; +}; + +const isNameNotNull = (lineName) => { + return !lineName ? alert('λ…Έμ„  이름을 μž…λ ₯ν•΄μ£Όμ„Έμš”') : true; +}; + +const isCorrectName = (lineName) => { + return lineName.split('')[lineName.length - 1] !== 'μ„ ' + ? alert("λ…Έμ„ μ˜ 이름은 'μ„ '으둜 λλ‚˜μ•Ό ν•©λ‹ˆλ‹€") + : true; +}; + +const isEqualPoints = (startStationName, endStationName) => { + return startStationName === endStationName + ? alert('상행 쒅점과 ν•˜ν–‰ 쒅점은 μ„œλ‘œ 달라야 ν•©λ‹ˆλ‹€') + : true; +}; + +const getStartStationIds = (stationName) => { + return lineStorage() + .getStartPointsId() + .map((stationId) => stationId === parseInt(stationStorage().getStationIdByName(stationName))); +}; + +const getEndStationIds = (stationName) => { + return lineStorage() + .getEndPointsId() + .map((stationId) => stationId === parseInt(stationStorage().getStationIdByName(stationName))); +}; + +const isEqualLine = (startStationName, endStationName) => { + const startStationIds = getStartStationIds(startStationName); + const endStationIds = getEndStationIds(endStationName); + + const equalLine = startStationIds.filter((station, index) => station && endStationIds[index]); + return equalLine.length !== 0 ? alert('λ™μΌν•œ 쒅점을 κ°€μ§„ 노선이 μžˆμŠ΅λ‹ˆλ‹€') : true; +}; + +const isEqualReverseLine = (startStationName, endStationName) => { + const startStationIds = getStartStationIds(endStationName); + const endStationIds = getEndStationIds(startStationName); + + const equalLine = startStationIds.filter((station, index) => station && endStationIds[index]); + return equalLine.length !== 0 ? alert('λ™μΌν•œ 쒅점을 κ°€μ§„ 노선이 μžˆμŠ΅λ‹ˆλ‹€') : true; +}; + +function lineNameValidator(lines, lineName) { + return isEqualName(lines, lineName) && isNameNotNull(lineName) && isCorrectName(lineName); +} + +function lineStationsValidator(startStationName, endStationName) { + return ( + isEqualPoints(startStationName, endStationName) && + isEqualLine(startStationName, endStationName) && + isEqualReverseLine(startStationName, endStationName) + ); +} + +export { lineNameValidator, lineStationsValidator }; diff --git a/src/utils/validator/sectionValidator.js b/src/utils/validator/sectionValidator.js new file mode 100644 index 000000000..d5438036d --- /dev/null +++ b/src/utils/validator/sectionValidator.js @@ -0,0 +1,45 @@ +import lineStorage from '../../storage/lineStorage.js'; +import { SECTION_MIN_LENGTH } from '../constant.js'; + +const isNumber = (sectionIndex) => { + return Number.isNaN(sectionIndex) ? alert('μ •ν™•ν•œ 숫자λ₯Ό μž…λ ₯ν•΄μ£Όμ„Έμš”') : true; +}; + +const isPositiveNumber = (sectionIndex) => { + return sectionIndex >= 0 ? true : alert('μŒμˆ˜κ°€ μ•„λ‹Œ 0 μ΄μƒμ˜ 숫자λ₯Ό μž…λ ₯ν•΄μ£Όμ„Έμš”'); +}; + +const isCorrectIndex = (sectionLength, sectionIndex) => { + return sectionIndex <= sectionLength ? true : alert('μž…λ ₯ν•œ μˆœμ„œλ₯Ό ν™•μΈν•΄μ£Όμ„Έμš”'); +}; + +const isLengthLongerThanTwo = (lineId) => { + const stationLength = lineStorage().getOneLine(lineId).stationIds.length; + return stationLength <= SECTION_MIN_LENGTH + ? alert('노선은 μ΅œμ†Œ 2개의 μ—­μœΌλ‘œ 이루어져 μžˆμŠ΅λ‹ˆλ‹€.') + : true; +}; + +const isNotRegistered = (id, stations, stationName) => { + return stations.filter((station) => station.name === stationName)[0].line.includes(id) + ? alert('이미 λ“±λ‘λœ μ—­μž…λ‹ˆλ‹€') + : true; +}; + +function sectionStationNameValidator({ id }, stations, stationName) { + return isNotRegistered(id, stations, stationName); +} + +function sectionIndexValidator(sectionLength, sectionIndex) { + return ( + isNumber(sectionIndex) && + isPositiveNumber(sectionIndex) && + isCorrectIndex(sectionLength, sectionIndex) + ); +} + +function sectionDeleteValidator(lineId) { + return isLengthLongerThanTwo(lineId); +} + +export { sectionStationNameValidator, sectionIndexValidator, sectionDeleteValidator }; diff --git a/src/utils/validator/stationValidator.js b/src/utils/validator/stationValidator.js new file mode 100644 index 000000000..12f8763b8 --- /dev/null +++ b/src/utils/validator/stationValidator.js @@ -0,0 +1,27 @@ +import { NAME_MIN_LENGTH } from '../constant.js'; + +const isNameLengthLongerThanTwo = (stationName) => { + return stationName.length < NAME_MIN_LENGTH ? alert('이름은 λ‘κΈ€μž μ΄μƒμž…λ‹ˆλ‹€') : true; +}; + +const isEqualName = (stations, stationName) => { + return stations && stations.map((value) => value.name).includes(stationName) + ? alert('μ€‘λ³΅λœ μ΄λ¦„μž…λ‹ˆλ‹€.') + : true; +}; + +const isIncludedLine = (stationTag) => { + return stationTag.dataset.lines.length !== 0 + ? alert('노선에 ν¬ν•¨λ˜μ–΄ μžˆλŠ” 라인은 μ‚­μ œν•  수 μ—†μŠ΅λ‹ˆλ‹€') + : true; +}; + +function stationNameValidator(stations, stationName) { + return isNameLengthLongerThanTwo(stationName) && isEqualName(stations, stationName); +} + +function stationDeleteValidation(stationTag) { + return isIncludedLine(stationTag); +} + +export { stationNameValidator, stationDeleteValidation };