Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[1단계 - 자판기] 병민(윤병인) 미션 제출합니다. #40

Merged
merged 48 commits into from
Apr 1, 2022
Merged

[1단계 - 자판기] 병민(윤병인) 미션 제출합니다. #40

merged 48 commits into from
Apr 1, 2022

Conversation

airman5573
Copy link

@airman5573 airman5573 commented Mar 28, 2022

안녕하세요, 병민입니다 :D

이번 미션 피드백 잘 부탁드립니다 :D

데모 페이지

전체적인 구조

  • Store하나를 두고 각 컴포넌트에서 Store를 구독하는 형식입니다.
  • 컴포넌트에서 action을 dispatch하면 Store의 상태가 변하고, 구독된 컴포넌트에게 알람이 갑니다. 그리고 컴포넌트는 store의 state를 바탕으로 다시 그려집니다.
  • 컴포넌트는 HTMLElement를 상속받아 사용했습니다.
  • decorator를 사용해 CustomElementRepository에 클래스를 등록하는 과정을 간소화 했습니다.

Routing

netlify의 redirect를 사용해 새로고침을 해도 404로 이동되지 않도록 했습니다.

airman5573 and others added 30 commits March 23, 2022 15:39
commitlint + commitizen 을 사용해서 commit message를 정형화한다
single quote, EOL, trailingComma 적용
store, reducer, creaAction 생성
component scope를 추가한다
airman5573 and others added 18 commits March 28, 2022 00:55
redirect rule을 적용한다
event decorator를 사용하면 컴포넌트가 사라졌을때 등록한 event가 사라지기 때문에, 사용하기에 적절치 않다.
충전 금액이 음수일 경우 에러를 체크하는 테스트를 추가한다
Copy link

@austinpark420 austinpark420 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

안녕하세요 😄

리뷰를 맡은 오스틴입니다.
flux 패턴을 활용하셔서 개발하신 부분이 인상적이었습니다.
관련해서 코멘트 남겨놨으니 확인 부탁드릴게요!

UX/UI 관련

  • 상품 관리 - 상품 현황 리스트 수정을 누르게되면 input 태그크기 때문인지 리스트 높이와 버튼 위치가 변하는데 이 부분 보기/수정 상관없이 리스트와 버튼의 위치가 동일하도록 css를 수정해보시면 좋을 것 같습니다.
  • 피그마와 다른 내용이긴 하지만 상품 관리탭에 추가할 상품정보를 입력하는 부분에 placeholder으로 어떤 값을 넣어야하는 설명해주고 있지만 처음 값을 작성할 땐 어떤 항목에 대한 값을 작성하고 있는지 헷갈리는 경우가 있어 라벨이 있으면 어떨까라는 생각을 했습니다.

