From be8c6e76bccbb3e5c632ce5de194e451e70682b0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EA=B9=80=EA=B4=80=EC=8B=9D?=
<39869096+gwansikk@users.noreply.github.com>
Date: Sun, 31 Mar 2024 00:25:55 +0900
Subject: [PATCH] =?UTF-8?q?refactor(member):=20=ED=9A=8C=EB=B9=84=20?=
=?UTF-8?q?=EC=82=AC=EC=9A=A9=20=EC=8B=A0=EC=B2=AD=EC=84=9C=20=EA=B0=9C?=
=?UTF-8?q?=EC=84=A0=20(#78)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../SupportRequestForm/SupportRequestForm.tsx | 225 +++++++++++-------
.../SupportRequestSection.tsx | 46 ++++
.../hooks/queries/useMembershipFeeMutation.ts | 7 +-
apps/member/src/types/support.ts | 9 +
4 files changed, 206 insertions(+), 81 deletions(-)
create mode 100644 apps/member/src/components/support/SupportRequestSection/SupportRequestSection.tsx
create mode 100644 apps/member/src/types/support.ts
diff --git a/apps/member/src/components/support/SupportRequestForm/SupportRequestForm.tsx b/apps/member/src/components/support/SupportRequestForm/SupportRequestForm.tsx
index f2a161f3..a9ce6d5b 100644
--- a/apps/member/src/components/support/SupportRequestForm/SupportRequestForm.tsx
+++ b/apps/member/src/components/support/SupportRequestForm/SupportRequestForm.tsx
@@ -1,111 +1,176 @@
-import { Button } from '@clab/design-system';
-import { ChangeEvent, useCallback, useRef, useState } from 'react';
-import { Input } from '@clab/design-system';
-import Section from '@components/common/Section/Section';
-import { useMembershipFeeMutation } from '@hooks/queries/useMembershipFeeMutation';
-import Select from '@components/common/Select/Select';
-import { SELECT_OPTIONS } from '@constants/select';
+import { Button, Input, Checkbox, ButtonSelect } from '@clab/design-system';
+import { ChangeEvent, FormEvent, useCallback, useState } from 'react';
import { formatComma } from '@utils/math';
import useToast from '@hooks/common/useToast';
-import Label from '@components/common/Label/Label';
-import { DEFAULT } from '@constants/default';
-import { FORM_DATA_KEY } from '@constants/api';
+import Linker from '@components/common/Linker/Linker';
+import Uploader from '@components/common/Uploader/Uploader';
+import { FcAnswers, FcMultipleDevices, FcTemplate } from 'react-icons/fc';
+import { SELECT_DEFAULT_OPTION } from '@constants/select';
+import type { SupportRequestDataType } from '@type/support';
-const SupportRequestForm = () => {
- const toast = useToast();
- const { membershipFeeMutate } = useMembershipFeeMutation();
+const typeSelectOptions = [
+ {
+ icon: ,
+ value: '도서',
+ },
+ {
+ icon: ,
+ value: '물품',
+ },
+ {
+ icon: ,
+ value: '기타',
+ },
+];
+
+interface SupportRequestFormProps {
+ isPending: boolean;
+ onSubmit: (data: SupportRequestDataType) => void;
+}
- const imageUploader = useRef(null);
- const [input, setInput] = useState({
- category: DEFAULT.SELECT,
+const SupportRequestForm = ({
+ isPending,
+ onSubmit,
+}: SupportRequestFormProps) => {
+ const toast = useToast();
+ const [checkList, setCheckList] = useState([false, false, false]);
+ const [formData, setFormData] = useState({
+ category: typeSelectOptions[0].value,
amount: 0,
content: '',
+ file: null,
});
- const { category, amount, content } = input;
+ const { category, amount, content, file } = formData;
- const handleInputChange = useCallback(
- (e: ChangeEvent) => {
- setInput((prev) => ({
- ...prev,
- [e.target.name]:
- e.target.name === 'amount'
- ? parseFloat(e.target.value.replace(/,/g, ''))
- : e.target.value,
- }));
- },
- [],
- );
+ const checkSubmitValidation =
+ !checkList.includes(false) && // 체크박스가 모두 체크되어 있을 경우
+ category !== SELECT_DEFAULT_OPTION && // 분류가 기본값이 아닐 경우
+ amount > 0 && // 금액이 0보다 클 경우
+ content.length !== 0 && // 사유가 작성되어 있을 경우
+ file; // 파일이 첨부되어 있을 경우
+ /**
+ * 입력값이 변경될 때마다 상태를 업데이트합니다.
+ */
+ const handleInputChange = useCallback((e: ChangeEvent) => {
+ const { name, value } = e.target;
+ setFormData((prev) => ({
+ ...prev,
+ [name]: name === 'amount' ? parseFloat(value.replace(/,/g, '')) : value,
+ }));
+ }, []);
+ /**
+ * 분류 선택값이 변경될 때마다 상태를 업데이트합니다.
+ */
+ const handleSelectChange = useCallback((value: string) => {
+ setFormData((prev) => ({
+ ...prev,
+ category: value,
+ }));
+ }, []);
+ /**
+ * 파일이 첨부될 때마다 상태를 업데이트합니다.
+ */
+ const handleFileAccepted = useCallback((file: File | null) => {
+ setFormData((prev) => ({
+ ...prev,
+ file,
+ }));
+ }, []);
+ /**
+ * 체크박스가 변경될 때마다 상태를 업데이트합니다.
+ */
+ const handleCheckboxChange = (index: number) => {
+ setCheckList((prev) => {
+ const next = [...prev];
+ next[index] = !prev[index];
+ return next;
+ });
+ };
+ /**
+ * 폼을 제출할 때 실행되는 이벤트입니다.
+ */
+ const handleOnSubmit = (e: FormEvent) => {
+ e.preventDefault();
+ if (isPending) {
+ return;
+ }
- const onClickRequest = async () => {
- if (
- category === 'none' ||
- !amount ||
- !content ||
- !imageUploader.current?.files?.length
- ) {
+ if (!checkSubmitValidation) {
return toast({
state: 'error',
- message: '신청서 항목을 모두 작성해주세요.',
+ message: '모든 항목을 입력해주세요',
});
}
-
- const formData = new FormData();
- const files = imageUploader.current?.files[0];
- formData.append(FORM_DATA_KEY, files, encodeURIComponent(files.name));
-
- membershipFeeMutate({
- body: input,
- multipartFile: imageUploader.current?.files?.length ? formData : null,
- });
+ onSubmit(formData);
};
return (
-
-
-
-
-
-
-
+
);
};
diff --git a/apps/member/src/components/support/SupportRequestSection/SupportRequestSection.tsx b/apps/member/src/components/support/SupportRequestSection/SupportRequestSection.tsx
new file mode 100644
index 00000000..44868da1
--- /dev/null
+++ b/apps/member/src/components/support/SupportRequestSection/SupportRequestSection.tsx
@@ -0,0 +1,46 @@
+import Section from '@components/common/Section/Section';
+import { useMembershipFeeMutation } from '@hooks/queries/useMembershipFeeMutation';
+import { FORM_DATA_KEY } from '@constants/api';
+import SupportRequestForm from '../SupportRequestForm/SupportRequestForm';
+import Linker from '@components/common/Linker/Linker';
+import { PATH } from '@constants/path';
+import type { SupportRequestDataType } from '@type/support';
+
+const SupportRequestSection = () => {
+ const { membershipFeeMutate, isPending } = useMembershipFeeMutation();
+ /**
+ * 사용 신청서를 제출합니다.
+ */
+ const handleRequestSubmit = async (data: SupportRequestDataType) => {
+ const formData = new FormData();
+ if (data.file) {
+ formData.append(
+ FORM_DATA_KEY,
+ data.file,
+ encodeURIComponent(data.file.name),
+ );
+ }
+ membershipFeeMutate({
+ body: data,
+ multipartFile: formData.get(FORM_DATA_KEY) ? formData : null,
+ });
+ };
+
+ return (
+
+
+
+ 혹시 도서 신청을 하시나요? 이미 보유중인 책일 수도 있어요.
+
+
+
+
+
+
+ );
+};
+
+export default SupportRequestSection;
diff --git a/apps/member/src/hooks/queries/useMembershipFeeMutation.ts b/apps/member/src/hooks/queries/useMembershipFeeMutation.ts
index 91d1c09e..87d067c5 100644
--- a/apps/member/src/hooks/queries/useMembershipFeeMutation.ts
+++ b/apps/member/src/hooks/queries/useMembershipFeeMutation.ts
@@ -24,5 +24,10 @@ export const useMembershipFeeMutation = () => {
},
});
- return { membershipFeeMutate: membershipFeeMutation.mutate };
+ membershipFeeMutation.isSuccess;
+
+ return {
+ membershipFeeMutate: membershipFeeMutation.mutate,
+ isPending: membershipFeeMutation.isPending,
+ };
};
diff --git a/apps/member/src/types/support.ts b/apps/member/src/types/support.ts
new file mode 100644
index 00000000..b9577903
--- /dev/null
+++ b/apps/member/src/types/support.ts
@@ -0,0 +1,9 @@
+/**
+ * SupportRequestForm에서 사용되는 데이터 타입
+ */
+export interface SupportRequestDataType {
+ category: string;
+ amount: number;
+ content: string;
+ file: File | null;
+}