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

[FE] 지출 내역 추가 변경사항 적용 #414

Merged
merged 18 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
33c3c66
design: 지출 추가, 인원 추가 button 퍼블리싱
soi-ha Aug 20, 2024
dc4bcd9
feat: 변경된 Button에 BottomSheet onClick연결
soi-ha Aug 20, 2024
cfd953f
chore: 디자인시스템 버전 업데이트
soi-ha Aug 20, 2024
e3e1b6c
feat: step.type이 Bill이 아니더라도 isAddEditableItem가 true라면 BillStepItem을 …
soi-ha Aug 20, 2024
df9e2e2
feat: onChange에 billInput 변경하기 및 blur시 조건을 충족할 경우 서버로 api 요청 보내기
soi-ha Aug 20, 2024
958aeff
feat: 지출 내역 post api를 요청하면 지출 내역 Input을 닫기
soi-ha Aug 20, 2024
dc5a60e
feat: 디자인시스템과의 병합을 위해 Input에 value 추가
soi-ha Aug 20, 2024
7330b72
chore: 불필요한 주석 제거
soi-ha Aug 20, 2024
b48ad94
fix: 불필요한 조건문 제거
soi-ha Aug 20, 2024
62b2cbf
chore: 불필요한 console.log 삭제
soi-ha Aug 20, 2024
5d4a67c
feat: 마지막 BillItem에만 EditableItem.Input을 렌더링하기
soi-ha Aug 20, 2024
930d27a
design: 관리 페이지 디자인 수정
Todari Aug 20, 2024
b4bec69
fix: billInput 값을 초기화
soi-ha Aug 21, 2024
1ea2ee4
Merge branch 'fe-dev' into feature/#399
soi-ha Aug 21, 2024
6152fc5
feat: BillItem이 존재하지 않을 때, 새로운 BillItem을 생성하여 지출 input 만들기
soi-ha Aug 21, 2024
bbf8b4d
feat: member action 추가후, 빈 stepList가 생성되지 않는 에러 해결
soi-ha Aug 21, 2024
deff0f6
chore: 디자인시스템 업데이트
soi-ha Aug 21, 2024
6c2e838
Merge branch 'fe-dev' into feature/#399
soi-ha Aug 21, 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
8 changes: 4 additions & 4 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
"@emotion/react": "^11.11.4",
"@sentry/react": "^8.25.0",
"@tanstack/react-query": "^5.51.23",
"haengdong-design": "^0.1.74",
"haengdong-design": "^0.1.75",
"react": "^18.3.1",
"react-copy-to-clipboard": "^5.1.0",
"react-dom": "^18.3.1",
Expand All @@ -80,4 +80,4 @@
"npm": ">=10.7.0",
"node": ">=20.15.1"
}
}
}
84 changes: 62 additions & 22 deletions client/src/components/StepList/BillStepItem.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,41 @@
import type {BillStep, MemberReport} from 'types/serviceType';

import {DragHandleItem, DragHandleItemContainer} from 'haengdong-design';
import {DragHandleItem, DragHandleItemContainer, EditableItem, Flex, Text} from 'haengdong-design';
import {Fragment, useState} from 'react';
import {useOutletContext} from 'react-router-dom';

import {BillStep, MemberReport} from 'types/serviceType';
import {PutAndDeleteBillActionModal} from '@components/Modal/SetActionModal/PutAndDeleteBillActionModal';
import {MemberListInBillStep} from '@components/Modal/MemberListInBillStep';
import {EventPageContextProps} from '@pages/EventPage/EventPageLayout';

import useSetBillInput from '@hooks/useSetBillInput';

interface BillStepItemProps {
step: BillStep;
isOpenBottomSheet: boolean;
setIsOpenBottomSheet: React.Dispatch<React.SetStateAction<boolean>>;
isAddEditableItem: boolean;
setIsAddEditableItem: React.Dispatch<React.SetStateAction<boolean>>;
isLastBillItem: boolean;
index: number;
}

