Skip to content

[클린코드 리액트 3기 정진범] 페이먼츠 미션 Step3 #159

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

Open
wants to merge 39 commits into
base: jungjinbeom
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
9ff4c10
vite 환경 설정
jungjinbeom Mar 3, 2024
5f29bb5
classnames 라이브러리 추가
jungjinbeom Mar 4, 2024
0924b64
PageTitle 문구 삭제
jungjinbeom Mar 4, 2024
122daa2
사용하지 않는 파일 삭제
jungjinbeom Mar 4, 2024
4cd3623
라우트 Context 컴포넌트 생성
jungjinbeom Mar 4, 2024
3295a14
사용하지 않는 파일 수정
jungjinbeom Mar 7, 2024
aedfe7d
카드리스트, 카드 완료 페이지 개발중
jungjinbeom Mar 7, 2024
d79e9d8
Button, Input, Card 스토리북 추가
jungjinbeom Mar 10, 2024
b7bc9ca
태그 구조 수정
jungjinbeom Mar 10, 2024
b12a25e
모달 컴포넌트 추가
jungjinbeom Mar 12, 2024
b64ca45
Merge remote-tracking branch 'upstream/jungjinbeom'
jungjinbeom Mar 12, 2024
cb3f051
중복 파일삭제
jungjinbeom Mar 16, 2024
b4dc5cf
lint 체크
jungjinbeom Mar 16, 2024
1c54168
툴팁 컴포넌트 개발
jungjinbeom Mar 18, 2024
68eb150
스토리북 추가
jungjinbeom Mar 18, 2024
5bae1a9
CardContext와 ListContext 통합
jungjinbeom Mar 20, 2024
db1c4d2
Merge remote-tracking branch 'upstream/jungjinbeom'
jungjinbeom Mar 20, 2024
2655062
eslint 적용
jungjinbeom Mar 20, 2024
2e1c2a2
스토리북 추가
jungjinbeom Mar 20, 2024
2b699a8
사용하지 않는 상수 삭제
jungjinbeom Mar 20, 2024
2f39969
chore: 사용하지 않는 파일 제거
jungjinbeom Apr 1, 2024
e2ea372
import 구문 정리
jungjinbeom Apr 7, 2024
5aa5572
커스텀훅 추가
jungjinbeom Apr 7, 2024
0ba4fe6
context삭제
jungjinbeom Apr 7, 2024
bcf9105
Lookup table 형식으로 변경
jungjinbeom Apr 7, 2024
12df3c4
portal 추가
jungjinbeom Apr 7, 2024
2e456dc
사용하지 않는 컴포넌트 삭제
jungjinbeom Apr 7, 2024
6fba43b
import 구문 정리 및 개행 추가
jungjinbeom Apr 7, 2024
b2b1123
개행 추가, 베럴 Import 형식으로 변경
jungjinbeom Apr 7, 2024
63ebfd4
Error 에러문 수정
jungjinbeom Apr 7, 2024
9b55a26
개월 최소값 수정
jungjinbeom Apr 7, 2024
d11174f
사용하지 않는 컴포넌트 삭제
jungjinbeom Apr 7, 2024
7ab4aa6
커스텀 훅 추가
jungjinbeom Apr 7, 2024
b87daaf
유효성 검사 함수 명 수정
jungjinbeom Apr 7, 2024
8960a2f
import 구문 구성 수정 및 개행 추가
jungjinbeom Apr 7, 2024
1a8e18a
import 구문 추가 및 개행 추가
jungjinbeom Apr 7, 2024
a834c1f
navigate함수에 useCallback 추가
jungjinbeom Apr 7, 2024
598c22f
사용하지 않는 룰 삭제
jungjinbeom Apr 7, 2024
55d1411
Stepper null 처리
jungjinbeom Apr 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:react-hooks/recommended', 'plugin:storybook/recommended'],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:storybook/recommended',
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parser: '@typescript-eslint/parser',
plugins: ['react-refresh'],
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"dev": "vite",
"test": "echo \"Error: no test specified\" && exit 1",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build"
"build-storybook": "storybook build",
"lint": "eslint --fix --ext .js,.jsx,.ts,.tsx ."
},
"keywords": [],
"author": "",
Expand All @@ -27,9 +28,8 @@
"@typescript-eslint/parser": "^7.0.2",
"@vitejs/plugin-react-swc": "^3.6.0",
"eslint": "^8.57.0",
"eslint-config-xo": "^0.44.0",
"eslint-config-xo-typescript": "^3.0.0",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-refresh": "^0.4.6",
"eslint-plugin-storybook": "^0.8.0",
"prettier": "^3.2.5",
"typescript": "^5.3.3",
Expand Down
21 changes: 6 additions & 15 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,16 @@
import CardList from './pages/card-list/CardList';
import AddCard from './pages/card-add/AddCard';
import CardRegisterComplete from './pages/card-register-complete/CardRegisterComplete';
import Stepper from './pages/Stepper';
import CardInfoProvider from './provider/card-info-provider/CardInfoProvider';
import MyCardsProvider from './provider/my-cards-provider/MyCardsProvider';

