From 870c3d3ce5867705703c73843d207331d3a78b22 Mon Sep 17 00:00:00 2001 From: BB-choi <78826879+BB-choi@users.noreply.github.com> Date: Thu, 14 Apr 2022 15:11:16 +0900 Subject: [PATCH 1/8] =?UTF-8?q?[BB]=20column=20=ED=83=80=EC=9D=B4=ED=8B=80?= =?UTF-8?q?=20=EC=98=86=20+,=20x=20=EB=B2=84=ED=8A=BC=20=EC=9D=B4=EB=B2=A4?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: column 제목 영역 +버튼,x버튼 클릭 이벤트 * fix: x버튼 클릭 이벤트 삭제 및 취소 이벤트 * refactor: button요소 tagComponents이용하여 생성 * refactor: 템플릿 리터럴 관련 변수명 변경, 코드 분리 * refactor: 중복함수 제거 - on~~MouseOver, Out과 같은 함수를 handle~과 같이 수정 * refactor: 각 버튼마다 존재했던 handle함수를 하나로 합침 * refactor: 칼럼제목 + 버튼 클릭시 $cardWritable 표시 - 기존 칼럼 헤더에 있던 cardWritable을 Cards내부로 이동 - 클래스 toggle로 추가 / 제거 * fix: 취소 버튼으로 newCard 닫히지 않던 문제 해결 * refactor: 메서드명의 get~을 create로 변경 --- .../Content/CardWritable/CardWritable.js | 84 ++++++++++++------- .../CardWritable/cardWritable.module.css | 9 +- front/src/components/Content/Cards/Cards.js | 6 +- .../src/components/Content/Column/Columns.js | 28 ++++++- .../Content/Column/columns.module.css | 4 + .../Content/ColumnHeader/ColumnHeader.js | 84 +++++++++++++------ .../ColumnHeader/columnHeader.module.css | 16 +++- 7 files changed, 164 insertions(+), 67 deletions(-) diff --git a/front/src/components/Content/CardWritable/CardWritable.js b/front/src/components/Content/CardWritable/CardWritable.js index 762651794..88c93f2d7 100644 --- a/front/src/components/Content/CardWritable/CardWritable.js +++ b/front/src/components/Content/CardWritable/CardWritable.js @@ -1,34 +1,60 @@ +import peact from "../../../core/peact"; +import Button from "../../../tagComponents/Button"; import styles from "./cardWritable.module.css"; -const CardWritable = () => { - return ` -
-
- -
- - - -
-
-
- -
-
- - -
-
- `; +const CardWritable = ({ handleNewCardVisibility }) => { + const $inputDesc = peact.createElement({ + tag: "input", + className: styles.cardDescInput, + attrs: { + value: "", + type: "text", + name: "card-content", + placeholder: "내용을 입력하세요", + }, + child: [], + }); + + const $inputTitle = peact.createElement({ + tag: "input", + className: styles.cardTitleInput, + attrs: { + value: "", + type: "text", + name: "card-title", + placeholder: "제목을 입력하세요", + }, + child: [], + }); + + const $cardWritableHeader = peact.createElement({ + tag: "div", + className: styles.headerArea, + child: [$inputTitle], + }); + + const $cancelButton = Button({ + onClick: handleNewCardVisibility, + className: [styles.button, styles.cancelButton], + innerHTML: "취소", + }); + + const $confirmButton = Button({ + className: [styles.button, styles.confirmButton, styles.activeButton], + innerHTML: "등록", + }); + + const $buttonArea = peact.createElement({ + tag: "div", + className: styles.buttons, + child: [$cancelButton, $confirmButton], + }); + + return peact.createElement({ + tag: "div", + className: [styles.cardWritable], + child: [$cardWritableHeader, $inputDesc, $buttonArea], + }); }; export default CardWritable; diff --git a/front/src/components/Content/CardWritable/cardWritable.module.css b/front/src/components/Content/CardWritable/cardWritable.module.css index e29e2a081..7021e2214 100644 --- a/front/src/components/Content/CardWritable/cardWritable.module.css +++ b/front/src/components/Content/CardWritable/cardWritable.module.css @@ -1,19 +1,16 @@ .cardWritable { height: 140px; - display: flex; + display: none; flex-direction: column; justify-content: space-between; background-color: #fff; box-shadow: 0px 1px 30px rgba(224, 224, 224, 0.3); + margin-bottom: 15px; padding: 15px; border: 1px solid #0075de; border-radius: 6px; } -.cardWritable:not(:last-child) { - margin-bottom: 15px; -} - .headerArea { display: flex; height: 20px; @@ -45,6 +42,7 @@ .button { width: 130px; height: 40px; + cursor: pointer; } .cancelButton { @@ -60,6 +58,7 @@ font-weight: 700; font-size: 14px; color: rgba(255, 255, 255, 0.4); + opacity: 0.5; background: #86c6ff; border: 0; border-radius: 6px; diff --git a/front/src/components/Content/Cards/Cards.js b/front/src/components/Content/Cards/Cards.js index 7c312b4c2..c0be3ce7f 100644 --- a/front/src/components/Content/Cards/Cards.js +++ b/front/src/components/Content/Cards/Cards.js @@ -2,7 +2,7 @@ import peact from "../../../core/peact"; import Card from "../Card/Card"; import styles from "./cards.module.css"; -const Cards = ({ todos, handleRenderFlag }) => { +const Cards = ({ $newCard, todos, handleRenderFlag }) => { const setTodosSortByLatest = (a, b) => new Date(b.updatedAt) - new Date(a.updatedAt); @@ -14,11 +14,11 @@ const Cards = ({ todos, handleRenderFlag }) => { }); }; - const childElements = todos.sort(setTodosSortByLatest).map(getCardsTemplate); + const todoElements = todos.sort(setTodosSortByLatest).map(getCardsTemplate); return peact.createElement({ tag: "div", - child: childElements, + child: [$newCard, ...todoElements], }); }; diff --git a/front/src/components/Content/Column/Columns.js b/front/src/components/Content/Column/Columns.js index 3bbc3a5c9..6f9ba61e8 100644 --- a/front/src/components/Content/Column/Columns.js +++ b/front/src/components/Content/Column/Columns.js @@ -1,5 +1,6 @@ import peact from "../../../core/peact"; import Cards from "../Cards/Cards"; +import CardWritable from "../CardWritable/CardWritable"; import ColumnHeader from "../ColumnHeader/ColumnHeader"; import styles from "./columns.module.css"; @@ -8,13 +9,32 @@ const Columns = ({ columns, todos, handleRenderFlag }) => { return todos.filter((todo) => todo.columnId === columnId); }; - const getColumnTemplate = (column) => { + const createColumnHeaderElement = ({ column, handleNewCardVisibility }) => + ColumnHeader({ + column, + todos: getTodosByColumnId(column._id), + handleNewCardVisibility, + }); + + const createCardsElement = ({ $newCard, column }) => + Cards({ + $newCard, + todos: getTodosByColumnId(column._id), + handleRenderFlag, + }); + + const createColumnElement = (column) => { + const $newCard = CardWritable({ handleNewCardVisibility }); + function handleNewCardVisibility() { + $newCard.classList.toggle(styles.visible); + } + return peact.createElement({ tag: "div", className: styles.column, child: [ - ColumnHeader({ column, todos: getTodosByColumnId(column._id) }), - Cards({ todos: getTodosByColumnId(column._id), handleRenderFlag }), + createColumnHeaderElement({ column, handleNewCardVisibility }), + createCardsElement({ $newCard, column }), ], }); }; @@ -22,7 +42,7 @@ const Columns = ({ columns, todos, handleRenderFlag }) => { return peact.createElement({ tag: "div", className: styles.content, - child: columns.map(getColumnTemplate), + child: columns.map(createColumnElement), }); }; diff --git a/front/src/components/Content/Column/columns.module.css b/front/src/components/Content/Column/columns.module.css index 1d878d886..93b0d7cda 100644 --- a/front/src/components/Content/Column/columns.module.css +++ b/front/src/components/Content/Column/columns.module.css @@ -10,3 +10,7 @@ display: flex; padding: 0 80px; } + +.visible { + display: flex; +} diff --git a/front/src/components/Content/ColumnHeader/ColumnHeader.js b/front/src/components/Content/ColumnHeader/ColumnHeader.js index b770e2839..b68586dc7 100644 --- a/front/src/components/Content/ColumnHeader/ColumnHeader.js +++ b/front/src/components/Content/ColumnHeader/ColumnHeader.js @@ -1,35 +1,69 @@ import peact from "../../../core/peact"; import styles from "./columnHeader.module.css"; -const ColumnHeader = ({ column, todos }) => { +const ColumnHeader = ({ column, todos, handleNewCardVisibility }) => { + const handleButtonOverOut = (target, buttonName) => { + const targetButton = target.closest(`.${styles[buttonName]}`) || target; + targetButton.classList.toggle(styles[`${buttonName}Over`]); + }; + const todosCount = todos.length; + const columTitleTemplate = `

${column.title}

`; + const cardsCountTemplate = `
${todosCount}
`; + + const $columnTitleWrap = peact.createElement({ + tag: "div", + className: styles.titleWrap, + child: [columTitleTemplate + cardsCountTemplate], + }); + + const plusButtonImgTemplate = ` + + + `; + + const $plusButton = peact.createElement({ + tag: "div", + className: styles.plusButton, + attrs: { + onMouseOver: ({ target }) => handleButtonOverOut(target, "plusButton"), + onMouseOut: ({ target }) => handleButtonOverOut(target, "plusButton"), + onClick: handleNewCardVisibility, + }, + child: [plusButtonImgTemplate], + }); + + const deleteButtonImgTemplate = ` + + + `; + + const $deleteButton = peact.createElement({ + tag: "div", + className: styles.xButton, + attrs: { + onMouseOver: ({ target }) => handleButtonOverOut(target, "xButton"), + onMouseOut: ({ target }) => handleButtonOverOut(target, "xButton"), + }, + child: [deleteButtonImgTemplate], + }); + + const $columnButtonArea = peact.createElement({ + tag: "div", + className: styles.buttonArea, + child: [$plusButton, $deleteButton], + }); + + const $columnTitleArea = peact.createElement({ + tag: "div", + className: styles.titleArea, + child: [$columnTitleWrap, $columnButtonArea], + }); - const headerInnerHTML = ` -
-

${column.title}

-
${todosCount}
-
-
- - - - - - - - - - - -
- `; return peact.createElement({ tag: "div", - className: styles.header, - child: [headerInnerHTML], + className: [styles.header, "header"], + child: [$columnTitleArea], }); }; diff --git a/front/src/components/Content/ColumnHeader/columnHeader.module.css b/front/src/components/Content/ColumnHeader/columnHeader.module.css index b7f5c96d1..5e00db714 100644 --- a/front/src/components/Content/ColumnHeader/columnHeader.module.css +++ b/front/src/components/Content/ColumnHeader/columnHeader.module.css @@ -1,4 +1,4 @@ -.header { +.titleArea { display: flex; justify-content: space-between; padding: 15px; @@ -32,3 +32,17 @@ .buttonArea :not(:last-child) { margin-right: 10px; } + +.plusButton, +.xButton { + cursor: pointer; + fill: #bdbdbd; +} + +.plusButtonOver { + fill: #0075de; +} + +.xButtonOver { + fill: #ff4343; +} From c714fb33e8e2f89509091cb42c4a8fcdb4c3cf6f Mon Sep 17 00:00:00 2001 From: Sangjin Park <58503584+healtheloper@users.noreply.github.com> Date: Thu, 14 Apr 2022 15:38:16 +0900 Subject: [PATCH 2/8] =?UTF-8?q?[FE]=202=EC=A3=BC=EC=B0=A8=201=EB=B2=88?= =?UTF-8?q?=EC=A7=B8=20PR=20=EB=B0=98=EC=98=81=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=84=B0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * remove: 사용하지 않는 파일 삭제 * refactor: 상수 -> 대문자로 사용 * refactor: LOG_TYPE 대문자 변경에 따른 uppercase * refactor: Content components props * refactor: tag, innerHTML -> template 변수명 변경 * refactor: useRef & DOM API 사용 로직 제거 * refactor: tag, innerHTML -> template 변수명 변경 * refactor: create column element refactor --- front/.eslintrc.js | 1 + front/src/App.js | 5 +- front/src/common/constants.js | 8 +- front/src/common/domUtils.js | 6 -- .../Content/{Column => Columns}/Columns.js | 9 ++- .../{Column => Columns}/columns.module.css | 0 front/src/components/Content/Content.js | 5 +- .../components/SideContent/Action/Action.js | 7 +- .../src/components/SideContent/SideContent.js | 73 ++++++++++--------- front/src/core/peact.js | 13 +++- front/src/tagComponents/Button.js | 5 +- 11 files changed, 71 insertions(+), 61 deletions(-) delete mode 100644 front/src/common/domUtils.js rename front/src/components/Content/{Column => Columns}/Columns.js (84%) rename front/src/components/Content/{Column => Columns}/columns.module.css (100%) diff --git a/front/.eslintrc.js b/front/.eslintrc.js index 37b542264..6ecdbcff8 100644 --- a/front/.eslintrc.js +++ b/front/.eslintrc.js @@ -34,5 +34,6 @@ module.exports = { "import/prefer-default-export": "off", "func-names": "off", "no-underscore-dangle": ["error", { allow: ["_id"] }], + "no-param-reassign": "off", }, }; diff --git a/front/src/App.js b/front/src/App.js index 85b96b97e..1bfe40cae 100644 --- a/front/src/App.js +++ b/front/src/App.js @@ -1,4 +1,5 @@ import styles from "./App.module.css"; +import Columns from "./components/Content/Columns/Columns"; import Content from "./components/Content/Content"; import Header from "./components/Header/Header"; import SideContent from "./components/SideContent/SideContent"; @@ -35,10 +36,12 @@ const App = () => { fetchTodoLogs(); }, [renderFlag]); + const $columns = Columns({ columns, todos, handleRenderFlag }); + const $todoListArea = peact.createElement({ tag: "div", className: styles.todolistArea, - child: [Header(), Content({ columns, todos, handleRenderFlag })], + child: [Header(), Content({ content: $columns })], }); return peact.createElement({ diff --git a/front/src/common/constants.js b/front/src/common/constants.js index f3c6d0e1b..3f880b77f 100644 --- a/front/src/common/constants.js +++ b/front/src/common/constants.js @@ -1,6 +1,6 @@ export const LOG_TYPE = { - create: "등록", - delete: "삭제", - update: "변경", - move: "이동", + CREATE: "등록", + DELETE: "삭제", + UPDATE: "변경", + MOVE: "이동", }; diff --git a/front/src/common/domUtils.js b/front/src/common/domUtils.js deleted file mode 100644 index c3777b46b..000000000 --- a/front/src/common/domUtils.js +++ /dev/null @@ -1,6 +0,0 @@ -export const addEventAfterRender = ({ eventType, selector, callback }) => { - setTimeout(() => { - const $element = document.getElementById(selector); - $element.addEventListener(eventType, callback); - }, 0); -}; diff --git a/front/src/components/Content/Column/Columns.js b/front/src/components/Content/Columns/Columns.js similarity index 84% rename from front/src/components/Content/Column/Columns.js rename to front/src/components/Content/Columns/Columns.js index 6f9ba61e8..7856de209 100644 --- a/front/src/components/Content/Column/Columns.js +++ b/front/src/components/Content/Columns/Columns.js @@ -24,10 +24,11 @@ const Columns = ({ columns, todos, handleRenderFlag }) => { }); const createColumnElement = (column) => { - const $newCard = CardWritable({ handleNewCardVisibility }); - function handleNewCardVisibility() { - $newCard.classList.toggle(styles.visible); - } + const newCardRef = peact.useRef(); + const handleNewCardVisibility = () => { + newCardRef.current.classList.toggle(styles.visible); + }; + const $newCard = CardWritable({ handleNewCardVisibility, ref: newCardRef }); return peact.createElement({ tag: "div", diff --git a/front/src/components/Content/Column/columns.module.css b/front/src/components/Content/Columns/columns.module.css similarity index 100% rename from front/src/components/Content/Column/columns.module.css rename to front/src/components/Content/Columns/columns.module.css diff --git a/front/src/components/Content/Content.js b/front/src/components/Content/Content.js index 6adfa890b..66c076856 100644 --- a/front/src/components/Content/Content.js +++ b/front/src/components/Content/Content.js @@ -1,10 +1,9 @@ import peact from "../../core/peact"; -import Columns from "./Column/Columns"; -const Content = ({ columns, todos, handleRenderFlag }) => { +const Content = ({ content }) => { return peact.createElement({ tag: "div", - child: [Columns({ columns, todos, handleRenderFlag })], + child: [content], }); }; diff --git a/front/src/components/SideContent/Action/Action.js b/front/src/components/SideContent/Action/Action.js index 4205c2760..848a709b6 100644 --- a/front/src/components/SideContent/Action/Action.js +++ b/front/src/components/SideContent/Action/Action.js @@ -10,21 +10,22 @@ import styles from "./action.module.css"; const Action = ({ todoLog }) => { const { columnTitle, title, author, type } = todoLog; - const actionInnerHTML = ` + const actionTemplate = `
🥳

${author}

${columnTitle}${title}를 - ${LOG_TYPE[type]}하였습니다. + ${LOG_TYPE[type.toUpperCase()]}하였습니다.

1분 전

`; + return peact.createElement({ tag: "div", className: styles.action, - child: [actionInnerHTML], + child: [actionTemplate], }); }; diff --git a/front/src/components/SideContent/SideContent.js b/front/src/components/SideContent/SideContent.js index b5c825259..e17585358 100644 --- a/front/src/components/SideContent/SideContent.js +++ b/front/src/components/SideContent/SideContent.js @@ -3,7 +3,7 @@ import Button from "../../tagComponents/Button"; import Action from "./Action/Action"; import styles from "./sideContent.module.css"; -const menuBtnTag = ` +const menuBtnImageTemplate = ` `; -const closeBtnTag = ` +const closeBtnImageTemplate = ` `; +const toggleSideContent = (elements) => { + elements.forEach(({ elementRef, className }) => { + const element = elementRef.current; + element.classList.toggle(className); + }); +}; + const SideContent = ({ todoLogs, columns }) => { + const actionsRef = peact.useRef(); + const menuBtnRef = peact.useRef(); + const closeBtnRef = peact.useRef(); + const newTodoLogs = todoLogs.map((todoLog) => { const column = columns?.find((col) => col._id === todoLog.columnId); return { ...todoLog, columnTitle: column?.title }; }); + const toggleElements = [ + { elementRef: actionsRef, className: styles.active }, + { elementRef: menuBtnRef, className: styles.btnActive }, + ]; + + const handleClickMenuBtn = () => { + toggleSideContent(toggleElements); + }; + + const handleClickCloseBtn = () => { + toggleSideContent(toggleElements); + }; + const $actionsWrap = peact.createElement({ tag: "div", className: styles.actionWrap, child: newTodoLogs.map((todoLog) => Action({ todoLog })), }); - const toggleSideContent = (elements) => { - elements.forEach(({ element, className }) => { - element.classList.toggle(className); - }); - }; - - const handleCloseBtn = ({ target }) => { - const $closeBtn = target.closest(`.${styles.closeBtn}`); - const $actions = $closeBtn.parentNode; - const $menuBtn = $actions.parentNode.querySelector(`.${styles.menuBtn}`); - const elements = [ - { element: $actions, className: styles.active }, - { element: $menuBtn, className: styles.btnActive }, - ]; - toggleSideContent(elements); - }; - const $closeBtn = Button({ className: styles.closeBtn, - onClick: handleCloseBtn, - innerHTML: closeBtnTag, + onClick: handleClickCloseBtn, + innerHTML: closeBtnImageTemplate, + ref: closeBtnRef, + }); + + const $menuBtn = Button({ + className: [styles.menuBtn, styles.btnActive], + onClick: handleClickMenuBtn, + innerHTML: menuBtnImageTemplate, + ref: menuBtnRef, }); const $actions = peact.createElement({ tag: "div", className: styles.actions, child: [$actionsWrap, $closeBtn], - }); - - const handleMenuBtn = ({ target }) => { - const $menuBtn = target.closest(`.${styles.menuBtn}`); - const elements = [ - { element: $actions, className: styles.active }, - { element: $menuBtn, className: styles.btnActive }, - ]; - toggleSideContent(elements); - }; - - const $menuBtn = Button({ - className: [styles.menuBtn, styles.btnActive], - onClick: handleMenuBtn, - innerHTML: menuBtnTag, + ref: actionsRef, }); return peact.createElement({ diff --git a/front/src/core/peact.js b/front/src/core/peact.js index 7a278d694..3fa9519ef 100644 --- a/front/src/core/peact.js +++ b/front/src/core/peact.js @@ -22,7 +22,13 @@ const peact = (function () { $el.addEventListener(eventType.toLowerCase(), callback); }; - const createElement = ({ tag, id, className, attrs = null, child }) => { + const useRef = () => { + return { + current: null, + }; + }; + + const createElement = ({ tag, id, ref, className, attrs = null, child }) => { const $element = document.createElement(tag); if (id) { $element.id = id; @@ -50,6 +56,9 @@ const peact = (function () { $element.appendChild(childElement); }); } + if (ref) { + ref.current = $element; + } return $element; }; @@ -98,7 +107,7 @@ const peact = (function () { return [value, setValue]; }; - return { setRoot, useState, useEffect, render, createElement }; + return { setRoot, useState, useEffect, render, createElement, useRef }; })(); export default peact; diff --git a/front/src/tagComponents/Button.js b/front/src/tagComponents/Button.js index f1315fb2e..96e63a740 100644 --- a/front/src/tagComponents/Button.js +++ b/front/src/tagComponents/Button.js @@ -1,13 +1,14 @@ import peact from "../core/peact"; import { useId } from "../hooks/useId"; -const Button = ({ onClick, className, innerHTML }) => { +const Button = ({ onClick, className, innerHTML, ref, ...rest }) => { const id = useId("button"); return peact.createElement({ tag: "button", id, className, - attrs: { onClick }, + ref, + attrs: { onClick, ...rest }, child: [innerHTML], }); }; From a0442961b76a59112e555e8f08497a1fc9fb0171 Mon Sep 17 00:00:00 2001 From: Sangjin Park <58503584+healtheloper@users.noreply.github.com> Date: Thu, 14 Apr 2022 18:41:13 +0900 Subject: [PATCH 3/8] =?UTF-8?q?[FE]=20date=20utils=20&=20actions=20?= =?UTF-8?q?=EC=8B=9C=EA=B0=84=20=EC=B0=A8=EC=9D=B4=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: date utils & get date diff * feat: create getISODateDiff --- front/src/common/dateUtils.js | 55 +++++++++++++++++++ front/src/common/utils.js | 4 ++ .../components/SideContent/Action/Action.js | 10 +++- 3 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 front/src/common/dateUtils.js create mode 100644 front/src/common/utils.js diff --git a/front/src/common/dateUtils.js b/front/src/common/dateUtils.js new file mode 100644 index 000000000..780507677 --- /dev/null +++ b/front/src/common/dateUtils.js @@ -0,0 +1,55 @@ +const { pipe } = require("./utils"); + +export const getISODateDiff = (aISODate, bISODate) => { + return new Date(aISODate) - new Date(bISODate); +}; + +const getDateDiffInOrder = ({ prevDate, nextDate }) => { + return new Date(nextDate) - new Date(prevDate); +}; + +export const second = (s) => { + return s * 1000; +}; + +export const minute = (m) => { + return m * 60 * 1000; +}; + +export const hour = (h) => { + return h * 60 * 60 * 1000; +}; + +const diffToString = (date) => { + const dateSecond = Math.floor(date / 1000); + const dateMinute = Math.floor(dateSecond / 60); + const dateHour = Math.floor(dateMinute / 60); + const dateDay = Math.floor(dateHour / 24); + const dateMonth = Math.floor(dateDay / 30); + const dateYear = Math.floor(dateMonth / 12); + const dateValue = [ + dateYear, + dateMonth, + dateDay, + dateHour, + dateMinute, + dateSecond, + ]; + const dateUnit = ["년", "월", "일", "시간", "분", "초"]; + const biggestUnitIdx = dateValue.findIndex((value) => value !== 0); + return `${dateValue[biggestUnitIdx]} ${dateUnit[biggestUnitIdx]}전`; +}; + +export const getDateDiffFormat = ({ prev, next }) => { + return pipe( + getDateDiffInOrder, + diffToString + )({ prevDate: prev, nextDate: next }); +}; + +export const getMongoNow = () => { + const now = new Date(); + const mongoDiff = hour(9); + const mongoNow = new Date(now - mongoDiff); + return mongoNow.toISOString(); +}; diff --git a/front/src/common/utils.js b/front/src/common/utils.js new file mode 100644 index 000000000..b1c784576 --- /dev/null +++ b/front/src/common/utils.js @@ -0,0 +1,4 @@ +export const pipe = + (...fns) => + (value) => + fns.reduce((result, fn) => fn(result), value); diff --git a/front/src/components/SideContent/Action/Action.js b/front/src/components/SideContent/Action/Action.js index 848a709b6..5fb3a09dc 100644 --- a/front/src/components/SideContent/Action/Action.js +++ b/front/src/components/SideContent/Action/Action.js @@ -1,4 +1,5 @@ import { LOG_TYPE } from "../../../common/constants"; +import { getDateDiffFormat, getMongoNow } from "../../../common/dateUtils"; import peact from "../../../core/peact"; import styles from "./action.module.css"; @@ -8,7 +9,12 @@ import styles from "./action.module.css"; */ const Action = ({ todoLog }) => { - const { columnTitle, title, author, type } = todoLog; + const { columnTitle, title, author, type, createdAt } = todoLog; + const currentTime = getMongoNow(); + const dateDiff = getDateDiffFormat({ + prev: createdAt, + next: currentTime, + }); const actionTemplate = `
🥳
@@ -18,7 +24,7 @@ const Action = ({ todoLog }) => { ${columnTitle}${title}${LOG_TYPE[type.toUpperCase()]}하였습니다.

-

1분 전

+

${dateDiff}

`; From 07ee231c6a19cde0d48d17317838c041cf593f48 Mon Sep 17 00:00:00 2001 From: Sangjin Park <58503584+healtheloper@users.noreply.github.com> Date: Thu, 14 Apr 2022 21:57:30 +0900 Subject: [PATCH 4/8] =?UTF-8?q?[Park]=20webpack=20devtool=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EB=B0=98=EB=8C=80=EB=A1=9C=20=EB=90=98=EC=96=B4?= =?UTF-8?q?=EC=9E=88=EB=8D=98=20=EA=B2=83=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: webpack devtoom 설정 반대로되어있던 것 수정 * style: console 삭제 --- front/src/components/Content/Card/Card.js | 4 +++- front/src/components/Content/CardWritable/CardWritable.js | 3 ++- front/webpack.config.js | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/front/src/components/Content/Card/Card.js b/front/src/components/Content/Card/Card.js index ccbc5f1e0..497a3bc06 100644 --- a/front/src/components/Content/Card/Card.js +++ b/front/src/components/Content/Card/Card.js @@ -79,7 +79,7 @@ const Card = ({ todo, handleRenderFlag }) => { child: [todo.author], }); - return peact.createElement({ + const $card = peact.createElement({ tag: "div", className: styles.card, attrs: { @@ -87,6 +87,8 @@ const Card = ({ todo, handleRenderFlag }) => { }, child: [$cardHeaderArea, $cardContent, $cardAuthor], }); + + return $card; }; export default Card; diff --git a/front/src/components/Content/CardWritable/CardWritable.js b/front/src/components/Content/CardWritable/CardWritable.js index 88c93f2d7..009826e0c 100644 --- a/front/src/components/Content/CardWritable/CardWritable.js +++ b/front/src/components/Content/CardWritable/CardWritable.js @@ -2,7 +2,7 @@ import peact from "../../../core/peact"; import Button from "../../../tagComponents/Button"; import styles from "./cardWritable.module.css"; -const CardWritable = ({ handleNewCardVisibility }) => { +const CardWritable = ({ handleNewCardVisibility, ref }) => { const $inputDesc = peact.createElement({ tag: "input", className: styles.cardDescInput, @@ -54,6 +54,7 @@ const CardWritable = ({ handleNewCardVisibility }) => { tag: "div", className: [styles.cardWritable], child: [$cardWritableHeader, $inputDesc, $buttonArea], + ref, }); }; diff --git a/front/webpack.config.js b/front/webpack.config.js index 926ae27e6..4bfffe403 100644 --- a/front/webpack.config.js +++ b/front/webpack.config.js @@ -52,6 +52,6 @@ module.exports = (env) => { }, ], }, - ...(isDeploy ? { devtool: "source-map" } : {}), + ...(isDeploy ? {} : { devtool: "source-map" }), }; }; From 020409997064312f0861ed3a9e1406a76392d2e9 Mon Sep 17 00:00:00 2001 From: Sangjin Park <58503584+healtheloper@users.noreply.github.com> Date: Fri, 15 Apr 2022 02:41:48 +0900 Subject: [PATCH 5/8] =?UTF-8?q?[Park]=20=EC=B9=B4=EB=93=9C=20=EB=8D=94?= =?UTF-8?q?=EB=B8=94=ED=81=B4=EB=A6=AD=20=EC=8B=9C=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?=EA=B0=80=EB=8A=A5,=20=EC=88=98=EC=A0=95=20=EC=9A=94=EC=B2=AD?= =?UTF-8?q?=20=EB=B3=B4=EB=82=B4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: update card use double click * style: input value 없을 때 등록버튼 비활성화 * refactor: inline 으로 css 조작하던 방식 리팩터링 * style: confirm button 안쓰는 클래스 삭제 --- back/src/middlewares/cors.js | 4 ++ front/src/common/dateUtils.js | 2 + front/src/components/Content/Card/Card.js | 4 +- .../components/Content/Card/card.module.css | 4 ++ .../Content/CardWritable/CardWritable.js | 65 ++++++++++++++++--- .../CardWritable/cardWritable.module.css | 12 ++-- front/src/components/Content/Cards/Cards.js | 65 +++++++++++++++++-- .../components/Content/Cards/cards.module.css | 6 +- front/src/core/peact.js | 2 +- front/src/service/todoApi.js | 6 +- 10 files changed, 144 insertions(+), 26 deletions(-) diff --git a/back/src/middlewares/cors.js b/back/src/middlewares/cors.js index 8cef89bd0..c841afbdd 100644 --- a/back/src/middlewares/cors.js +++ b/back/src/middlewares/cors.js @@ -11,6 +11,10 @@ const cors = (req, res, next) => { key: "Access-Control-Allow-Methods", value: isProduction ? SERVICE_DOMAIN : "*", }, + { + key: "Access-Control-Allow-Headers", + value: isProduction ? SERVICE_DOMAIN : "*", + }, ]; accessControls.forEach((control) => { const { key, value } = control; diff --git a/front/src/common/dateUtils.js b/front/src/common/dateUtils.js index 780507677..45c917aad 100644 --- a/front/src/common/dateUtils.js +++ b/front/src/common/dateUtils.js @@ -21,6 +21,8 @@ export const hour = (h) => { }; const diffToString = (date) => { + if (date < 1000) return "방금 전"; + const dateSecond = Math.floor(date / 1000); const dateMinute = Math.floor(dateSecond / 60); const dateHour = Math.floor(dateMinute / 60); diff --git a/front/src/components/Content/Card/Card.js b/front/src/components/Content/Card/Card.js index 497a3bc06..97198506b 100644 --- a/front/src/components/Content/Card/Card.js +++ b/front/src/components/Content/Card/Card.js @@ -2,7 +2,7 @@ import peact from "../../../core/peact"; import Modal from "../../Modal/Modal"; import styles from "./card.module.css"; -const Card = ({ todo, handleRenderFlag }) => { +const Card = ({ todo, handleRenderFlag, handleDoubleClickCard, ref }) => { const showAlert = ({ todoId }) => { const $body = document.querySelector("body"); $body.append(Modal({ todoId, handleRenderFlag })); @@ -84,8 +84,10 @@ const Card = ({ todo, handleRenderFlag }) => { className: styles.card, attrs: { id: todo._id, + onDblClick: handleDoubleClickCard, }, child: [$cardHeaderArea, $cardContent, $cardAuthor], + ref, }); return $card; diff --git a/front/src/components/Content/Card/card.module.css b/front/src/components/Content/Card/card.module.css index cc2f79521..6b8c22f78 100644 --- a/front/src/components/Content/Card/card.module.css +++ b/front/src/components/Content/Card/card.module.css @@ -51,3 +51,7 @@ font-size: 12px; color: var(--dark-gray); } + +.hide { + display: none; +} diff --git a/front/src/components/Content/CardWritable/CardWritable.js b/front/src/components/Content/CardWritable/CardWritable.js index 009826e0c..d156755e5 100644 --- a/front/src/components/Content/CardWritable/CardWritable.js +++ b/front/src/components/Content/CardWritable/CardWritable.js @@ -2,15 +2,55 @@ import peact from "../../../core/peact"; import Button from "../../../tagComponents/Button"; import styles from "./cardWritable.module.css"; -const CardWritable = ({ handleNewCardVisibility, ref }) => { +const activateButton = ($button, deactiveClassName) => { + $button.removeAttribute("disabled"); + $button.classList.remove(deactiveClassName); +}; + +const deactivateButton = ($button, deactiveClassName) => { + $button.setAttribute("disabled", ""); + $button.classList.add(deactiveClassName); +}; + +const CardWritable = ({ + handleNewCardVisibility, + handleSubmitForm, + inputValues, + ref, +}) => { + const addButtonRef = peact.useRef(); + + const handleKeyUpInput = ({ target }) => { + const $addButton = addButtonRef.current; + const isInputEmpty = target.value === ""; + const isInputActive = !$addButton.classList.contains(styles.deactiveButton); + if (isInputEmpty && isInputActive) { + deactivateButton($addButton, styles.deactiveButton); + } else if (!isInputActive) { + activateButton($addButton, styles.deactiveButton); + } + }; + + const $inputAuthor = peact.createElement({ + tag: "input", + className: styles.author, + attrs: { + value: inputValues ? inputValues.author : "", + type: "hidden", + name: "author", + }, + child: [], + }); + const $inputDesc = peact.createElement({ tag: "input", className: styles.cardDescInput, attrs: { - value: "", + value: inputValues ? inputValues.desc : "", type: "text", - name: "card-content", + name: "desc", placeholder: "내용을 입력하세요", + onKeyUp: handleKeyUpInput, }, child: [], }); @@ -19,10 +59,11 @@ const CardWritable = ({ handleNewCardVisibility, ref }) => { tag: "input", className: styles.cardTitleInput, attrs: { - value: "", + value: inputValues ? inputValues.title : "", type: "text", - name: "card-title", + name: "title", placeholder: "제목을 입력하세요", + onKeyUp: handleKeyUpInput, }, child: [], }); @@ -37,11 +78,14 @@ const CardWritable = ({ handleNewCardVisibility, ref }) => { onClick: handleNewCardVisibility, className: [styles.button, styles.cancelButton], innerHTML: "취소", + type: "button", }); const $confirmButton = Button({ - className: [styles.button, styles.confirmButton, styles.activeButton], + className: [styles.button, styles.confirmButton], innerHTML: "등록", + type: "submit", + ref: addButtonRef, }); const $buttonArea = peact.createElement({ @@ -51,9 +95,12 @@ const CardWritable = ({ handleNewCardVisibility, ref }) => { }); return peact.createElement({ - tag: "div", - className: [styles.cardWritable], - child: [$cardWritableHeader, $inputDesc, $buttonArea], + tag: "form", + className: styles.cardWritable, + attrs: { + onSubmit: handleSubmitForm, + }, + child: [$inputAuthor, $cardWritableHeader, $inputDesc, $buttonArea], ref, }); }; diff --git a/front/src/components/Content/CardWritable/cardWritable.module.css b/front/src/components/Content/CardWritable/cardWritable.module.css index 7021e2214..12f1333fd 100644 --- a/front/src/components/Content/CardWritable/cardWritable.module.css +++ b/front/src/components/Content/CardWritable/cardWritable.module.css @@ -57,14 +57,14 @@ .confirmButton { font-weight: 700; font-size: 14px; - color: rgba(255, 255, 255, 0.4); - opacity: 0.5; - background: #86c6ff; + color: #fff; + background: #0075de; border: 0; border-radius: 6px; } -.activeButton { - color: #fff; - background: #0075de; +.deactiveButton { + cursor: default; + color: rgba(255, 255, 255, 0.4); + background: #86c6ff; } diff --git a/front/src/components/Content/Cards/Cards.js b/front/src/components/Content/Cards/Cards.js index c0be3ce7f..bc48949b4 100644 --- a/front/src/components/Content/Cards/Cards.js +++ b/front/src/components/Content/Cards/Cards.js @@ -1,24 +1,77 @@ import peact from "../../../core/peact"; +import todoApi from "../../../service/todoApi"; import Card from "../Card/Card"; +import cardStyles from "../Card/card.module.css"; +import CardWritable from "../CardWritable/CardWritable"; import styles from "./cards.module.css"; const Cards = ({ $newCard, todos, handleRenderFlag }) => { + const cardsRef = peact.useRef(); const setTodosSortByLatest = (a, b) => new Date(b.updatedAt) - new Date(a.updatedAt); - const getCardsTemplate = (todo) => { - return peact.createElement({ - tag: "div", - className: styles.cardsArea, - child: [Card({ todo, handleRenderFlag })], + const getCard = (todo) => { + const cardRef = peact.useRef(); + const cardWritableRef = peact.useRef(); + + const handleNewCardVisibility = () => { + cardsRef.current.removeChild(cardWritableRef.current); + cardRef.current.classList.toggle(cardStyles.hide); + }; + + const handleSubmitForm = async (event) => { + event.preventDefault(); + const { title, desc, author } = event.target; + const requestBody = { + title: title.value, + desc: desc.value, + author: author.value, + }; + await todoApi.updateTodo(todo._id, requestBody); + cardsRef.current.removeChild(cardWritableRef.current); + handleRenderFlag(); + }; + + const handleDoubleClickCard = () => { + const $card = cardRef.current; + const $title = $card.querySelector(`.${cardStyles.title}`); + const $desc = $card.querySelector(`.${cardStyles.cardContent}`); + const $author = $card.querySelector(`.${cardStyles.author}`); + + const inputValues = { + title: $title.textContent, + desc: $desc.textContent, + author: $author.textContent, + }; + + const $cardWritable = CardWritable({ + handleNewCardVisibility, + handleSubmitForm, + inputValues, + ref: cardWritableRef, + }); + // TODO: CardWritable 만들 때 display 속성 props 로 넘겨서 만드는게 좋을 듯 + $cardWritable.style.display = "flex"; + // + cardsRef.current.insertBefore($cardWritable, $card); + $card.classList.toggle(cardStyles.hide); + }; + + return Card({ + todo, + handleRenderFlag, + handleDoubleClickCard, + ref: cardRef, }); }; - const todoElements = todos.sort(setTodosSortByLatest).map(getCardsTemplate); + const todoElements = todos.sort(setTodosSortByLatest).map(getCard); return peact.createElement({ tag: "div", + className: styles.cards, child: [$newCard, ...todoElements], + ref: cardsRef, }); }; diff --git a/front/src/components/Content/Cards/cards.module.css b/front/src/components/Content/Cards/cards.module.css index 9e5173543..d946d5179 100644 --- a/front/src/components/Content/Cards/cards.module.css +++ b/front/src/components/Content/Cards/cards.module.css @@ -1,4 +1,8 @@ -.cardsArea { +.cards { max-height: calc(100vh - 190px); overflow: auto; } + +.cardWritableVisible { + display: flex; +} diff --git a/front/src/core/peact.js b/front/src/core/peact.js index 3fa9519ef..fe1daa2d6 100644 --- a/front/src/core/peact.js +++ b/front/src/core/peact.js @@ -38,7 +38,7 @@ const peact = (function () { } if (attrs) { Object.entries(attrs).forEach(([key, value]) => { - if (key.includes("on")) { + if (key.slice(0, 2) === "on") { addEvent($element, key, value); } else { $element.setAttribute(key, value); diff --git a/front/src/service/todoApi.js b/front/src/service/todoApi.js index 7858b429a..8d844ca99 100644 --- a/front/src/service/todoApi.js +++ b/front/src/service/todoApi.js @@ -9,14 +9,16 @@ const client = axios.create({ const todoApi = { getTodos: async () => { const response = await client.get(); - return response.data.results; }, - deleteTodo: async (id) => { const response = await client.delete(`delete/${id}`); return response.data.results; }, + updateTodo: async (todoId, updateData) => { + const response = await client.patch(`update/${todoId}`, updateData); + return response.data.results; + }, }; export default todoApi; From e54e4361feacefb88a5d690cbbef0ba1c457bdf7 Mon Sep 17 00:00:00 2001 From: BB-choi <78826879+BB-choi@users.noreply.github.com> Date: Fri, 15 Apr 2022 11:16:50 +0900 Subject: [PATCH 6/8] =?UTF-8?q?[BB]=20=EC=83=88=EB=A1=9C=EC=9A=B4=20?= =?UTF-8?q?=EC=B9=B4=EB=93=9C=20=EB=93=B1=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 불분명한 함수명, 변수명 변경 - 카드 등록 버튼 $addButton으로 변경 - 칼럼header의 +, x버튼 hover 핸들러 handleButtonHover로 변경 * feat: newCard 생성시 등록버튼 비활성 스타일 * feat: post 새로운 카드 등록하기 * fix: 처음 $newCard가 표시되면 submit 버튼 disabled처리 * fix: Fix a typo * refactor: 함수명, 변수명 등 불확실한 이름을 변경 - id -> columnId - putTodo -> createTodo * fix: handleKeyUpInput에 빠졌던 조건 추가 - else if()의 조건에 !isInputEmpty 추가 * refactor: plusButton, deleteButton 핸들러 리팩토링 - xButton, deleteButton 이름이 혼재 되어있던 것도 deleteButton으로 통합 * refactor: handleNewCardVisibl~을 toggleCardVisible로 변경 * refactor: $plusButton 클릭 이벤트 핸들러 추가 - $plusButton이벤트 핸들러간 네이밍 통일 handle~PlusButton --- .../Content/CardWritable/CardWritable.js | 26 ++++++++++---- .../CardWritable/cardWritable.module.css | 2 +- front/src/components/Content/Cards/Cards.js | 4 +-- .../Content/ColumnHeader/ColumnHeader.js | 31 ++++++++++------ .../ColumnHeader/columnHeader.module.css | 6 ++-- .../src/components/Content/Columns/Columns.js | 36 ++++++++++++++++--- front/src/service/todoApi.js | 4 +++ 7 files changed, 81 insertions(+), 28 deletions(-) diff --git a/front/src/components/Content/CardWritable/CardWritable.js b/front/src/components/Content/CardWritable/CardWritable.js index d156755e5..07d9f5ea4 100644 --- a/front/src/components/Content/CardWritable/CardWritable.js +++ b/front/src/components/Content/CardWritable/CardWritable.js @@ -13,9 +13,10 @@ const deactivateButton = ($button, deactiveClassName) => { }; const CardWritable = ({ - handleNewCardVisibility, + toggleCardVisible, handleSubmitForm, inputValues, + columnId, ref, }) => { const addButtonRef = peact.useRef(); @@ -26,7 +27,7 @@ const CardWritable = ({ const isInputActive = !$addButton.classList.contains(styles.deactiveButton); if (isInputEmpty && isInputActive) { deactivateButton($addButton, styles.deactiveButton); - } else if (!isInputActive) { + } else if (!isInputEmpty && !isInputActive) { activateButton($addButton, styles.deactiveButton); } }; @@ -75,29 +76,40 @@ const CardWritable = ({ }); const $cancelButton = Button({ - onClick: handleNewCardVisibility, + onClick: toggleCardVisible, className: [styles.button, styles.cancelButton], innerHTML: "취소", type: "button", }); - const $confirmButton = Button({ - className: [styles.button, styles.confirmButton], + const addButtonProps = { + className: [styles.button, styles.addButton], innerHTML: "등록", type: "submit", ref: addButtonRef, - }); + }; + + if (!inputValues) { + addButtonProps.className = [ + ...addButtonProps.className, + styles.deactiveButton, + ]; + addButtonProps.disabled = ""; + } + + const $addButton = Button(addButtonProps); const $buttonArea = peact.createElement({ tag: "div", className: styles.buttons, - child: [$cancelButton, $confirmButton], + child: [$cancelButton, $addButton], }); return peact.createElement({ tag: "form", className: styles.cardWritable, attrs: { + "data-column-id": columnId, onSubmit: handleSubmitForm, }, child: [$inputAuthor, $cardWritableHeader, $inputDesc, $buttonArea], diff --git a/front/src/components/Content/CardWritable/cardWritable.module.css b/front/src/components/Content/CardWritable/cardWritable.module.css index 12f1333fd..0168e28c2 100644 --- a/front/src/components/Content/CardWritable/cardWritable.module.css +++ b/front/src/components/Content/CardWritable/cardWritable.module.css @@ -54,7 +54,7 @@ border-radius: 6px; } -.confirmButton { +.addButton { font-weight: 700; font-size: 14px; color: #fff; diff --git a/front/src/components/Content/Cards/Cards.js b/front/src/components/Content/Cards/Cards.js index bc48949b4..29c71ff29 100644 --- a/front/src/components/Content/Cards/Cards.js +++ b/front/src/components/Content/Cards/Cards.js @@ -14,7 +14,7 @@ const Cards = ({ $newCard, todos, handleRenderFlag }) => { const cardRef = peact.useRef(); const cardWritableRef = peact.useRef(); - const handleNewCardVisibility = () => { + const toggleCardVisible = () => { cardsRef.current.removeChild(cardWritableRef.current); cardRef.current.classList.toggle(cardStyles.hide); }; @@ -45,7 +45,7 @@ const Cards = ({ $newCard, todos, handleRenderFlag }) => { }; const $cardWritable = CardWritable({ - handleNewCardVisibility, + toggleCardVisible, handleSubmitForm, inputValues, ref: cardWritableRef, diff --git a/front/src/components/Content/ColumnHeader/ColumnHeader.js b/front/src/components/Content/ColumnHeader/ColumnHeader.js index b68586dc7..c9f1af18b 100644 --- a/front/src/components/Content/ColumnHeader/ColumnHeader.js +++ b/front/src/components/Content/ColumnHeader/ColumnHeader.js @@ -1,10 +1,21 @@ import peact from "../../../core/peact"; import styles from "./columnHeader.module.css"; -const ColumnHeader = ({ column, todos, handleNewCardVisibility }) => { - const handleButtonOverOut = (target, buttonName) => { - const targetButton = target.closest(`.${styles[buttonName]}`) || target; - targetButton.classList.toggle(styles[`${buttonName}Over`]); +const ColumnHeader = ({ column, todos, toggleCardVisible }) => { + const hoverButton = ($button, className) => { + $button.classList.toggle(className); + }; + + const handleHoverPlusButton = () => { + hoverButton($plusButton, styles.plusButtonHover); + }; + + const handleHoverDeleteButton = () => { + hoverButton($deleteButton, styles.deleteButtonHover); + }; + + const handleClickPlusButton = () => { + toggleCardVisible(); }; const todosCount = todos.length; @@ -26,9 +37,9 @@ const ColumnHeader = ({ column, todos, handleNewCardVisibility }) => { tag: "div", className: styles.plusButton, attrs: { - onMouseOver: ({ target }) => handleButtonOverOut(target, "plusButton"), - onMouseOut: ({ target }) => handleButtonOverOut(target, "plusButton"), - onClick: handleNewCardVisibility, + onMouseOver: handleHoverPlusButton, + onMouseOut: handleHoverPlusButton, + onClick: handleClickPlusButton, }, child: [plusButtonImgTemplate], }); @@ -40,10 +51,10 @@ const ColumnHeader = ({ column, todos, handleNewCardVisibility }) => { const $deleteButton = peact.createElement({ tag: "div", - className: styles.xButton, + className: styles.deleteButton, attrs: { - onMouseOver: ({ target }) => handleButtonOverOut(target, "xButton"), - onMouseOut: ({ target }) => handleButtonOverOut(target, "xButton"), + onMouseOver: handleHoverDeleteButton, + onMouseOut: handleHoverDeleteButton, }, child: [deleteButtonImgTemplate], }); diff --git a/front/src/components/Content/ColumnHeader/columnHeader.module.css b/front/src/components/Content/ColumnHeader/columnHeader.module.css index 5e00db714..a1438aae3 100644 --- a/front/src/components/Content/ColumnHeader/columnHeader.module.css +++ b/front/src/components/Content/ColumnHeader/columnHeader.module.css @@ -34,15 +34,15 @@ } .plusButton, -.xButton { +.deleteButton { cursor: pointer; fill: #bdbdbd; } -.plusButtonOver { +.plusButtonHover { fill: #0075de; } -.xButtonOver { +.deleteButtonHover { fill: #ff4343; } diff --git a/front/src/components/Content/Columns/Columns.js b/front/src/components/Content/Columns/Columns.js index 7856de209..51e0fdea4 100644 --- a/front/src/components/Content/Columns/Columns.js +++ b/front/src/components/Content/Columns/Columns.js @@ -1,4 +1,5 @@ import peact from "../../../core/peact"; +import todoApi from "../../../service/todoApi"; import Cards from "../Cards/Cards"; import CardWritable from "../CardWritable/CardWritable"; import ColumnHeader from "../ColumnHeader/ColumnHeader"; @@ -9,11 +10,11 @@ const Columns = ({ columns, todos, handleRenderFlag }) => { return todos.filter((todo) => todo.columnId === columnId); }; - const createColumnHeaderElement = ({ column, handleNewCardVisibility }) => + const createColumnHeaderElement = ({ column, toggleCardVisible }) => ColumnHeader({ column, todos: getTodosByColumnId(column._id), - handleNewCardVisibility, + toggleCardVisible, }); const createCardsElement = ({ $newCard, column }) => @@ -23,18 +24,43 @@ const Columns = ({ columns, todos, handleRenderFlag }) => { handleRenderFlag, }); + const handleSubmitForm = async (event) => { + event.preventDefault(); + const { + title, + desc, + author, + dataset: { columnId }, + } = event.target; + + const requestBody = { + title: title.value, + desc: desc.value, + author: author.value, + columnId, + }; + + await todoApi.createTodo(requestBody); + handleRenderFlag(); + }; + const createColumnElement = (column) => { const newCardRef = peact.useRef(); - const handleNewCardVisibility = () => { + const toggleCardVisible = () => { newCardRef.current.classList.toggle(styles.visible); }; - const $newCard = CardWritable({ handleNewCardVisibility, ref: newCardRef }); + const $newCard = CardWritable({ + toggleCardVisible, + ref: newCardRef, + handleSubmitForm, + columnId: column._id, + }); return peact.createElement({ tag: "div", className: styles.column, child: [ - createColumnHeaderElement({ column, handleNewCardVisibility }), + createColumnHeaderElement({ column, toggleCardVisible }), createCardsElement({ $newCard, column }), ], }); diff --git a/front/src/service/todoApi.js b/front/src/service/todoApi.js index 8d844ca99..ca83fdf69 100644 --- a/front/src/service/todoApi.js +++ b/front/src/service/todoApi.js @@ -19,6 +19,10 @@ const todoApi = { const response = await client.patch(`update/${todoId}`, updateData); return response.data.results; }, + createTodo: async (newData) => { + const response = await client.post(`create`, newData); + return response.data.results; + }, }; export default todoApi; From 592c2e5cc549e464a963fe7fefe83094052ff308 Mon Sep 17 00:00:00 2001 From: BB-choi <78826879+BB-choi@users.noreply.github.com> Date: Fri, 15 Apr 2022 12:05:49 +0900 Subject: [PATCH 7/8] =?UTF-8?q?[BB]=20=EB=A6=AC=EB=B7=B0=20PR=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81=20-=20Modal,?= =?UTF-8?q?=20Card?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: Cards.js에서 todos 정렬 함수 외부로 분리 - dateUtils 사용하여 분리 * refactor: Card.js 불필요한 함수 삭제 - onMouseOver, onMouseOut 등 불필요한 함수 삭제 * refactor: modal 핸들러 함수 위치 변경 - App에서 state로 관리하도록 변경 - columns를 App에서 생성하므로 App에서 state로 관리 - 선택된id를 state로 관리하므로 re-rendering으로 인해 클래스 토글이 아닌 state로 모달 표시 여부 결정 * feat: 카드 삭제 / 모달 팝업 닫을 때 선택된 id 리셋 * fix: x 버튼 hover시 cursor 범위 오류 해결 * fix: PR confilct 해결 * refactor: SideContent 최신순 정렬 * refactor: PR리뷰 반영 --- front/src/App.js | 40 ++++++++++++++++++- front/src/components/Content/Card/Card.js | 31 +++++--------- .../components/Content/Card/card.module.css | 2 +- .../Content/CardWritable/CardWritable.js | 2 +- front/src/components/Content/Cards/Cards.js | 18 +++++---- .../Content/ColumnHeader/ColumnHeader.js | 7 ++++ .../src/components/Content/Columns/Columns.js | 6 +-- front/src/components/Modal/Modal.js | 28 ++++++------- front/src/components/Modal/modal.module.css | 5 +++ .../components/SideContent/Action/Action.js | 2 +- .../src/components/SideContent/SideContent.js | 22 +++++++--- 11 files changed, 108 insertions(+), 55 deletions(-) diff --git a/front/src/App.js b/front/src/App.js index 1bfe40cae..2a18a24a0 100644 --- a/front/src/App.js +++ b/front/src/App.js @@ -2,6 +2,7 @@ import styles from "./App.module.css"; import Columns from "./components/Content/Columns/Columns"; import Content from "./components/Content/Content"; import Header from "./components/Header/Header"; +import Modal from "./components/Modal/Modal"; import SideContent from "./components/SideContent/SideContent"; import peact from "./core/peact"; import columnApi from "./service/columnApi"; @@ -13,11 +14,23 @@ const App = () => { const [columns, setColumns] = peact.useState([]); const [todoLogs, setTodoLogs] = peact.useState([]); const [renderFlag, setRenderFlag] = peact.useState(false); + const [selectedTodoId, setSelectedTodoId] = peact.useState(null); + const [isModalVisible, setIsModalVisible] = peact.useState(false); + + const modalRef = peact.useRef(); const handleRenderFlag = () => { setRenderFlag(!renderFlag); }; + const handleModalVisibility = () => { + setIsModalVisible(!isModalVisible); + }; + + const handleSelectedTodoId = (todoId) => { + setSelectedTodoId(todoId); + }; + peact.useEffect(() => { const fetchTodos = async () => { const newTodos = await todoApi.getTodos(); @@ -36,7 +49,30 @@ const App = () => { fetchTodoLogs(); }, [renderFlag]); - const $columns = Columns({ columns, todos, handleRenderFlag }); + const modalHandlers = { + handleRenderFlag, + handleSelectedTodoId, + handleModalVisibility, + }; + + const $modal = Modal({ + handlers: modalHandlers, + ref: modalRef, + isModalVisible, + selectedTodoId, + }); + + const columnsHandlers = { + handleRenderFlag, + handleSelectedTodoId, + handleModalVisibility, + }; + + const $columns = Columns({ + columns, + todos, + handlers: columnsHandlers, + }); const $todoListArea = peact.createElement({ tag: "div", @@ -47,7 +83,7 @@ const App = () => { return peact.createElement({ tag: "div", className: styles.wrap, - child: [$todoListArea, SideContent({ todoLogs, columns })], + child: [$todoListArea, SideContent({ todoLogs, columns }), $modal], }); }; diff --git a/front/src/components/Content/Card/Card.js b/front/src/components/Content/Card/Card.js index 97198506b..b1c18615a 100644 --- a/front/src/components/Content/Card/Card.js +++ b/front/src/components/Content/Card/Card.js @@ -1,14 +1,11 @@ import peact from "../../../core/peact"; -import Modal from "../../Modal/Modal"; import styles from "./card.module.css"; -const Card = ({ todo, handleRenderFlag, handleDoubleClickCard, ref }) => { - const showAlert = ({ todoId }) => { - const $body = document.querySelector("body"); - $body.append(Modal({ todoId, handleRenderFlag })); - }; +const Card = ({ todo, handlers, ref }) => { + const { handleSelectedTodoId, handleModalVisibility, handleDoubleClickCard } = + handlers; - const handleXButton = (target) => { + const handleXButtonHover = ({ target }) => { const $path = target.querySelector(`.${styles.path}`) || target; const $cardElement = target.closest(`.${styles.card}`); @@ -16,20 +13,13 @@ const Card = ({ todo, handleRenderFlag, handleDoubleClickCard, ref }) => { $cardElement.classList.toggle(styles.cardMouseOver); }; - const onXButtonOver = ({ target }) => { - handleXButton(target); - }; - - const onXButtonOut = ({ target }) => { - handleXButton(target); - }; - const onXButtonClick = ({ target }) => { const todoId = target.closest(`.${styles.card}`).id; - showAlert({ todoId }); + handleModalVisibility(); + handleSelectedTodoId(todoId); }; - const xButtonInnerHTML = ` + const xButtonImgTemplate = ` { const $xButtonWrap = peact.createElement({ tag: "div", + className: styles.xButtonWrap, attrs: { onClick: onXButtonClick, - onMouseOver: onXButtonOver, - onMouseOut: onXButtonOut, + onMouseOver: handleXButtonHover, + onMouseOut: handleXButtonHover, }, - child: [xButtonInnerHTML], + child: [xButtonImgTemplate], }); const $cardHeaderArea = peact.createElement({ diff --git a/front/src/components/Content/Card/card.module.css b/front/src/components/Content/Card/card.module.css index 6b8c22f78..6dd51c97e 100644 --- a/front/src/components/Content/Card/card.module.css +++ b/front/src/components/Content/Card/card.module.css @@ -23,7 +23,7 @@ line-height: 20px; } -.xButton { +.xButtonWrap { cursor: pointer; } diff --git a/front/src/components/Content/CardWritable/CardWritable.js b/front/src/components/Content/CardWritable/CardWritable.js index 07d9f5ea4..11b16529a 100644 --- a/front/src/components/Content/CardWritable/CardWritable.js +++ b/front/src/components/Content/CardWritable/CardWritable.js @@ -36,7 +36,7 @@ const CardWritable = ({ tag: "input", className: styles.author, attrs: { - value: inputValues ? inputValues.author : "", + value: inputValues ? inputValues.author : "비발디파크", type: "hidden", name: "author", }, diff --git a/front/src/components/Content/Cards/Cards.js b/front/src/components/Content/Cards/Cards.js index 29c71ff29..543e0eae7 100644 --- a/front/src/components/Content/Cards/Cards.js +++ b/front/src/components/Content/Cards/Cards.js @@ -1,3 +1,4 @@ +import { getISODateDiff } from "../../../common/dateUtils"; import peact from "../../../core/peact"; import todoApi from "../../../service/todoApi"; import Card from "../Card/Card"; @@ -5,12 +6,16 @@ import cardStyles from "../Card/card.module.css"; import CardWritable from "../CardWritable/CardWritable"; import styles from "./cards.module.css"; -const Cards = ({ $newCard, todos, handleRenderFlag }) => { +const getSortedDatabyLatest = (data) => { + return data.sort((a, b) => getISODateDiff(b.updatedAt, a.updatedAt)); +}; + +const Cards = ({ $newCard, todos, handlers }) => { + const { handleRenderFlag } = handlers; + const cardsRef = peact.useRef(); - const setTodosSortByLatest = (a, b) => - new Date(b.updatedAt) - new Date(a.updatedAt); - const getCard = (todo) => { + const createCard = (todo) => { const cardRef = peact.useRef(); const cardWritableRef = peact.useRef(); @@ -59,13 +64,12 @@ const Cards = ({ $newCard, todos, handleRenderFlag }) => { return Card({ todo, - handleRenderFlag, - handleDoubleClickCard, ref: cardRef, + handlers: { ...handlers, handleDoubleClickCard }, }); }; - const todoElements = todos.sort(setTodosSortByLatest).map(getCard); + const todoElements = getSortedDatabyLatest(todos).map(createCard); return peact.createElement({ tag: "div", diff --git a/front/src/components/Content/ColumnHeader/ColumnHeader.js b/front/src/components/Content/ColumnHeader/ColumnHeader.js index c9f1af18b..42e94abb8 100644 --- a/front/src/components/Content/ColumnHeader/ColumnHeader.js +++ b/front/src/components/Content/ColumnHeader/ColumnHeader.js @@ -2,15 +2,20 @@ import peact from "../../../core/peact"; import styles from "./columnHeader.module.css"; const ColumnHeader = ({ column, todos, toggleCardVisible }) => { + const plusButtonRef = peact.useRef(); + const deleteButtonRef = peact.useRef(); + const hoverButton = ($button, className) => { $button.classList.toggle(className); }; const handleHoverPlusButton = () => { + const $plusButton = plusButtonRef.current; hoverButton($plusButton, styles.plusButtonHover); }; const handleHoverDeleteButton = () => { + const $deleteButton = deleteButtonRef.current; hoverButton($deleteButton, styles.deleteButtonHover); }; @@ -41,6 +46,7 @@ const ColumnHeader = ({ column, todos, toggleCardVisible }) => { onMouseOut: handleHoverPlusButton, onClick: handleClickPlusButton, }, + ref: plusButtonRef, child: [plusButtonImgTemplate], }); @@ -56,6 +62,7 @@ const ColumnHeader = ({ column, todos, toggleCardVisible }) => { onMouseOver: handleHoverDeleteButton, onMouseOut: handleHoverDeleteButton, }, + ref: deleteButtonRef, child: [deleteButtonImgTemplate], }); diff --git a/front/src/components/Content/Columns/Columns.js b/front/src/components/Content/Columns/Columns.js index 51e0fdea4..4b3e4f1ea 100644 --- a/front/src/components/Content/Columns/Columns.js +++ b/front/src/components/Content/Columns/Columns.js @@ -5,7 +5,7 @@ import CardWritable from "../CardWritable/CardWritable"; import ColumnHeader from "../ColumnHeader/ColumnHeader"; import styles from "./columns.module.css"; -const Columns = ({ columns, todos, handleRenderFlag }) => { +const Columns = ({ columns, todos, handlers }) => { const getTodosByColumnId = (columnId) => { return todos.filter((todo) => todo.columnId === columnId); }; @@ -21,7 +21,7 @@ const Columns = ({ columns, todos, handleRenderFlag }) => { Cards({ $newCard, todos: getTodosByColumnId(column._id), - handleRenderFlag, + handlers, }); const handleSubmitForm = async (event) => { @@ -41,7 +41,7 @@ const Columns = ({ columns, todos, handleRenderFlag }) => { }; await todoApi.createTodo(requestBody); - handleRenderFlag(); + handlers.handleRenderFlag(); }; const createColumnElement = (column) => { diff --git a/front/src/components/Modal/Modal.js b/front/src/components/Modal/Modal.js index f3264a9e9..6d565390c 100644 --- a/front/src/components/Modal/Modal.js +++ b/front/src/components/Modal/Modal.js @@ -2,27 +2,24 @@ import peact from "../../core/peact"; import todoApi from "../../service/todoApi"; import styles from "./modal.module.css"; -const Modal = ({ todoId, handleRenderFlag }) => { - const hideAlert = () => { - const $body = document.querySelector("body"); - const $alert = $body.querySelector(`.${styles.modalWrap}`); - $body.removeChild($alert); - }; - - const onModalClick = ({ target }) => { - if (target.classList.contains(styles.modalWrap)) { - hideAlert(); - } - }; +const Modal = ({ handlers, isModalVisible, selectedTodoId, ref }) => { + const { handleRenderFlag, handleSelectedTodoId, handleModalVisibility } = + handlers; const deleteTodo = async () => { - const deletedTodo = await todoApi.deleteTodo(todoId); + const deletedTodo = await todoApi.deleteTodo(selectedTodoId); if (deletedTodo) { handleRenderFlag(); + handleSelectedTodoId(null); } }; + const onModalClick = () => { + handleModalVisibility(); + handleSelectedTodoId(null); + }; + const $modalPopupMessage = peact.createElement({ tag: "p", className: styles.alertMessage, @@ -33,7 +30,7 @@ const Modal = ({ todoId, handleRenderFlag }) => { tag: "button", className: styles.cancelButton, attrs: { - onClick: hideAlert, + onClick: handleModalVisibility, }, child: ["취소"], }); @@ -61,11 +58,12 @@ const Modal = ({ todoId, handleRenderFlag }) => { return peact.createElement({ tag: "div", - className: styles.modalWrap, + className: [styles.modalWrap, ...(isModalVisible ? [styles.visible] : [])], child: [$modalPopup], attrs: { onClick: onModalClick, }, + ref, }); }; diff --git a/front/src/components/Modal/modal.module.css b/front/src/components/Modal/modal.module.css index 345a32815..65bac02ad 100644 --- a/front/src/components/Modal/modal.module.css +++ b/front/src/components/Modal/modal.module.css @@ -1,4 +1,5 @@ .modalWrap { + display: none; position: absolute; top: 0; right: 0; @@ -56,3 +57,7 @@ background: #0075de; border-radius: 6px; } + +.visible { + display: block; +} diff --git a/front/src/components/SideContent/Action/Action.js b/front/src/components/SideContent/Action/Action.js index 5fb3a09dc..951302c32 100644 --- a/front/src/components/SideContent/Action/Action.js +++ b/front/src/components/SideContent/Action/Action.js @@ -19,7 +19,7 @@ const Action = ({ todoLog }) => { const actionTemplate = `
🥳
-

${author}

+

@${author}

${columnTitle}${title}${LOG_TYPE[type.toUpperCase()]}하였습니다. diff --git a/front/src/components/SideContent/SideContent.js b/front/src/components/SideContent/SideContent.js index e17585358..37f079c21 100644 --- a/front/src/components/SideContent/SideContent.js +++ b/front/src/components/SideContent/SideContent.js @@ -1,3 +1,5 @@ +import { getISODateDiff } from "../../common/dateUtils"; +import { pipe } from "../../common/utils"; import peact from "../../core/peact"; import Button from "../../tagComponents/Button"; import Action from "./Action/Action"; @@ -45,10 +47,20 @@ const SideContent = ({ todoLogs, columns }) => { const menuBtnRef = peact.useRef(); const closeBtnRef = peact.useRef(); - const newTodoLogs = todoLogs.map((todoLog) => { - const column = columns?.find((col) => col._id === todoLog.columnId); - return { ...todoLog, columnTitle: column?.title }; - }); + const insertColumnTitle = (todoLogs) => { + return todoLogs.map((todoLog) => { + const column = columns?.find((col) => col._id === todoLog.columnId); + return { ...todoLog, columnTitle: column?.title }; + }); + }; + + const sortTodoLogs = (todoLogs) => { + return todoLogs.sort((aTodo, bTodo) => + getISODateDiff(bTodo.createdAt, aTodo.createdAt) + ); + }; + + const sortedTodoLogs = pipe(insertColumnTitle, sortTodoLogs)(todoLogs); const toggleElements = [ { elementRef: actionsRef, className: styles.active }, @@ -66,7 +78,7 @@ const SideContent = ({ todoLogs, columns }) => { const $actionsWrap = peact.createElement({ tag: "div", className: styles.actionWrap, - child: newTodoLogs.map((todoLog) => Action({ todoLog })), + child: sortedTodoLogs.map((todoLog) => Action({ todoLog })), }); const $closeBtn = Button({ From 7125d446177c3739f0f31d60332a09e0475ce048 Mon Sep 17 00:00:00 2001 From: Sangjin Park <58503584+healtheloper@users.noreply.github.com> Date: Fri, 15 Apr 2022 14:59:05 +0900 Subject: [PATCH 8/8] =?UTF-8?q?[Park]=20visible=20=EC=B2=98=EB=A6=AC=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81,=20input=20=EA=B0=92=20=EC=B2=B4=ED=81=AC=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80,=20Webpack=20alias=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: visible 처리 로직, input 값 체크 로직 추가 * env: webpack alias 설정 --- front/.eslintrc.js | 9 + front/package-lock.json | 172 ++++++++++++++++++ front/package.json | 1 + front/src/App.js | 19 +- front/src/components/Content/Card/Card.js | 3 +- .../Content/CardWritable/CardWritable.js | 18 +- .../CardWritable/cardWritable.module.css | 4 + front/src/components/Content/Cards/Cards.js | 17 +- .../Content/ColumnHeader/ColumnHeader.js | 3 +- .../src/components/Content/Columns/Columns.js | 15 +- front/src/components/Content/Content.js | 2 +- front/src/components/Header/Header.js | 3 +- front/src/components/Modal/Modal.js | 5 +- .../components/SideContent/Action/Action.js | 7 +- .../src/components/SideContent/SideContent.js | 19 +- front/src/index.js | 3 +- front/src/tagComponents/Button.js | 4 +- front/webpack.config.js | 10 + 18 files changed, 264 insertions(+), 50 deletions(-) diff --git a/front/.eslintrc.js b/front/.eslintrc.js index 6ecdbcff8..11fca4b8a 100644 --- a/front/.eslintrc.js +++ b/front/.eslintrc.js @@ -11,6 +11,15 @@ module.exports = { "plugin:prettier/recommended", "plugin:import/recommended", ], + settings: { + "import/resolver": { + webpack: { + env: { + DEPLOY: true, + }, + }, + }, + }, rules: { "prettier/prettier": [ "error", diff --git a/front/package-lock.json b/front/package-lock.json index 0e7ce2b70..b02913781 100644 --- a/front/package-lock.json +++ b/front/package-lock.json @@ -25,6 +25,7 @@ "eslint": "^8.2.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-config-prettier": "^8.5.0", + "eslint-import-resolver-webpack": "^0.13.2", "eslint-plugin-import": "^2.26.0", "eslint-plugin-prettier": "^4.0.0", "eslint-webpack-plugin": "^3.1.1", @@ -2320,6 +2321,12 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "node_modules/array-find": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-find/-/array-find-1.0.0.tgz", + "integrity": "sha1-bI4obRHtdoMn+OYuzuhzU8o+eLg=", + "dev": true + }, "node_modules/array-includes": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", @@ -3524,6 +3531,82 @@ "ms": "^2.1.1" } }, + "node_modules/eslint-import-resolver-webpack": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.13.2.tgz", + "integrity": "sha512-XodIPyg1OgE2h5BDErz3WJoK7lawxKTJNhgPNafRST6csC/MZC+L5P6kKqsZGRInpbgc02s/WZMrb4uGJzcuRg==", + "dev": true, + "dependencies": { + "array-find": "^1.0.0", + "debug": "^3.2.7", + "enhanced-resolve": "^0.9.1", + "find-root": "^1.1.0", + "has": "^1.0.3", + "interpret": "^1.4.0", + "is-core-module": "^2.7.0", + "is-regex": "^1.1.4", + "lodash": "^4.17.21", + "resolve": "^1.20.0", + "semver": "^5.7.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "eslint-plugin-import": ">=1.4.0", + "webpack": ">=1.11.0" + } + }, + "node_modules/eslint-import-resolver-webpack/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-webpack/node_modules/enhanced-resolve": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz", + "integrity": "sha1-TW5omzcl+GCQknzMhs2fFjW4ni4=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.2.0", + "tapable": "^0.1.8" + }, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/eslint-import-resolver-webpack/node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/eslint-import-resolver-webpack/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/eslint-import-resolver-webpack/node_modules/tapable": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.1.10.tgz", + "integrity": "sha1-KcNXB8K3DlDQdIK10gLo7URtr9Q=", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, "node_modules/eslint-module-utils": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", @@ -4193,6 +4276,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "dev": true + }, "node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -5597,6 +5686,12 @@ "node": ">= 4.0.0" } }, + "node_modules/memory-fs": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.2.0.tgz", + "integrity": "sha1-8rslNovBIeORwlIN6Slpyu4KApA=", + "dev": true + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -9942,6 +10037,12 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "array-find": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-find/-/array-find-1.0.0.tgz", + "integrity": "sha1-bI4obRHtdoMn+OYuzuhzU8o+eLg=", + "dev": true + }, "array-includes": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", @@ -10922,6 +11023,65 @@ } } }, + "eslint-import-resolver-webpack": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.13.2.tgz", + "integrity": "sha512-XodIPyg1OgE2h5BDErz3WJoK7lawxKTJNhgPNafRST6csC/MZC+L5P6kKqsZGRInpbgc02s/WZMrb4uGJzcuRg==", + "dev": true, + "requires": { + "array-find": "^1.0.0", + "debug": "^3.2.7", + "enhanced-resolve": "^0.9.1", + "find-root": "^1.1.0", + "has": "^1.0.3", + "interpret": "^1.4.0", + "is-core-module": "^2.7.0", + "is-regex": "^1.1.4", + "lodash": "^4.17.21", + "resolve": "^1.20.0", + "semver": "^5.7.1" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "enhanced-resolve": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz", + "integrity": "sha1-TW5omzcl+GCQknzMhs2fFjW4ni4=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.2.0", + "tapable": "^0.1.8" + } + }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "tapable": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.1.10.tgz", + "integrity": "sha1-KcNXB8K3DlDQdIK10gLo7URtr9Q=", + "dev": true + } + } + }, "eslint-module-utils": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", @@ -11319,6 +11479,12 @@ } } }, + "find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "dev": true + }, "find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -12318,6 +12484,12 @@ "fs-monkey": "1.0.3" } }, + "memory-fs": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.2.0.tgz", + "integrity": "sha1-8rslNovBIeORwlIN6Slpyu4KApA=", + "dev": true + }, "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", diff --git a/front/package.json b/front/package.json index be1e6d1a1..a3a28f7e8 100644 --- a/front/package.json +++ b/front/package.json @@ -36,6 +36,7 @@ "eslint": "^8.2.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-config-prettier": "^8.5.0", + "eslint-import-resolver-webpack": "^0.13.2", "eslint-plugin-import": "^2.26.0", "eslint-plugin-prettier": "^4.0.0", "eslint-webpack-plugin": "^3.1.1", diff --git a/front/src/App.js b/front/src/App.js index 2a18a24a0..05d428c0a 100644 --- a/front/src/App.js +++ b/front/src/App.js @@ -1,13 +1,14 @@ +import Columns from "components/Content/Columns/Columns"; +import Content from "components/Content/Content"; +import Header from "components/Header/Header"; +import Modal from "components/Modal/Modal"; +import SideContent from "components/SideContent/SideContent"; +import peact from "core/peact"; +import columnApi from "service/columnApi"; +import logApi from "service/logApi"; +import todoApi from "service/todoApi"; + import styles from "./App.module.css"; -import Columns from "./components/Content/Columns/Columns"; -import Content from "./components/Content/Content"; -import Header from "./components/Header/Header"; -import Modal from "./components/Modal/Modal"; -import SideContent from "./components/SideContent/SideContent"; -import peact from "./core/peact"; -import columnApi from "./service/columnApi"; -import logApi from "./service/logApi"; -import todoApi from "./service/todoApi"; const App = () => { const [todos, setTodos] = peact.useState([]); diff --git a/front/src/components/Content/Card/Card.js b/front/src/components/Content/Card/Card.js index b1c18615a..d16a788ce 100644 --- a/front/src/components/Content/Card/Card.js +++ b/front/src/components/Content/Card/Card.js @@ -1,4 +1,5 @@ -import peact from "../../../core/peact"; +import peact from "core/peact"; + import styles from "./card.module.css"; const Card = ({ todo, handlers, ref }) => { diff --git a/front/src/components/Content/CardWritable/CardWritable.js b/front/src/components/Content/CardWritable/CardWritable.js index 11b16529a..167209353 100644 --- a/front/src/components/Content/CardWritable/CardWritable.js +++ b/front/src/components/Content/CardWritable/CardWritable.js @@ -1,5 +1,6 @@ -import peact from "../../../core/peact"; -import Button from "../../../tagComponents/Button"; +import peact from "core/peact"; +import Button from "tagComponents/Button"; + import styles from "./cardWritable.module.css"; const activateButton = ($button, deactiveClassName) => { @@ -17,13 +18,18 @@ const CardWritable = ({ handleSubmitForm, inputValues, columnId, + isVisible, ref, }) => { const addButtonRef = peact.useRef(); + const inputTitleRef = peact.useRef(); + const inputDescRef = peact.useRef(); - const handleKeyUpInput = ({ target }) => { + const handleKeyUpInput = () => { const $addButton = addButtonRef.current; - const isInputEmpty = target.value === ""; + const $inputTitle = inputTitleRef.current; + const $inputDesc = inputDescRef.current; + const isInputEmpty = $inputTitle.value === "" || $inputDesc.value === ""; const isInputActive = !$addButton.classList.contains(styles.deactiveButton); if (isInputEmpty && isInputActive) { deactivateButton($addButton, styles.deactiveButton); @@ -54,6 +60,7 @@ const CardWritable = ({ onKeyUp: handleKeyUpInput, }, child: [], + ref: inputDescRef, }); const $inputTitle = peact.createElement({ @@ -67,6 +74,7 @@ const CardWritable = ({ onKeyUp: handleKeyUpInput, }, child: [], + ref: inputTitleRef, }); const $cardWritableHeader = peact.createElement({ @@ -107,7 +115,7 @@ const CardWritable = ({ return peact.createElement({ tag: "form", - className: styles.cardWritable, + className: [styles.cardWritable, ...(isVisible ? [styles.show] : [])], attrs: { "data-column-id": columnId, onSubmit: handleSubmitForm, diff --git a/front/src/components/Content/CardWritable/cardWritable.module.css b/front/src/components/Content/CardWritable/cardWritable.module.css index 0168e28c2..4d80afc75 100644 --- a/front/src/components/Content/CardWritable/cardWritable.module.css +++ b/front/src/components/Content/CardWritable/cardWritable.module.css @@ -11,6 +11,10 @@ border-radius: 6px; } +.cardWritable.show { + display: flex; +} + .headerArea { display: flex; height: 20px; diff --git a/front/src/components/Content/Cards/Cards.js b/front/src/components/Content/Cards/Cards.js index 543e0eae7..a6fa98cf7 100644 --- a/front/src/components/Content/Cards/Cards.js +++ b/front/src/components/Content/Cards/Cards.js @@ -1,9 +1,10 @@ -import { getISODateDiff } from "../../../common/dateUtils"; -import peact from "../../../core/peact"; -import todoApi from "../../../service/todoApi"; -import Card from "../Card/Card"; -import cardStyles from "../Card/card.module.css"; -import CardWritable from "../CardWritable/CardWritable"; +import { getISODateDiff } from "common/dateUtils"; +import Card from "components/Content/Card/Card"; +import cardStyles from "components/Content/Card/card.module.css"; +import CardWritable from "components/Content/CardWritable/CardWritable"; +import peact from "core/peact"; +import todoApi from "service/todoApi"; + import styles from "./cards.module.css"; const getSortedDatabyLatest = (data) => { @@ -53,11 +54,9 @@ const Cards = ({ $newCard, todos, handlers }) => { toggleCardVisible, handleSubmitForm, inputValues, + isVisible: true, ref: cardWritableRef, }); - // TODO: CardWritable 만들 때 display 속성 props 로 넘겨서 만드는게 좋을 듯 - $cardWritable.style.display = "flex"; - // cardsRef.current.insertBefore($cardWritable, $card); $card.classList.toggle(cardStyles.hide); }; diff --git a/front/src/components/Content/ColumnHeader/ColumnHeader.js b/front/src/components/Content/ColumnHeader/ColumnHeader.js index 42e94abb8..daa7e6589 100644 --- a/front/src/components/Content/ColumnHeader/ColumnHeader.js +++ b/front/src/components/Content/ColumnHeader/ColumnHeader.js @@ -1,4 +1,5 @@ -import peact from "../../../core/peact"; +import peact from "core/peact"; + import styles from "./columnHeader.module.css"; const ColumnHeader = ({ column, todos, toggleCardVisible }) => { diff --git a/front/src/components/Content/Columns/Columns.js b/front/src/components/Content/Columns/Columns.js index 4b3e4f1ea..cca214fe0 100644 --- a/front/src/components/Content/Columns/Columns.js +++ b/front/src/components/Content/Columns/Columns.js @@ -1,8 +1,9 @@ -import peact from "../../../core/peact"; -import todoApi from "../../../service/todoApi"; -import Cards from "../Cards/Cards"; -import CardWritable from "../CardWritable/CardWritable"; -import ColumnHeader from "../ColumnHeader/ColumnHeader"; +import Cards from "components/Content/Cards/Cards"; +import CardWritable from "components/Content/CardWritable/CardWritable"; +import ColumnHeader from "components/Content/ColumnHeader/ColumnHeader"; +import peact from "core/peact"; +import todoApi from "service/todoApi"; + import styles from "./columns.module.css"; const Columns = ({ columns, todos, handlers }) => { @@ -49,11 +50,13 @@ const Columns = ({ columns, todos, handlers }) => { const toggleCardVisible = () => { newCardRef.current.classList.toggle(styles.visible); }; + const $newCard = CardWritable({ toggleCardVisible, - ref: newCardRef, handleSubmitForm, columnId: column._id, + isVisible: false, + ref: newCardRef, }); return peact.createElement({ diff --git a/front/src/components/Content/Content.js b/front/src/components/Content/Content.js index 66c076856..567e59de5 100644 --- a/front/src/components/Content/Content.js +++ b/front/src/components/Content/Content.js @@ -1,4 +1,4 @@ -import peact from "../../core/peact"; +import peact from "core/peact"; const Content = ({ content }) => { return peact.createElement({ diff --git a/front/src/components/Header/Header.js b/front/src/components/Header/Header.js index 300d9048f..b43da4d2b 100644 --- a/front/src/components/Header/Header.js +++ b/front/src/components/Header/Header.js @@ -1,4 +1,5 @@ -import peact from "../../core/peact"; +import peact from "core/peact"; + import styles from "./header.module.css"; const Header = () => { diff --git a/front/src/components/Modal/Modal.js b/front/src/components/Modal/Modal.js index 6d565390c..6e9508c01 100644 --- a/front/src/components/Modal/Modal.js +++ b/front/src/components/Modal/Modal.js @@ -1,5 +1,6 @@ -import peact from "../../core/peact"; -import todoApi from "../../service/todoApi"; +import peact from "core/peact"; +import todoApi from "service/todoApi"; + import styles from "./modal.module.css"; const Modal = ({ handlers, isModalVisible, selectedTodoId, ref }) => { diff --git a/front/src/components/SideContent/Action/Action.js b/front/src/components/SideContent/Action/Action.js index 951302c32..ad68cbda5 100644 --- a/front/src/components/SideContent/Action/Action.js +++ b/front/src/components/SideContent/Action/Action.js @@ -1,6 +1,7 @@ -import { LOG_TYPE } from "../../../common/constants"; -import { getDateDiffFormat, getMongoNow } from "../../../common/dateUtils"; -import peact from "../../../core/peact"; +import { LOG_TYPE } from "common/constants"; +import { getDateDiffFormat, getMongoNow } from "common/dateUtils"; +import peact from "core/peact"; + import styles from "./action.module.css"; /* diff --git a/front/src/components/SideContent/SideContent.js b/front/src/components/SideContent/SideContent.js index 37f079c21..2fb7d71cc 100644 --- a/front/src/components/SideContent/SideContent.js +++ b/front/src/components/SideContent/SideContent.js @@ -1,8 +1,9 @@ -import { getISODateDiff } from "../../common/dateUtils"; -import { pipe } from "../../common/utils"; -import peact from "../../core/peact"; -import Button from "../../tagComponents/Button"; -import Action from "./Action/Action"; +import { getISODateDiff } from "common/dateUtils"; +import { pipe } from "common/utils"; +import Action from "components/SideContent/Action/Action"; +import peact from "core/peact"; +import Button from "tagComponents/Button"; + import styles from "./sideContent.module.css"; const menuBtnImageTemplate = ` @@ -47,15 +48,15 @@ const SideContent = ({ todoLogs, columns }) => { const menuBtnRef = peact.useRef(); const closeBtnRef = peact.useRef(); - const insertColumnTitle = (todoLogs) => { - return todoLogs.map((todoLog) => { + const insertColumnTitle = (originTodoLogs) => { + return originTodoLogs.map((todoLog) => { const column = columns?.find((col) => col._id === todoLog.columnId); return { ...todoLog, columnTitle: column?.title }; }); }; - const sortTodoLogs = (todoLogs) => { - return todoLogs.sort((aTodo, bTodo) => + const sortTodoLogs = (todoLogsWithColumnTitle) => { + return todoLogsWithColumnTitle.sort((aTodo, bTodo) => getISODateDiff(bTodo.createdAt, aTodo.createdAt) ); }; diff --git a/front/src/index.js b/front/src/index.js index 90159f621..c316fa753 100644 --- a/front/src/index.js +++ b/front/src/index.js @@ -1,5 +1,6 @@ +import peact from "core/peact"; + import App from "./App"; -import peact from "./core/peact"; peact.setRoot(document.getElementById("root")); peact.render(App); diff --git a/front/src/tagComponents/Button.js b/front/src/tagComponents/Button.js index 96e63a740..6da42173e 100644 --- a/front/src/tagComponents/Button.js +++ b/front/src/tagComponents/Button.js @@ -1,5 +1,5 @@ -import peact from "../core/peact"; -import { useId } from "../hooks/useId"; +import peact from "core/peact"; +import { useId } from "hooks/useId"; const Button = ({ onClick, className, innerHTML, ref, ...rest }) => { const id = useId("button"); diff --git a/front/webpack.config.js b/front/webpack.config.js index 4bfffe403..8aa3774fa 100644 --- a/front/webpack.config.js +++ b/front/webpack.config.js @@ -52,6 +52,16 @@ module.exports = (env) => { }, ], }, + resolve: { + alias: { + common: path.resolve(__dirname, "./src/common/"), + components: path.resolve(__dirname, "./src/components/"), + core: path.resolve(__dirname, "./src/core/"), + hooks: path.resolve(__dirname, "./src/hooks/"), + service: path.resolve(__dirname, "./src/service/"), + tagComponents: path.resolve(__dirname, "./src/tagComponents/"), + }, + }, ...(isDeploy ? {} : { devtool: "source-map" }), }; };