const BillStepItem: React.FC<BillStepItemProps> = ({step, isOpenBottomSheet, setIsOpenBottomSheet}) => {
const BillStepItem: React.FC<BillStepItemProps> = ({
step,
isOpenBottomSheet,
setIsOpenBottomSheet,
isAddEditableItem,
setIsAddEditableItem,
isLastBillItem,
index,
}) => {
const {isAdmin} = useOutletContext<EventPageContextProps>();
const {handleBlurBillRequest, handleChangeBillInput, billInput} = useSetBillInput({setIsAddEditableItem});

const [clickedIndex, setClickedIndex] = useState(-1);
const [isOpenMemberListInBillStep, setIsOpenMemberListInBillStep] = useState(false);

const stepName = `차`;
const totalPrice = step.actions.reduce((acc, cur) => acc + cur.price, 0);
const totalPrice = step.actions && step.type === 'BILL' ? step.actions.reduce((acc, cur) => acc + cur.price, 0) : 0;
Copy link
Contributor

Choose a reason for hiding this comment

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

오 step.type이 BILL 인 경우만 BillStep 컴포넌트로 들어오는 줄 알았는데 아니었군요.?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Step에서의 조건 때문에 BillStepItem에서 위 조건문을 추가하게 되었어요!


const handleDragHandleItemClick = (index: number) => {
setClickedIndex(index);
Expand All @@ -39,31 +54,56 @@ const BillStepItem: React.FC<BillStepItemProps> = ({step, isOpenBottomSheet, set
return (
<>
<DragHandleItemContainer
id={`${index}`}
topLeftText={stepName}
topRightText={`${step.members.length}명`}
bottomLeftText="총액"
bottomRightText={`${totalPrice.toLocaleString('ko-kr')} 원`}
backgroundColor="white"
onTopRightTextClick={handleTopRightTextClick}
>
{step.actions.map((action, index) => (
<Fragment key={action.actionId}>
<DragHandleItem
hasDragHandler={isAdmin}
prefix={action.name}
suffix={`${action.price.toLocaleString('ko-kr')} 원`}
backgroundColor="lightGrayContainer"
onClick={() => handleDragHandleItemClick(index)}
/>
{isOpenBottomSheet && clickedIndex === index && isAdmin && (
<PutAndDeleteBillActionModal
billAction={action}
isBottomSheetOpened={isOpenBottomSheet}
setIsBottomSheetOpened={setIsOpenBottomSheet}
{step.actions &&
step.type === 'BILL' &&
step.actions.map((action, index) => (
<Fragment key={action.actionId}>
<DragHandleItem
hasDragHandler={isAdmin}
prefix={action.name}
suffix={`${action.price.toLocaleString('ko-kr')} 원`}
backgroundColor="lightGrayContainer"
onClick={() => handleDragHandleItemClick(index)}
/>
)}
</Fragment>
))}

{isOpenBottomSheet && clickedIndex === index && isAdmin && (
<PutAndDeleteBillActionModal
billAction={action}
isBottomSheetOpened={isOpenBottomSheet}
setIsBottomSheetOpened={setIsOpenBottomSheet}
/>
)}
</Fragment>
))}

{isAddEditableItem && isLastBillItem && (
<EditableItem backgroundColor="lightGrayContainer" onBlur={handleBlurBillRequest}>
<EditableItem.Input
placeholder="지출 내역"
textSize="bodyBold"
value={billInput.title}
onChange={e => handleChangeBillInput('title', e)}
></EditableItem.Input>
<Flex gap="0.25rem" alignItems="center">
<EditableItem.Input
placeholder="0"
type="number"
value={billInput.price}
onChange={e => handleChangeBillInput('price', e)}
style={{textAlign: 'right'}}
></EditableItem.Input>
<Text size="caption">원</Text>
</Flex>
</EditableItem>
)}
Todari marked this conversation as resolved.
Show resolved Hide resolved
</DragHandleItemContainer>
{isOpenMemberListInBillStep && (
<MemberListInBillStep
Expand Down
30 changes: 25 additions & 5 deletions client/src/components/StepList/Step.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,42 @@
import type {BillStep, MemberStep} from 'types/serviceType';

import {useState} from 'react';
import {useEffect, useState} from 'react';

import BillStepItem from './BillStepItem';
import MemberStepItem from './MemberStepItem';

interface StepProps {
step: BillStep | MemberStep;
isAddEditableItem: boolean;
lastBillItemIndex: number;
setIsAddEditableItem: React.Dispatch<React.SetStateAction<boolean>>;
index: number;
}

const Step = ({step}: StepProps) => {
const Step = ({step, isAddEditableItem, lastBillItemIndex, setIsAddEditableItem, index}: StepProps) => {
const [isOpenBottomSheet, setIsOpenBottomSheet] = useState<boolean>(false);
const [isLastBillItem, setIsLastBillItem] = useState<boolean>(false);

if (step.type === 'BILL') {
useEffect(() => {
if (index === lastBillItemIndex) {
// index를 사용하여 마지막 BillStep인지 확인
setIsLastBillItem(true);
}
}, [index, lastBillItemIndex]);

if (step.actions && step.type === 'BILL') {
return (
<BillStepItem step={step} isOpenBottomSheet={isOpenBottomSheet} setIsOpenBottomSheet={setIsOpenBottomSheet} />
<BillStepItem
index={index}
step={step as BillStep}
isOpenBottomSheet={isOpenBottomSheet}
setIsOpenBottomSheet={setIsOpenBottomSheet}
isAddEditableItem={isAddEditableItem}
setIsAddEditableItem={setIsAddEditableItem}
isLastBillItem={isLastBillItem}
/>
);
} else if (step.type === 'IN' || step.type === 'OUT') {
} else if (step.actions && (step.type === 'IN' || step.type === 'OUT')) {
return (
<MemberStepItem step={step} isOpenBottomSheet={isOpenBottomSheet} setIsOpenBottomSheet={setIsOpenBottomSheet} />
);
Expand Down
25 changes: 21 additions & 4 deletions client/src/components/StepList/StepList.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,38 @@
import {Flex} from 'haengdong-design';
import {useMemo} from 'react';

import {BillStep, MemberStep} from 'types/serviceType';
import useRequestGetStepList from '@hooks/queries/useRequestGetStepList';

import Step from './Step';

const StepList = () => {
// const {stepList} = useStepList();
interface StepListProps {
isAddEditableItem: boolean;
setIsAddEditableItem: React.Dispatch<React.SetStateAction<boolean>>;
}

const StepList = ({isAddEditableItem, setIsAddEditableItem}: StepListProps) => {
const {data: stepListData} = useRequestGetStepList();
const stepList = stepListData ?? ([] as (MemberStep | BillStep)[]);

// TODO: (@weadie) if else 구문이 지저분하므로 리펙터링이 필요합니다.
const lastBillItemIndex = useMemo(() => {
const billSteps = stepList.map((step, index) => ({...step, index})).filter(step => step.type === 'BILL');

// billSteps 배열이 비어 있지 않으면 마지막 항목의 index를 반환, 그렇지 않으면 -1을 반환
return billSteps.length > 0 ? billSteps.slice(-1)[0].index : -1;
}, [stepList]);

return (
<Flex flexDirection="column" gap="0.5rem" paddingInline="0.5rem">
{stepList.map((step, index) => (
<Step step={step} key={`${step.stepName}${index}`} />
<Step
index={index}
step={step}
lastBillItemIndex={lastBillItemIndex}
key={`${step.stepName}${index}`}
Copy link
Contributor

Choose a reason for hiding this comment

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

stepName이 지금 없으니 이렇게 하는게 맞네요

isAddEditableItem={isAddEditableItem}
setIsAddEditableItem={setIsAddEditableItem}
/>
))}
</Flex>
);
Expand Down
65 changes: 65 additions & 0 deletions client/src/hooks/useSetBillInput.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import {useState} from 'react';

import validatePurchase from '@utils/validate/validatePurchase';
import {Bill} from 'types/serviceType';

import useRequestPostBillList from './queries/useRequestPostBillList';
import {BillInputType, InputPair} from './useDynamicBillActionInput';

interface UseSetBillInputProps {
setIsAddEditableItem: React.Dispatch<React.SetStateAction<boolean>>;
}

interface UseSetBillInputReturns {
billInput: Bill;
handleChangeBillInput: (field: BillInputType, event: React.ChangeEvent<HTMLInputElement>) => void;
handleBlurBillRequest: () => void;
}

const useSetBillInput = ({setIsAddEditableItem}: UseSetBillInputProps): UseSetBillInputReturns => {
const initialInput = {title: '', price: 0};
const [billInput, setBillInput] = useState<Bill>(initialInput);

const {mutate: postBillList} = useRequestPostBillList();

const handleChangeBillInput = (field: BillInputType, event: React.ChangeEvent<HTMLInputElement>) => {
const {value} = event.target;
const {isValid} = validatePurchase({
...billInput,
[field]: value,
});

if (isValid) {
setBillInput(prev => ({
...prev,
[field]: value,
}));
}
};

Comment on lines +20 to +39
Copy link
Contributor

Choose a reason for hiding this comment

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

bill 저도 차등 기능 넣을 때 써야하는데 참고할게요..! 굿

const handleBlurBillRequest = () => {
const isEmptyTitle = billInput.title.trim().length;
const isEmptyPrice = Number(billInput.price);

// 두 input의 값이 모두 채워졌을 때 api 요청
// api 요청을 하면 Input을 띄우지 않음
if (isEmptyTitle && isEmptyPrice) {
postBillList(
{billList: [billInput]},
{
onSuccess: () => {
setIsAddEditableItem(false);
},
Todari marked this conversation as resolved.
Show resolved Hide resolved
},
);
}
};

return {
billInput,
handleBlurBillRequest,
handleChangeBillInput,
};
};

export default useSetBillInput;
11 changes: 9 additions & 2 deletions client/src/pages/EventPage/AdminPage/AdminPage.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ export const receiptStyle = () =>
css({
display: 'flex',
flexDirection: 'column',
gap: '8px',
padding: '0 8px',
gap: '1rem',
paddingBottom: '8.75rem',
});

Expand All @@ -14,3 +13,11 @@ export const titleAndListButtonContainerStyle = () =>
display: 'flex',
flexDirection: 'column',
});

export const buttonGroupStyle = () =>
css({
display: 'flex',
width: '100%',
padding: '0 0.5rem',
gap: '0.5rem',
});
28 changes: 21 additions & 7 deletions client/src/pages/EventPage/AdminPage/AdminPage.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {useEffect, useState} from 'react';
import {Title, FixedButton, ListButton} from 'haengdong-design';
import {Title, FixedButton, ListButton, Button} from 'haengdong-design';
import {useOutletContext} from 'react-router-dom';

import StepList from '@components/StepList/StepList';
Expand All @@ -11,11 +11,12 @@ import {useTotalExpenseAmountStore} from '@store/totalExpenseAmountStore';

import {EventPageContextProps} from '../EventPageLayout';

import {receiptStyle, titleAndListButtonContainerStyle} from './AdminPage.style';
import {receiptStyle, titleAndListButtonContainerStyle, buttonGroupStyle} from './AdminPage.style';

const AdminPage = () => {
const [isOpenFixedButtonBottomSheet, setIsOpenFixedButtonBottomSheet] = useState(false);
const [isOpenAllMemberListButton, setIsOpenAllMemberListButton] = useState(false);
const [isAddEditableItem, setIsAddEditableItem] = useState(false);

const {eventName} = useOutletContext<EventPageContextProps>();
const {data: allMemberListData} = useRequestGetAllMemberList();
Expand Down Expand Up @@ -54,11 +55,24 @@ const AdminPage = () => {
)}
</div>
<section css={receiptStyle}>
<StepList />
<FixedButton
children={allMemberList.length === 0 ? '시작인원 추가하기' : '행동 추가하기'}
onClick={() => setIsOpenFixedButtonBottomSheet(prev => !prev)}
/>
<StepList isAddEditableItem={isAddEditableItem} setIsAddEditableItem={setIsAddEditableItem} />
{allMemberList.length === 0 ? (
<FixedButton children={'시작인원 추가하기'} onClick={() => setIsOpenFixedButtonBottomSheet(prev => !prev)} />
) : (
<div css={buttonGroupStyle}>
<Button
size="medium"
variants="tertiary"
style={{width: '100%'}}
onClick={() => setIsOpenFixedButtonBottomSheet(prev => !prev)}
>
인원 변동 추가
</Button>
<Button size="medium" onClick={() => setIsAddEditableItem(true)} style={{width: '100%'}}>
지출 내역 추가
</Button>
</div>
)}
{isOpenFixedButtonBottomSheet && (
<ModalBasedOnMemberCount
allMemberList={allMemberList}
Expand Down