import StepProvider from './provider/step-provider/StepProvider';

const App = () => (
<div className="root">
<MyCardsProvider>
<CardInfoProvider>
<StepProvider>
{(route) => (
<>
{'LIST' === route && <CardList />}
<CardInfoProvider>
{'CARD' === route && <AddCard />}
{'COMPLETE' === route && <CardRegisterComplete />}
</CardInfoProvider>
</>
)}
<Stepper />
Copy link
Member

Choose a reason for hiding this comment

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

훨씬 선언적으로 되었네요 👍

</StepProvider>
</MyCardsProvider>
</CardInfoProvider>
<div id="modal"></div>
</div>
);

Expand Down
4 changes: 4 additions & 0 deletions src/assets/question.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 5 additions & 2 deletions src/components/card/Card.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { Meta, StoryObj } from '@storybook/react';
import Card from './Card';
import { type Meta, type StoryObj } from '@storybook/react';

import { Card } from '.';

import '../../../styles/card.css';

const meta = {
title: 'Card',
component: Card,
Expand Down
30 changes: 18 additions & 12 deletions src/components/card/Card.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,48 @@
import CardNumbers from './parts/CardNumbers';
import { type CardBrand, type CardStateType } from '@/domain/type';
import CardBox from './parts/CardBox';
import CardForm from './parts/CardForm';
import CardNumbers from './parts/CardNumbers';
import CardTitle from './parts/CardTitle';
import { CardStateType } from '@/domain/type';

import CardBottom from './parts/CardBottom';
import CardText from './parts/CardText';
import Chip from './parts/Chip';
import CardBottom from './parts/CardBottom';

interface CardProps extends CardStateType {
type CardProps = {
status?: 'small' | 'big' | 'empty';
onClick?: () => void;
}
cardBrandName: string;
} & CardStateType &
CardBrand;

const Card = ({
const REGEX = /[1-9]/gi;

export const Card = ({
ownerName = 'NAME',
month,
year = '',
cardNumbers,
status = 'small',
status = 'empty',
color,
cardBrandName,
onClick,
}: CardProps) => {
const cardNumber = `${cardNumbers?.first ?? ''} ${cardNumbers?.second ?? ''} ${cardNumbers?.third?.replace(REGEX, '*') ?? ''} ${cardNumbers?.fourth?.replace(REGEX, '*') ?? ''}`;

const displayMonth = month ? `${month} / ` : '';
const expirationDate = `${displayMonth}${year}`;

return (
<CardBox onClick={onClick}>
<CardForm status={status}>
<CardForm status={status} style={{ backgroundColor: color }}>
<CardTitle>
<CardText status={status}>타이틀</CardText>
<CardText status={status}>{cardBrandName}</CardText>
</CardTitle>
<div className="card-middle">
<Chip status={status} />
</div>
<CardBottom>
<CardNumbers status={status} {...cardNumbers} />
<CardNumbers status={status} cardNumber={cardNumber} />
<div className="card-bottom__info">
<CardText status={status}>{ownerName}</CardText>
<CardText status={status}>{expirationDate || 'MM/YY'}</CardText>
Expand All @@ -44,5 +52,3 @@ const Card = ({
</CardBox>
);
};

export default Card;
7 changes: 0 additions & 7 deletions src/components/card/CardBox.tsx

This file was deleted.

8 changes: 0 additions & 8 deletions src/components/card/CardForm.tsx

This file was deleted.

28 changes: 0 additions & 28 deletions src/components/card/CardNumbers.tsx

This file was deleted.

19 changes: 8 additions & 11 deletions src/components/card/EmptyCard.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import CardBox from './parts/CardBox';
import CardForm from './parts/CardForm';

interface EmptyCardProps {
type EmptyCardProps = {
onClick: () => void;
}
const EmptyCard = ({ onClick }: EmptyCardProps) => {
return (
<CardBox onClick={onClick}>
<CardForm status="empty">
<div>+</div>
</CardForm>
</CardBox>
);
};

export default EmptyCard;
export const EmptyCard = ({ onClick }: EmptyCardProps) => (
<CardBox onClick={onClick}>
<CardForm status="empty">
<div>+</div>
</CardForm>
</CardBox>
);
2 changes: 2 additions & 0 deletions src/components/card/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { Card } from './Card';
export { EmptyCard } from './EmptyCard';
8 changes: 4 additions & 4 deletions src/components/card/parts/CardBottom.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { PropsWithChildren } from 'react';
import { type PropsWithChildren } from 'react';

const CardBottom = ({ children }: PropsWithChildren) => {
return <div className="card-bottom">{children}</div>;
};
const CardBottom = ({ children }: PropsWithChildren) => (
<div className="card-bottom">{children}</div>
);

export default CardBottom;
19 changes: 9 additions & 10 deletions src/components/card/parts/CardBox.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { PropsWithChildren } from 'react';
import { type PropsWithChildren } from 'react';

interface CardBoxProps extends PropsWithChildren {
type CardBoxProps = {
onClick?: () => void;
}
const CardBox = ({ onClick, children }: CardBoxProps) => {
return (
<div onClick={onClick} className="card-box">
{children}
</div>
);
};
} & PropsWithChildren;

const CardBox = ({ onClick, children }: CardBoxProps) => (
<div onClick={onClick} className="card-box">
{children}
</div>
);

export default CardBox;
17 changes: 10 additions & 7 deletions src/components/card/parts/CardForm.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import classNames from 'classnames';
import { PropsWithChildren } from 'react';

interface CardFormProps extends PropsWithChildren {
import { type HTMLAttributes, type PropsWithChildren } from 'react';
type BaseCardFormProps = HTMLAttributes<HTMLDivElement>;
type CardFormProps = {
status: string;
}
const CardForm = ({ status, children }: CardFormProps) => {
return <div className={classNames(`${status}-card`)}>{children}</div>;
};
} & PropsWithChildren<BaseCardFormProps>;

const CardForm = ({ status, children, style }: CardFormProps) => (
<div className={classNames(`${status}-card`)} style={style}>
{children}
</div>
);

export default CardForm;
26 changes: 8 additions & 18 deletions src/components/card/parts/CardNumbers.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,14 @@
import { CardNumbersType } from '@/domain/type';
import CardText from './CardText';

const REGEX = /[1-9]/gi;
interface CardNumbersProps extends CardNumbersType {
type CardNumbersProps = {
status: 'big' | 'small' | 'empty';
}
const CardNumbers = ({
status,
first = '',
second = '',
third = '',
fourth = '',
}: CardNumbersProps) => {
return (
<div className="card-bottom__number">
<CardText
status={status}
>{`${first} ${second} ${third.replace(REGEX, '*')} ${fourth.replace(REGEX, '*')}`}</CardText>
</div>
);
cardNumber: string;
};

const CardNumbers = ({ status, cardNumber }: CardNumbersProps) => (
<div className="card-bottom__number">
<CardText status={status}>{cardNumber}</CardText>
</div>
);

export default CardNumbers;
19 changes: 8 additions & 11 deletions src/components/card/parts/CardText.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import classNames from 'classnames';
import { DetailedHTMLProps, PropsWithChildren } from 'react';
import { type HTMLAttributes, type PropsWithChildren } from 'react';

type BaseCardTextProps = DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>;
interface CardTextProps extends BaseCardTextProps, PropsWithChildren {
type BaseCardTextProps = HTMLAttributes<HTMLSpanElement>;

type CardTextProps = {
status: string;
}
} & PropsWithChildren<BaseCardTextProps>;

const CardText = ({ status, children }: CardTextProps) => {
return (
<span className={classNames(status === 'big' ? 'card-text__big' : 'card-text')}>
{children}
</span>
);
};
const CardText = ({ status, children }: CardTextProps) => (
<span className={classNames(status === 'big' ? 'card-text__big' : 'card-text')}>{children}</span>
);

export default CardText;
6 changes: 2 additions & 4 deletions src/components/card/parts/CardTitle.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { PropsWithChildren } from 'react';
import { type PropsWithChildren } from 'react';

const CardTitle = ({ children }: PropsWithChildren) => {
return <div className="card-top">{children}</div>;
};
const CardTitle = ({ children }: PropsWithChildren) => <div className="card-top">{children}</div>;

export default CardTitle;
9 changes: 5 additions & 4 deletions src/components/card/parts/Chip.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import classNames from 'classnames';

interface ChipProps {
type ChipProps = {
status: 'small' | 'big' | 'empty';
}
const Chip = ({ status }: ChipProps) => {
return <div className={classNames(status === 'big' ? 'big-card__chip' : 'small-card__chip')} />;
};

const Chip = ({ status }: ChipProps) => (
<div className={classNames(status === 'big' ? 'big-card__chip' : 'small-card__chip')} />
);

export default Chip;
11 changes: 5 additions & 6 deletions src/components/common/button-box/ButtonBox.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import classNames from 'classnames';
import { DetailedHTMLProps, HTMLAttributes, PropsWithChildren } from 'react';
import { type DetailedHTMLProps, type HTMLAttributes, type PropsWithChildren } from 'react';

type BaseButtonBox = DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
interface ButtonBoxProps extends BaseButtonBox, PropsWithChildren {}

const ButtonBox = ({ className, children }: ButtonBoxProps) => {
return <div className={classNames(className, 'button-box')}>{children}</div>;
};
type ButtonBoxProps = Record<string, unknown> & PropsWithChildren<BaseButtonBox>;

export default ButtonBox;
export const ButtonBox = ({ className, children }: ButtonBoxProps) => (
<div className={classNames(className, 'button-box')}>{children}</div>
);
Loading