Skip to content

Commit

Permalink
feat: 정산 계좌 입력 다이얼로그 은행 선택, 계좌 정보 입력 컨텐츠 추가 (#35)
Browse files Browse the repository at this point in the history
* feat: 정산 바텀시트 은행 선택 UI 추가

* feat: index 기반으로 렌더링하도록 설정

* fix: svg 오류 수정

* feat: 계좌 번호, 예금주 입력 폼 기초 작업 추가

* feat: 입력 정보 확인 UI 추가

* fix: border-width 1.5 -> 1로 변경

* feat: 정산 정보 입력 상태 추가

* feat: useBodyScrollLock 훅 추가

* chore: index.tsx로 변경

* feat: import 정렬 설정 추가

* fix: lint:fix 실행

* refac: validation 함수 유틸로 분리
  • Loading branch information
alstn2468 authored Feb 8, 2024
1 parent a405d55 commit 2001f70
Show file tree
Hide file tree
Showing 85 changed files with 1,858 additions and 293 deletions.
678 changes: 678 additions & 0 deletions .pnp.cjs

Large diffs are not rendered by default.

Binary file modified .yarn/install-state.gz
Binary file not shown.
1 change: 1 addition & 0 deletions apps/admin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"lint:fix": "eslint . --ext ts,tsx --fix",
"type-check": "tsc --noEmit",
"preview": "vite preview"
},
Expand Down
18 changes: 10 additions & 8 deletions apps/admin/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import 'the-new-css-reset/css/reset.css';
import './index.css';

import { LOCAL_STORAGE, QueryClientProvider } from '@boolti/api';
import { createBrowserRouter, RouterProvider, Navigate, Outlet } from 'react-router-dom';
import { BooltiUIProvider } from '@boolti/ui';
import LoginPage from './pages/Login/LoginPage';
import SignUpCompletePage from './pages/SignUpComplete/SignUpCompletePage';
import { createBrowserRouter, Navigate, Outlet, RouterProvider } from 'react-router-dom';

import AuthErrorBoundary from './components/ErrorBoundary/AuthErrorBoundary';
import { PATH } from './constants/routes';
import HomePage from './pages/HomePage/HomePage';
import OAuthKakaoPage from './pages/OAuth/OAuthKakaoPage';
import LoginPage from './pages/Login/LoginPage';
import OAuthApplePage from './pages/OAuth/OAuthApplePage';
import 'the-new-css-reset/css/reset.css';
import './index.css';
import { PATH } from './constants/routes';
import AuthErrorBoundary from './components/ErrorBoundary/AuthErrorBoundary';
import OAuthKakaoPage from './pages/OAuth/OAuthKakaoPage';
import SignUpCompletePage from './pages/SignUpComplete/SignUpCompletePage';

const PublicRoute = () => {
const isLogin =
Expand Down
17 changes: 15 additions & 2 deletions apps/admin/src/components/AccountInfo/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Button } from '@boolti/ui';
import { Button, useDialog } from '@boolti/ui';

import SettlementDialogContent from '../SettlementDialogContent';
import Styled from './AccountInfo.styles';

interface Props {
Expand All @@ -8,6 +10,7 @@ interface Props {
}

const AccountInfo = ({ orgName, accountHolder, accountNumber }: Props) => {
const { open, close } = useDialog();
return (
<Styled.Container>
<Styled.Title>정산 계좌 정보</Styled.Title>
Expand All @@ -16,7 +19,17 @@ const AccountInfo = ({ orgName, accountHolder, accountNumber }: Props) => {
{orgName && <Styled.AccountText>{orgName}</Styled.AccountText>}
{accountNumber && <Styled.AccountText>{accountNumber}</Styled.AccountText>}
{accountHolder && <Styled.AccountText>{accountHolder}</Styled.AccountText>}
<Button type="button" colorTheme="netural" size="regular">
<Button
onClick={() => {
open({
title: '정산 계좌 입력하기',
content: <SettlementDialogContent onClose={close} />,
});
}}
type="button"
colorTheme="netural"
size="regular"
>
{accountNumber ? '변경하기' : '입력하기'}
</Button>
</Styled.AccountContainer>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { BooltiHTTPError, LOCAL_STORAGE } from '@boolti/api';
import React from 'react';
import { Navigate } from 'react-router-dom';

import { PATH } from '../../constants/routes';

interface AuthErrorBoundaryProps {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';

import Styled from './Header.styles';

interface HeaderProps {
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import styled from '@emotion/styled';

const Container = styled.div``;

const Title = styled.h2`
${({ theme }) => theme.typo.b3};
color: ${({ theme }) => theme.palette.grey.g70};
margin-bottom: 28px;
`;

const BankList = styled.ul`
height: 290px;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 12px;
overflow-y: scroll;
`;

const BankItem = styled.li`
width: 120px;
height: 74px;
`;

const BankItemButton = styled.button<{ isSelected?: boolean; isNull?: boolean }>`
cursor: pointer;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
border-radius: 4px;
border-width: 1px;
border-style: solid;
padding: 8px 20px;
transition:
border 0.2s ease-in-out,
opacity 0.2s ease-in-out;
background-color: ${({ theme }) => theme.palette.grey.g00};
border-color: ${({ theme }) => theme.palette.grey.g00};
${({ isSelected, isNull, theme }) => {
if (isNull) {
return ``;
}
if (isSelected) {
return `
border-color: ${theme.palette.primary.o1};
`;
}
return `
opacity: 0.4;
`;
}}
`;

const BankIcon = styled.div`
& > svg {
width: 32px;
height: 32px;
}
`;

const BankName = styled.span`
${({ theme }) => theme.typo.b1};
color: ${({ theme }) => theme.palette.grey.g90};
`;

const ButtonContainer = styled.div`
display: flex;
justify-content: flex-end;
width: 100%;
margin-top: 32px;
& > button {
margin-left: 8px;
}
`;

const InputLabel = styled.p`
margin-bottom: 8px;
${({ theme }) => theme.typo.b3};
color: ${({ theme }) => theme.palette.grey.g90};
`;

const InputContainer = styled.div`
margin-bottom: 28px;
`;

const ConfirmContainer = styled.div`
border-radius: 4px;
padding: 16px;
background-color: ${({ theme }) => theme.palette.grey.g00};
`;

const ConfrimTextContainer = styled.div`
display: flex;
justify-content: flex-start;
align-items: center;
&:not(:last-of-type) {
margin-bottom: 8px;
}
`;

const ConfirmTextLabel = styled.span`
display: inline-block;
${({ theme }) => theme.typo.b3};
color: ${({ theme }) => theme.palette.grey.g70};
width: 56px;
margin-right: 20px;
`;

const ConfrimTextValue = styled.span`
${({ theme }) => theme.typo.sh1};
color: ${({ theme }) => theme.palette.grey.g90};
`;

export default {
Container,
ButtonContainer,
Title,
BankList,
BankItem,
BankName,
BankIcon,
BankItemButton,
InputLabel,
InputContainer,
ConfirmContainer,
ConfrimTextContainer,
ConfirmTextLabel,
ConfrimTextValue,
};
157 changes: 157 additions & 0 deletions apps/admin/src/components/SettlementDialogContent/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import { Button, TextField, useToast } from '@boolti/ui';
import { useState } from 'react';

import { bankItems } from '~/constants/bankItems';
import { useBodyScrollLock } from '~/hooks/useBodyScrollLock';
import { validateAccountHolder, validateAccountNumber } from '~/utils/validation';

import Styled from './SettlementDialogContent.styles';

const titles = [
'은행을 선택해 주세요.',
'계좌번호와 계좌주를 입력해 주세요.',
'입력하신 계좌 정보를 다시 한 번 확인해주세요.',
];

interface Props {
onClose?: VoidFunction;
}

const SettlementDialogContent = ({ onClose }: Props) => {
const toast = useToast();
const [currentStepIndex, setCurrentStepIndex] = useState(0);
const [selectedBank, setSelectedBank] = useState<string | null>(null);
const [accountNumber, setAccountNumber] = useState<string>('');
const [accountHolder, setAccountHolder] = useState<string>('');
const [accountHolderError, setAccountHolderError] = useState<string | undefined>(undefined);
const [accountNumberError, setAccountNumberError] = useState<string | undefined>(undefined);

useBodyScrollLock();

return (
<Styled.Container>
<Styled.Title>{titles[currentStepIndex]}</Styled.Title>
{currentStepIndex === 0 && (
<Styled.BankList>
{bankItems.map((bankItem) => (
<Styled.BankItem key={bankItem.name}>
<Styled.BankItemButton
isNull={selectedBank === null}
isSelected={selectedBank === bankItem.name}
onClick={() => {
setSelectedBank(bankItem.name);
}}
>
<Styled.BankIcon>{<bankItem.icon />}</Styled.BankIcon>
<Styled.BankName>{bankItem.name}</Styled.BankName>
</Styled.BankItemButton>
</Styled.BankItem>
))}
</Styled.BankList>
)}
{currentStepIndex === 1 && (
<>
<Styled.InputContainer>
<Styled.InputLabel>계좌번호</Styled.InputLabel>
<TextField
placeholder="계좌번호를 입력해 주세요"
size="small"
inputType="text"
value={accountNumber}
errorMessage={accountNumberError}
onBlur={(event) => {
setAccountNumberError(
validateAccountNumber(event.target.value)
? undefined
: '계좌번호를 확인 후 다시 입력해 주세요.',
);
}}
onChange={(event) => {
const value = event.target.value;
if (!isNaN(Number(value))) {
setAccountNumber(value);
}
}}
/>
</Styled.InputContainer>
<Styled.InputContainer>
<Styled.InputLabel>계좌주</Styled.InputLabel>
<TextField
placeholder="계좌주 이름을 입력해 주세요"
size="small"
inputType="text"
value={accountHolder}
errorMessage={accountHolderError}
onBlur={(event) => {
setAccountHolderError(
validateAccountHolder(event.target.value) ? undefined : '한글만 입력 가능합니다.',
);
}}
onChange={(event) => {
setAccountHolder(event.target.value);
}}
/>
</Styled.InputContainer>
</>
)}
{currentStepIndex === 2 && (
<Styled.ConfirmContainer>
<Styled.ConfrimTextContainer>
<Styled.ConfirmTextLabel>은행</Styled.ConfirmTextLabel>
<Styled.ConfrimTextValue>{selectedBank}</Styled.ConfrimTextValue>
</Styled.ConfrimTextContainer>
<Styled.ConfrimTextContainer>
<Styled.ConfirmTextLabel>계좌번호</Styled.ConfirmTextLabel>
<Styled.ConfrimTextValue>{accountNumber}</Styled.ConfrimTextValue>
</Styled.ConfrimTextContainer>
<Styled.ConfrimTextContainer>
<Styled.ConfirmTextLabel>계좌주</Styled.ConfirmTextLabel>
<Styled.ConfrimTextValue>{accountHolder}</Styled.ConfrimTextValue>
</Styled.ConfrimTextContainer>
</Styled.ConfirmContainer>
)}
<Styled.ButtonContainer>
{currentStepIndex !== 0 && (
<Button
type="button"
colorTheme="line"
size="bold"
onClick={() => {
setCurrentStepIndex((prev) => prev - 1);
}}
>
이전으로
</Button>
)}
<Button
type="button"
colorTheme="primary"
size="bold"
disabled={
(currentStepIndex === 0 && !selectedBank) ||
(currentStepIndex === 1 &&
(accountNumber === '' ||
accountHolder === '' ||
!!accountHolderError ||
!!accountNumberError))
}
onClick={() => {
if (accountHolderError || accountNumberError) {
return;
}
if (currentStepIndex === 2) {
toast.success('정산 계좌를 저장했습니다.');
onClose?.();
return;
}
setCurrentStepIndex((prev) => prev + 1);
}}
>
{currentStepIndex === 2 ? '저장하기' : '다음으로'}
</Button>
</Styled.ButtonContainer>
</Styled.Container>
);
};

export default SettlementDialogContent;
5 changes: 3 additions & 2 deletions apps/admin/src/components/ShowList/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Button } from '@boolti/ui';
import Styled from './ShowList.styles';
import { PlusIcon } from '@boolti/icon';
import { Button } from '@boolti/ui';

import ShowListItem from '../ShowListItem';
import Styled from './ShowList.styles';

interface Props {
shows: React.ComponentProps<typeof ShowListItem>[];
Expand Down
3 changes: 2 additions & 1 deletion apps/admin/src/components/ShowListItem/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ChevronRightIcon } from '@boolti/icon';
import { Badge } from '@boolti/ui';

import Styled from './ShowListItem.styles';
import { ChevronRightIcon } from '@boolti/icon';

interface Props {
isEmpty?: boolean;
Expand Down
Loading

0 comments on commit 2001f70

Please sign in to comment.