return `
<nav class="d-flex justify-content-center">
<button class="btn btn-secondary mr-1 ${
activeTab === Tab.ProductManageTab ? 'active' : ''

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3항연산자 말고 &&을 활용하셔도 될것 같습니다.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

activeTab === Tab.ProductManageTab && 'active' 를 써보니, false가 class에 들어갑니다.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아고 제가 리엑트 문법에 너무 익숙해져서 간과했던 부분이네요 🙏

@@ -0,0 +1,10 @@
import { Action } from '../types';

const createAction = (type: string, payload: any): Action => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

return coins;
}

const reducer = (state: AppState, { type, payload }: Action) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Comment on lines +30 to +48
if (type === ACTION.ADD_PRODUCT) {
newState.productList = [...newState.productList, { ...payload, isEditing: false }];
} else if (type === ACTION.CHANGE_EDIT_MODE) {
const { name, isEditing } = payload;
const index = newState.productList.findIndex((item) => item.name === name);
newState.productList[index].isEditing = isEditing;
} else if (type === ACTION.EDIT_PRODUCT) {
const { originalName, name, price, quantity } = payload;
const index = newState.productList.findIndex((item) => item.name === originalName);
newState.productList[index] = { name, price, quantity, isEditing: false };
} else if (type === ACTION.DELETE_PRODUCT) {
newState.productList = newState.productList.filter((item) => item.name !== payload);
} else if (type === ACTION.CHARGE_COINS) {
newState.chargedCoins = mergeCoins(newState.chargedCoins, moneyToCoin(payload));
newState.chargedMoney += payload;
} else if (type === ACTION.CHANGE_ACTIVE_TAB) {
newState.activeTab = payload;
}
return newState;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

switch 문으로 리페토링 가능하시면 swith 문 활용하시는걸 추천드려요.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네, 그 편이 더 읽기 좋을것 같습니다. 감사합니다 :D

class PurchaseProductTab extends Component {
template(activeTab: Tab): string {
if (this.localName !== activeTab) return '';
return '<h3 class="text-center">🤖 페이지 건설중...</h3>';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UX/UI를 고려한 부분 좋네요. 👍

@@ -0,0 +1,70 @@
import {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

validators.ts 파일이 유독 가독성이 떨어져 보이네요. 🤔

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

맞습니다. 다시보니 읽기가 힘드네요. 수정하겠습니다 :D

import { toInt } from '../utils';
import ValidationResult from './validation-result';

const isInteger = (str: string) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intger은 javascript에는 없는 타입이네요.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네, 맞습니다. 다만 정수인지를 판단하는 일을 하는 함수라서
Integer가 직관적이라 더 어울려 보이는데, 리뷰어님의 생각은 어떠신가요?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

toInt 함수와 동일한 의견입니다!

const productList = Store.instance.getState().productList;
const errorList = validateProduct(
{ name, price, quantity },
productList.filter((item) => !(item.name === originalName && item.name === name))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

개인적인 취향이지만 드모르간 법칙을 이용해 가독성좋게 바꿔보는건 어떨까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제안 감사합니다 :D

드모르간 법칙을 적용하면

const productList = Store.instance.getState().productList;
const errorList = validateProduct(
    { name, price, quantity },
    productList.filter((item) => item.name !== originalName || item.name !== name)

이렇게 되서, 더 잘 읽히는것 같습니다.

다만, 그래도 역시 한번에 이해하기 어려운 코드여서 아래와 같이 바꿔보았습니다.

const productList = Store.instance.getState().productList;
const isEditingSameProduct = (item: ProductItem) => {
  if (originalName === name && item.name === name) return true;
  return false;
};
const errorList = validateProduct(
  { name, price, quantity },
  productList.filter(!isEditingSameProduct)
).filter((result) => result.hasError);

이 코드는 어떤가요?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Comment on lines +35 to +41
export const MAX_LENGTH_OF_PRODUCT_NAME = 10;
export const MIN_PRODUCT_PRICE = 100;
export const MAX_PRODUCT_PRICE = 10000;
export const MIN_COIN_UNIT = 10;
export const MIN_PRODUCT_QUANTITY = 1;
export const MAX_PRODUCT_QUANTITY = 20;
export const MAX_CHARGABLE_MONEY = 100000;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

관련있는 변수를 묶어서 관리해도 좋을 것 같습니다.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네, 수정하겠습니다 :D


$color-primary: $color-cyan-900;
$color-secondary: $color-gray-400;
// $color-cancel: $color-cyan-900;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

불필요한 주석은 지워주시는게 좋을 것 같습니다.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네, 지우겠습니다 :D

Copy link

@austinpark420 austinpark420 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

안녕하세요. 병민님.
아직 리뷰요청을 주시진 않았는데요. 피드백 반영해주신 것으로 확인됩니다.
2단계 진행 및 리뷰 일정 확보를위해 머지하도록 하겠습니다.

step1 구현하시느라 고생많으셨습니다 👍

import { toInt } from '../utils';
import ValidationResult from './validation-result';

const isInteger = (str: string) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

toInt 함수와 동일한 의견입니다!

import { VALIDATION_ERROR_NAME } from './constants';
import { Indexable } from './types';

export const toInt = (str: string, defaultNum = 0) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

디테일하시군요 👍
저는 그냥 보편적으로 숫자라고 생각했는데 병민님 의견 주신 부분이 맞는것 같습니다 🙏

import Component from '../abstract/component';
import { ComponentConstructor } from '../types';

export function customElement(name: string) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그렇군요. 제가 궁금했던건 customElement자체의 사용 이유 였습니다.
본인의 생각이 명확하시네요 👍

return `
<nav class="d-flex justify-content-center">
<button class="btn btn-secondary mr-1 ${
activeTab === Tab.ProductManageTab ? 'active' : ''

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아고 제가 리엑트 문법에 너무 익숙해져서 간과했던 부분이네요 🙏

const productList = Store.instance.getState().productList;
const errorList = validateProduct(
{ name, price, quantity },
productList.filter((item) => !(item.name === originalName && item.name === name))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

.map((unit) => {
return `
<tr>
<td>${unit.toLocaleString('ko-kr')}원</td>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prototype에 직접 추가하는 추천드리지 않습니다.. 어떤 사이드 이펙트가 생길지 모르기때문입니다.
store나 util로 따로 뺄순 있지않나 해서 말씀드렸습니다!

@austinpark420 austinpark420 merged commit 960db37 into woowacourse:airman5573 Apr 1, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants