Skip to content

Commit

Permalink
feat: 사용자 기본 정보 및 계좌 정보 API 연동 (#38)
Browse files Browse the repository at this point in the history
* feat: 사용자 기본 정보 API 연동

* feat: 계좌 정보 관련 API 연동

* feat: 저장 성공 시 cache 무효화 기능 추가

* feat: 에러 케이스 적용

* fix: 타입 오류 수정
  • Loading branch information
alstn2468 authored Feb 12, 2024
1 parent 8338240 commit d6788e1
Show file tree
Hide file tree
Showing 20 changed files with 300 additions and 108 deletions.
16 changes: 8 additions & 8 deletions apps/admin/src/components/AccountInfo/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@ import SettlementDialogContent from '../SettlementDialogContent';
import Styled from './AccountInfo.styles';

interface Props {
orgName?: string;
accountNumber?: string;
accountHolder?: string;
bankName?: string;
bankAccountNumber?: string;
bankAccountHolder?: string;
}

const AccountInfo = ({ orgName, accountHolder, accountNumber }: Props) => {
const AccountInfo = ({ bankName, bankAccountHolder, bankAccountNumber }: Props) => {
const { open, close } = useDialog();
return (
<Styled.Container>
<Styled.Title>정산 계좌 정보</Styled.Title>
<Styled.Description>빠른 정산을 위해서는 정확한 계좌 정보가 필요해요.</Styled.Description>
<Styled.AccountContainer>
{orgName && <Styled.AccountText>{orgName}</Styled.AccountText>}
{accountNumber && <Styled.AccountText>{accountNumber}</Styled.AccountText>}
{accountHolder && <Styled.AccountText>{accountHolder}</Styled.AccountText>}
{bankName && <Styled.AccountText>{bankName}</Styled.AccountText>}
{bankAccountNumber && <Styled.AccountText>{bankAccountNumber}</Styled.AccountText>}
{bankAccountHolder && <Styled.AccountText>{bankAccountHolder}</Styled.AccountText>}
<Button
onClick={() => {
open({
Expand All @@ -30,7 +30,7 @@ const AccountInfo = ({ orgName, accountHolder, accountNumber }: Props) => {
colorTheme="netural"
size="regular"
>
{accountNumber ? '변경하기' : '입력하기'}
{bankAccountNumber ? '변경하기' : '입력하기'}
</Button>
</Styled.AccountContainer>
</Styled.Container>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import styled from '@emotion/styled';

const Container = styled.div``;
const Container = styled.form``;

const Title = styled.h2`
${({ theme }) => theme.typo.b3};
Expand All @@ -14,14 +14,17 @@ const BankList = styled.ul`
grid-template-columns: 1fr 1fr 1fr;
gap: 12px;
overflow-y: scroll;
&::-webkit-scrollbar {
display: none;
}
`;

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

const BankItemButton = styled.button<{ isSelected?: boolean; isNull?: boolean }>`
const BankItemButton = styled.button<{ isSelected?: boolean; isUndefined?: boolean }>`
cursor: pointer;
width: 100%;
height: 100%;
Expand All @@ -38,8 +41,8 @@ const BankItemButton = styled.button<{ isSelected?: boolean; isNull?: boolean }>
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) {
${({ isSelected, isUndefined, theme }) => {
if (isUndefined) {
return ``;
}
if (isSelected) {
Expand Down
102 changes: 63 additions & 39 deletions apps/admin/src/components/SettlementDialogContent/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { queryKey, usePutUserSettlementAccountInfo, useQueryClient } from '@boolti/api';
import { Button, TextField, useToast } from '@boolti/ui';
import { useState } from 'react';
import { SubmitHandler, useForm } from 'react-hook-form';

import { bankItems } from '~/constants/bankItems';
import { useBodyScrollLock } from '~/hooks/useBodyScrollLock';
Expand All @@ -17,15 +19,39 @@ interface Props {
onClose?: VoidFunction;
}

interface SettlementDialogFormInputs {
bankCode: string;
accountHolder: string;
accountNumber: string;
}

const SettlementDialogContent = ({ onClose }: Props) => {
const toast = useToast();
const queryClient = useQueryClient();
const [currentStepIndex, setCurrentStepIndex] = useState(0);
const [selectedBank, setSelectedBank] = useState<string | null>(null);
const [accountNumber, setAccountNumber] = useState<string>('');
const [accountHolder, setAccountHolder] = useState<string>('');
const { setValue, register, handleSubmit, watch } = useForm<SettlementDialogFormInputs>();
const currentBankCode = watch('bankCode');
const currentBankName = bankItems.find(({ code }) => code === currentBankCode)?.name;
const currentAccountHolder = watch('accountHolder');
const currentAccountNumber = watch('accountNumber');
const [accountHolderError, setAccountHolderError] = useState<string | undefined>(undefined);
const [accountNumberError, setAccountNumberError] = useState<string | undefined>(undefined);

const { mutate } = usePutUserSettlementAccountInfo();

const onSubmit: SubmitHandler<SettlementDialogFormInputs> = (data) => {
mutate(data, {
onSuccess: async () => {
toast.success('정산 계좌를 저장했습니다.');
await queryClient.invalidateQueries({ queryKey: queryKey.userAccountInfo.queryKey });
onClose?.();
},
onError: () => {
toast.error('잠시후에 다시 시도하세요.');
},
});
};

useBodyScrollLock();

return (
Expand All @@ -36,10 +62,11 @@ const SettlementDialogContent = ({ onClose }: Props) => {
{bankItems.map((bankItem) => (
<Styled.BankItem key={bankItem.name}>
<Styled.BankItemButton
isNull={selectedBank === null}
isSelected={selectedBank === bankItem.name}
type="button"
isUndefined={currentBankCode === undefined}
isSelected={currentBankCode === bankItem.code}
onClick={() => {
setSelectedBank(bankItem.name);
setValue('bankCode', bankItem.code);
}}
>
<Styled.BankIcon>{<bankItem.icon />}</Styled.BankIcon>
Expand All @@ -57,21 +84,18 @@ const SettlementDialogContent = ({ onClose }: Props) => {
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);
}
}}
{...register('accountNumber', {
required: true,
onBlur(event) {
const value = event.target.value;
setAccountNumberError(
validateAccountNumber(value) && !isNaN(Number(value))
? undefined
: '계좌번호를 확인 후 다시 입력해 주세요.',
);
},
})}
/>
</Styled.InputContainer>
<Styled.InputContainer>
Expand All @@ -80,16 +104,17 @@ const SettlementDialogContent = ({ onClose }: Props) => {
placeholder="예금주 이름을 입력해 주세요"
size="small"
inputType="text"
value={accountHolder}
errorMessage={accountHolderError}
onBlur={(event) => {
setAccountHolderError(
validateAccountHolder(event.target.value) ? undefined : '한글만 입력 가능합니다.',
);
}}
onChange={(event) => {
setAccountHolder(event.target.value);
}}
{...register('accountHolder', {
required: true,
onBlur(event) {
setAccountHolderError(
validateAccountHolder(event.target.value)
? undefined
: '한글만 입력 가능합니다.',
);
},
})}
/>
</Styled.InputContainer>
</>
Expand All @@ -98,15 +123,15 @@ const SettlementDialogContent = ({ onClose }: Props) => {
<Styled.ConfirmContainer>
<Styled.ConfrimTextContainer>
<Styled.ConfirmTextLabel>은행</Styled.ConfirmTextLabel>
<Styled.ConfrimTextValue>{selectedBank}</Styled.ConfrimTextValue>
<Styled.ConfrimTextValue>{currentBankName}</Styled.ConfrimTextValue>
</Styled.ConfrimTextContainer>
<Styled.ConfrimTextContainer>
<Styled.ConfirmTextLabel>계좌번호</Styled.ConfirmTextLabel>
<Styled.ConfrimTextValue>{accountNumber}</Styled.ConfrimTextValue>
<Styled.ConfrimTextValue>{currentAccountNumber}</Styled.ConfrimTextValue>
</Styled.ConfrimTextContainer>
<Styled.ConfrimTextContainer>
<Styled.ConfirmTextLabel>예금주</Styled.ConfirmTextLabel>
<Styled.ConfrimTextValue>{accountHolder}</Styled.ConfrimTextValue>
<Styled.ConfrimTextValue>{currentAccountHolder}</Styled.ConfrimTextValue>
</Styled.ConfrimTextContainer>
</Styled.ConfirmContainer>
)}
Expand All @@ -128,20 +153,19 @@ const SettlementDialogContent = ({ onClose }: Props) => {
colorTheme="primary"
size="bold"
disabled={
(currentStepIndex === 0 && !selectedBank) ||
(currentStepIndex === 0 && !currentBankName) ||
(currentStepIndex === 1 &&
(accountNumber === '' ||
accountHolder === '' ||
(currentAccountNumber === '' ||
currentAccountHolder === '' ||
!!accountHolderError ||
!!accountNumberError))
}
onClick={() => {
if (accountHolderError || accountNumberError) {
onClick={(event) => {
if (currentStepIndex === 1 && (accountHolderError || accountNumberError)) {
return;
}
if (currentStepIndex === 2) {
toast.success('정산 계좌를 저장했습니다.');
onClose?.();
handleSubmit(onSubmit)(event);
return;
}
setCurrentStepIndex((prev) => prev + 1);
Expand Down
7 changes: 6 additions & 1 deletion apps/admin/src/components/UserProfile/UserProfile.styles.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { UserProfile as DefaultUserProfileIcon } from '@boolti/icon';
import styled from '@emotion/styled';

const Container = styled.div`
Expand All @@ -7,7 +8,10 @@ const Container = styled.div`

const ProfileImage = styled.img`
border-radius: 100%;
background-color: ${({ theme }) => theme.palette.grey.g90};
`;

const DefaultProfileImage = styled(DefaultUserProfileIcon)`
border-radius: 100%;
`;

const TextContainer = styled.div`
Expand All @@ -31,4 +35,5 @@ export default {
TextContainer,
Username,
Email,
DefaultProfileImage,
};
12 changes: 8 additions & 4 deletions apps/admin/src/components/UserProfile/index.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import Styled from './UserProfile.styles';

interface Props {
profileImage: string;
profileImage?: string;
username: string;
email: string;
email?: string;
}

const UserProfile = ({ profileImage, username, email }: Props) => {
return (
<Styled.Container>
<Styled.ProfileImage width={68} height={68} alt="" src={profileImage} />
{profileImage ? (
<Styled.ProfileImage width={68} height={68} alt="" src={profileImage} />
) : (
<Styled.DefaultProfileImage />
)}
<Styled.TextContainer>
<Styled.Username>{username}</Styled.Username>
<Styled.Email>{email}</Styled.Email>
<Styled.Email>{email ?? '이메일 정보를 알 수 없습니다.'}</Styled.Email>
</Styled.TextContainer>
</Styled.Container>
);
Expand Down
Loading

0 comments on commit d6788e1

Please sign in to comment.