diff --git a/src/pages/common/register/RegisterPage.tsx b/src/pages/common/register/RegisterPage.tsx
index a35b932f..c6a8b1ff 100644
--- a/src/pages/common/register/RegisterPage.tsx
+++ b/src/pages/common/register/RegisterPage.tsx
@@ -4,6 +4,7 @@ import { useForm } from 'react-hook-form';
import { RegisterFields, RegisterType, Tos } from './components';
import { useRegister } from './store/hooks';
import { FormValues } from './types';
+import { parsePhoneNumber } from '@/shared';
import { BasicButton } from '@/shared/components';
import { Divider } from '@chakra-ui/react';
import styled from '@emotion/styled';
@@ -29,12 +30,11 @@ const RegisterPage = () => {
const requestData = {
name: data.name,
- phoneNumber: data.phoneNumber,
+ phoneNumber: parsePhoneNumber(data.phoneNumber),
email: 'test1@example.com', // 임시 (카카오 로그인 후 넘겨받기)
isSinitto,
};
console.log(requestData);
- // 회원가입 API 호출
mutation.mutate(requestData);
};
diff --git a/src/pages/guard/register/SeniorRegisterPage.tsx b/src/pages/guard/register/SeniorRegisterPage.tsx
index 530eabe7..60847a8f 100644
--- a/src/pages/guard/register/SeniorRegisterPage.tsx
+++ b/src/pages/guard/register/SeniorRegisterPage.tsx
@@ -1,58 +1,28 @@
-import { useState } from 'react';
-
+import { useGetAllSeniorInfo } from '../mypage';
import { SeniorInfo } from './components';
-import { SENIOR_DATA } from './data';
-import { Box, Flex, Input, Text } from '@chakra-ui/react';
+import SeniorRegisterBox from './components/senior-register-box/SeniorRegisterBox';
+import { Box, Flex } from '@chakra-ui/react';
import styled from '@emotion/styled';
export const SeniorRegisterPage = () => {
- const [name, setName] = useState('');
- const [seniorName, setSeniorName] = useState('');
- const [phoneNumber, setPhoneNumber] = useState('');
+ const { data: seniors, isLoading, isError, refetch } = useGetAllSeniorInfo();
- const handleRegister = () => {
- setName('');
- setSeniorName('');
- setPhoneNumber('');
- };
+ if (isLoading) {
+ return
Loading...
;
+ }
+
+ if (isError) {
+ return Error
;
+ }
return (
-
- {SENIOR_DATA.map((senior) => (
-
+
+ {seniors?.map((senior) => (
+
))}
-
-
-
- 등록 이름
- setName(e.target.value)}
- />
-
-
- 시니어의 성함
- setSeniorName(e.target.value)}
- />
-
-
- 시니어의 전화번호
- setPhoneNumber(e.target.value)}
- />
-
- 시니어 등록
-
+
+
);
};
@@ -60,60 +30,16 @@ export const SeniorRegisterPage = () => {
const Container = styled(Box)`
position: relative;
height: 100vh;
-`;
-
-const RegisterBox = styled(Box)`
- position: absolute;
- bottom: 0;
- width: 100%;
- height: 360px;
- left: 50%;
- transform: translateX(-50%);
- max-width: 370px;
display: flex;
flex-direction: column;
- align-items: center;
- background-color: var(--color-white-gray);
- border: 1px solid var(--color-white-gray);
- border-radius: 15px;
`;
-const InputBox = styled(Box)`
- width: 300px;
- height: 80px;
- display: flex;
+const SeniorInfoContainer = styled(Flex)`
+ flex-grow: 1;
+ overflow-y: auto;
+ height: 70vh;
flex-direction: column;
- margin: 0.5rem;
-`;
-
-const InputText = styled(Text)`
- font-size: 18px;
- font-weight: bold;
- margin-bottom: 0.5rem;
-`;
-
-const RegisterInput = styled(Input)`
- background-color: var(--color-white);
- border: none;
- font-size: 1rem;
+ align-items: center;
`;
-const StyledButton = styled.button`
- width: 300px;
- height: 40px;
- background-color: #c69090;
- color: #ffffff;
- border: none;
- border-radius: 5px;
- cursor: pointer;
- font-size: 16px;
- transition: background-color 0.3s;
-
- &:hover {
- background-color: #a67070;
- }
-
- &:active {
- transform: scale(0.98);
- }
-`;
+export default SeniorRegisterPage;
diff --git a/src/pages/guard/register/api/hooks/index.ts b/src/pages/guard/register/api/hooks/index.ts
new file mode 100644
index 00000000..a772528f
--- /dev/null
+++ b/src/pages/guard/register/api/hooks/index.ts
@@ -0,0 +1,3 @@
+export { useAddSeniorInfo } from './useAddSeniorInfo';
+export { useDeleteSeniorInfo } from './useDeleteSeniorInfo';
+export { useEditSeniorInfo } from './useEditSeniorInfo';
diff --git a/src/pages/guard/register/api/hooks/useAddSeniorInfo.ts b/src/pages/guard/register/api/hooks/useAddSeniorInfo.ts
new file mode 100644
index 00000000..3498a74d
--- /dev/null
+++ b/src/pages/guard/register/api/hooks/useAddSeniorInfo.ts
@@ -0,0 +1,20 @@
+import { addSeniorInfo } from '../senior-info.api';
+import { SeniorRegisterValues as SeniorRegisterRequest } from '../types/senior-register.type';
+import { useMutation, UseMutationResult } from '@tanstack/react-query';
+
+// 시니어 추가 훅
+export const useAddSeniorInfo = (
+ refetchCallback: () => void
+): UseMutationResult => {
+ return useMutation({
+ mutationFn: (seniorInfo: SeniorRegisterRequest) =>
+ addSeniorInfo(seniorInfo),
+ onSuccess: (data: string) => {
+ alert(data);
+ refetchCallback();
+ },
+ onError: (error: Error) => {
+ console.error(error);
+ },
+ });
+};
diff --git a/src/pages/guard/register/api/hooks/useDeleteSeniorInfo.ts b/src/pages/guard/register/api/hooks/useDeleteSeniorInfo.ts
new file mode 100644
index 00000000..ae77c42e
--- /dev/null
+++ b/src/pages/guard/register/api/hooks/useDeleteSeniorInfo.ts
@@ -0,0 +1,18 @@
+import { deleteSeniorInfo } from '../senior-info.api';
+import { useMutation, UseMutationResult } from '@tanstack/react-query';
+
+// 시니어 삭제 훅
+export const useDeleteSeniorInfo = (
+ refetchCallback: () => void
+): UseMutationResult => {
+ return useMutation({
+ mutationFn: (seniorId: number) => deleteSeniorInfo(seniorId),
+ onSuccess: (data: string) => {
+ alert(data);
+ refetchCallback();
+ },
+ onError: (error: Error) => {
+ console.error(error);
+ },
+ });
+};
diff --git a/src/pages/guard/register/api/hooks/useEditSeniorInfo.ts b/src/pages/guard/register/api/hooks/useEditSeniorInfo.ts
new file mode 100644
index 00000000..83892b00
--- /dev/null
+++ b/src/pages/guard/register/api/hooks/useEditSeniorInfo.ts
@@ -0,0 +1,24 @@
+import { editSeniorInfo } from '../senior-info.api';
+import { SeniorRegisterValues as SeniorRegisterRequest } from '../types/senior-register.type';
+import { useMutation, UseMutationResult } from '@tanstack/react-query';
+
+// 시니어 수정 훅
+export const useEditSeniorInfo = (
+ refetchCallback: () => void
+): UseMutationResult<
+ string,
+ Error,
+ { seniorId: number; seniorInfo: SeniorRegisterRequest }
+> => {
+ return useMutation({
+ mutationFn: ({ seniorId, seniorInfo }) =>
+ editSeniorInfo(seniorId, seniorInfo),
+ onSuccess: (data: string) => {
+ alert(data);
+ refetchCallback(); // 새로 데이터 가져오기 (콜백함수)
+ },
+ onError: (error: Error) => {
+ console.error(error);
+ },
+ });
+};
diff --git a/src/pages/guard/register/api/index.ts b/src/pages/guard/register/api/index.ts
new file mode 100644
index 00000000..b65e5352
--- /dev/null
+++ b/src/pages/guard/register/api/index.ts
@@ -0,0 +1,8 @@
+export {
+ addSeniorInfo,
+ deleteSeniorInfo,
+ editSeniorInfo,
+} from './senior-info.api';
+
+export * from './hooks';
+export * from './types';
diff --git a/src/pages/guard/register/api/senior-info.api.ts b/src/pages/guard/register/api/senior-info.api.ts
new file mode 100644
index 00000000..c2301e1e
--- /dev/null
+++ b/src/pages/guard/register/api/senior-info.api.ts
@@ -0,0 +1,30 @@
+import { SeniorRegisterValues as SeniorRegisterRequest } from './types/senior-register.type';
+import { fetchInstance } from '@/shared/api/instance';
+
+export const seniorInfoPath = () => '/api/guards/senior';
+
+// 시니어 추가
+export const addSeniorInfo = async (seniorInfo: SeniorRegisterRequest) => {
+ const response = await fetchInstance.post(seniorInfoPath(), seniorInfo);
+ return response.data;
+};
+
+// 시니어 삭제
+export const deleteSeniorInfo = async (seniorId: number) => {
+ const response = await fetchInstance.delete(
+ seniorInfoPath() + `/${seniorId}`
+ );
+ return response.data;
+};
+
+// 시니어 정보 수정
+export const editSeniorInfo = async (
+ seniorId: number,
+ seniorInfo: SeniorRegisterRequest
+) => {
+ const response = await fetchInstance.put(
+ seniorInfoPath() + `/${seniorId}`,
+ seniorInfo
+ );
+ return response.data;
+};
diff --git a/src/pages/guard/register/api/types/index.ts b/src/pages/guard/register/api/types/index.ts
new file mode 100644
index 00000000..0c1223b8
--- /dev/null
+++ b/src/pages/guard/register/api/types/index.ts
@@ -0,0 +1 @@
+export type { SeniorRegisterValues } from './senior-register.type';
diff --git a/src/pages/guard/register/api/types/senior-register.type.ts b/src/pages/guard/register/api/types/senior-register.type.ts
new file mode 100644
index 00000000..e67a5786
--- /dev/null
+++ b/src/pages/guard/register/api/types/senior-register.type.ts
@@ -0,0 +1,4 @@
+export type SeniorRegisterValues = {
+ seniorName: string;
+ seniorPhoneNumber: string;
+};
diff --git a/src/pages/guard/register/components/index.ts b/src/pages/guard/register/components/index.ts
index f70b7392..f1362dbd 100644
--- a/src/pages/guard/register/components/index.ts
+++ b/src/pages/guard/register/components/index.ts
@@ -1 +1,2 @@
export * from './senior-info';
+export * from './senior-register-box';
diff --git a/src/pages/guard/register/components/senior-info/senior-info-box/SeniorInfo.tsx b/src/pages/guard/register/components/senior-info/senior-info-box/SeniorInfo.tsx
index c5b8adef..8d6ce92a 100644
--- a/src/pages/guard/register/components/senior-info/senior-info-box/SeniorInfo.tsx
+++ b/src/pages/guard/register/components/senior-info/senior-info-box/SeniorInfo.tsx
@@ -1,32 +1,125 @@
-import { Box, Flex, Text } from '@chakra-ui/react';
+import { useState } from 'react';
+
+import { useDeleteSeniorInfo, useEditSeniorInfo } from '../../../api';
+import { formatPhoneNumber } from '@/shared';
+import { deleteIcon, editIcon } from '@/shared/assets';
+import { Box, Flex, Text, Image, Input } from '@chakra-ui/react';
import styled from '@emotion/styled';
type SeniorInfoType = {
- title: string;
- name: string;
- phoneNumber: string;
+ seniorName: string;
+ seniorPhoneNumber: string;
+ seniorId: number;
};
-const SeniorInfo = ({ senior }: { senior: SeniorInfoType }) => {
+const SeniorInfo = ({
+ senior,
+ refetch,
+}: {
+ senior: SeniorInfoType;
+ refetch: () => void;
+}) => {
+ const [isEditing, setIsEditing] = useState(false);
+ const [seniorName, setSeniorName] = useState(senior.seniorName);
+ const [seniorPhoneNumber, setSeniorPhoneNumber] = useState(
+ senior.seniorPhoneNumber
+ );
+
+ const deleteMutation = useDeleteSeniorInfo(refetch);
+ const editMutation = useEditSeniorInfo(refetch);
+
+ const handleDelete = () => {
+ deleteMutation.mutate(senior.seniorId);
+ };
+
+ const handleEdit = () => {
+ editMutation.mutate({
+ seniorId: senior.seniorId,
+ seniorInfo: { seniorName, seniorPhoneNumber },
+ });
+ setIsEditing(false);
+ };
+
return (
-
-
- {senior.title}
-
-
- 성함
- {senior.name}
-
-
- 전화번호
- {senior.phoneNumber}
-
-
+ {isEditing ? (
+
+
+ setSeniorName(e.target.value)}
+ placeholder='이름을 입력하세요'
+ size='sm'
+ bg='var(--color-white)'
+ border='1px solid var(--color-white)'
+ borderRadius='10px'
+ />
+ setSeniorPhoneNumber(e.target.value)}
+ placeholder='전화번호를 입력하세요'
+ bg='var(--color-white)'
+ border='1px solid var(--color-white)'
+ borderRadius='10px'
+ size='sm'
+ />
+
+
+ 저장
+
+
+ ) : (
+
+
+
+ {senior.seniorName}
+
+
+ setIsEditing(true)}
+ />
+
+
+
+
+ 전화번호
+ {formatPhoneNumber(senior.seniorPhoneNumber)}
+
+
+ )}
);
};
@@ -34,8 +127,8 @@ const SeniorInfo = ({ senior }: { senior: SeniorInfoType }) => {
const SeniorInfoContainer = styled(Flex)`
width: 100%;
max-width: 330px;
- height: 6rem;
- min-height: 6rem;
+ height: 5rem;
+ min-height: 5rem;
background-color: var(--color-secondary);
border: 1px solid var(--color-secondary);
border-radius: 10px;
diff --git a/src/pages/guard/register/components/senior-register-box/SeniorFormField.tsx b/src/pages/guard/register/components/senior-register-box/SeniorFormField.tsx
new file mode 100644
index 00000000..d439bf29
--- /dev/null
+++ b/src/pages/guard/register/components/senior-register-box/SeniorFormField.tsx
@@ -0,0 +1,53 @@
+import { UseFormRegister } from 'react-hook-form';
+
+import { SeniorRegisterValues } from '../../api';
+import { Box, Input, Text } from '@chakra-ui/react';
+import styled from '@emotion/styled';
+
+type Props = {
+ label: string;
+ placeholder: string;
+ error?: string;
+ registerProps: ReturnType>;
+};
+
+const SeniorFormField = ({
+ label,
+ placeholder,
+ error,
+ registerProps,
+}: Props) => {
+ return (
+
+
+
+ {error && {error}}
+
+ );
+};
+
+export default SeniorFormField;
+
+const FieldContainer = styled(Box)`
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+`;
+
+const Label = styled(Text)`
+ font-size: 18px;
+ font-weight: bold;
+ margin-bottom: 0.5rem;
+`;
+
+const StyledInput = styled(Input)`
+ background-color: var(--color-white);
+ border: none;
+ font-size: 1rem;
+ margin-bottom: 0.5rem;
+`;
+
+const ErrorMessage = styled(Text)`
+ color: red;
+ font-size: 14px;
+`;
diff --git a/src/pages/guard/register/components/senior-register-box/SeniorRegisterBox.tsx b/src/pages/guard/register/components/senior-register-box/SeniorRegisterBox.tsx
new file mode 100644
index 00000000..18144347
--- /dev/null
+++ b/src/pages/guard/register/components/senior-register-box/SeniorRegisterBox.tsx
@@ -0,0 +1,97 @@
+import { useForm } from 'react-hook-form';
+
+import { SeniorRegisterValues, useAddSeniorInfo } from '../../api';
+import SeniorFormField from './SeniorFormField';
+import { parsePhoneNumber } from '@/shared';
+import { Box } from '@chakra-ui/react';
+import styled from '@emotion/styled';
+
+const SeniorRegisterBox = ({ refetch }: { refetch: () => void }) => {
+ const {
+ register,
+ handleSubmit,
+ formState: { errors },
+ } = useForm();
+ const { mutate: postSeniorInfo } = useAddSeniorInfo(refetch);
+
+ const onSubmit = (data: SeniorRegisterValues) => {
+ const requestSeniorData = {
+ seniorName: data.seniorName,
+ seniorPhoneNumber: parsePhoneNumber(data.seniorPhoneNumber),
+ };
+ postSeniorInfo(requestSeniorData);
+ };
+
+ return (
+
+
+
+
+
+
+
+ 시니어 등록
+
+ );
+};
+
+export default SeniorRegisterBox;
+
+const RegisterBox = styled(Box)`
+ position: relative;
+ width: 100%;
+ height: auto;
+ left: 50%;
+ transform: translateX(-50%);
+ max-width: 370px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ background-color: var(--color-white-gray);
+ border: 1px solid var(--color-white-gray);
+ border-radius: 15px;
+`;
+
+const InputBox = styled(Box)`
+ width: 300px;
+ margin: 0.5rem;
+`;
+
+const StyledButton = styled.button`
+ width: 300px;
+ height: 40px;
+ background-color: #c69090;
+ color: #ffffff;
+ border: none;
+ border-radius: 5px;
+ cursor: pointer;
+ font-size: 16px;
+ transition: background-color 0.3s;
+ margin-bottom: 10px;
+
+ &:hover {
+ background-color: #a67070;
+ }
+
+ &:active {
+ transform: scale(0.98);
+ }
+`;
diff --git a/src/pages/guard/register/components/senior-register-box/index.ts b/src/pages/guard/register/components/senior-register-box/index.ts
new file mode 100644
index 00000000..f12a913e
--- /dev/null
+++ b/src/pages/guard/register/components/senior-register-box/index.ts
@@ -0,0 +1,2 @@
+export { default as SeniorRegisterBox } from './SeniorRegisterBox';
+export { default as SeniorFormField } from './SeniorFormField';
diff --git a/src/pages/guard/register/index.ts b/src/pages/guard/register/index.ts
index e795c5b8..c2af5082 100644
--- a/src/pages/guard/register/index.ts
+++ b/src/pages/guard/register/index.ts
@@ -2,3 +2,4 @@ export { SeniorRegisterPage } from './SeniorRegisterPage';
export * from './components';
export * from './data';
+export * from './api';
diff --git a/src/pages/guard/register/types/index.tsx b/src/pages/guard/register/types/index.tsx
deleted file mode 100644
index e69de29b..00000000
diff --git a/src/shared/assets/delete-icon.svg b/src/shared/assets/delete-icon.svg
new file mode 100644
index 00000000..c153dad3
--- /dev/null
+++ b/src/shared/assets/delete-icon.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/shared/assets/edit-icon.svg b/src/shared/assets/edit-icon.svg
new file mode 100644
index 00000000..d4eb690d
--- /dev/null
+++ b/src/shared/assets/edit-icon.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/shared/assets/index.ts b/src/shared/assets/index.ts
new file mode 100644
index 00000000..18e64c15
--- /dev/null
+++ b/src/shared/assets/index.ts
@@ -0,0 +1,2 @@
+export { default as deleteIcon } from './delete-icon.svg';
+export { default as editIcon } from './edit-icon.svg';
diff --git a/src/shared/components/features/header/Header.tsx b/src/shared/components/features/header/Header.tsx
index 73f66e76..2c5e200a 100644
--- a/src/shared/components/features/header/Header.tsx
+++ b/src/shared/components/features/header/Header.tsx
@@ -44,6 +44,7 @@ const HeaderBox = styled.header`
justify-content: center;
align-items: center;
background-color: var(--color-white);
+ z-index: 10;
`;
const Icon = styled(Image)`
diff --git a/src/shared/components/features/mypage/point-log-box/PointLogBox.tsx b/src/shared/components/features/mypage/point-log-box/PointLogBox.tsx
index 0e0e3141..6a70ada3 100644
--- a/src/shared/components/features/mypage/point-log-box/PointLogBox.tsx
+++ b/src/shared/components/features/mypage/point-log-box/PointLogBox.tsx
@@ -2,7 +2,7 @@ import { useState } from 'react';
import PointLogImg from '../../../../assets/point-log-icon.png';
import { getPointStatusLabel, useGetPointLogs } from '@/shared/hooks';
-import { Box, Image } from '@chakra-ui/react';
+import { Box, Image, Text } from '@chakra-ui/react';
import styled from '@emotion/styled';
const PointLogBox = () => {
@@ -40,7 +40,25 @@ const PointLogBox = () => {
{item.content}
- {item.price.toLocaleString()}
+
+ {(item.status === 'SPEND_COMPLETE' ||
+ item.status === 'WITHDRAW_COMPLETE'
+ ? '-'
+ : item.status === 'EARN' ||
+ item.status === 'CHARGE_COMPLETE'
+ ? '+'
+ : '') + item.price.toLocaleString()}
+
@@ -153,3 +171,8 @@ const DetailText = styled(Box)`
font-size: 16px;
font-weight: 600;
`;
+
+const PriceText = styled(Text)`
+ font-size: 16px;
+ font-weight: 600;
+`;
diff --git a/src/shared/hooks/index.ts b/src/shared/hooks/index.ts
index 86d45520..1d40b502 100644
--- a/src/shared/hooks/index.ts
+++ b/src/shared/hooks/index.ts
@@ -1,3 +1,4 @@
export { useIntersectionObserver } from './useIntersectionObserver';
export type { UseIntersectionObserverProps } from './useIntersectionObserver';
export * from './point';
+export * from './phone-number';
diff --git a/src/shared/index.ts b/src/shared/index.ts
index 8ec826f3..634e7aa1 100644
--- a/src/shared/index.ts
+++ b/src/shared/index.ts
@@ -3,3 +3,4 @@ export * from './constants';
export * from './hooks';
export * from './provider';
export * from './types';
+export * from './utils';
diff --git a/src/shared/utils/index.ts b/src/shared/utils/index.ts
index d2cfe48f..5be19105 100644
--- a/src/shared/utils/index.ts
+++ b/src/shared/utils/index.ts
@@ -1 +1,2 @@
export { handleCallbackError } from './handle-callback-error';
+export * from './phone-number';
diff --git a/src/shared/utils/phone-number/formatPhoneNumber.ts b/src/shared/utils/phone-number/formatPhoneNumber.ts
new file mode 100644
index 00000000..33aba0c5
--- /dev/null
+++ b/src/shared/utils/phone-number/formatPhoneNumber.ts
@@ -0,0 +1,9 @@
+export const formatPhoneNumber = (phone: string): string => {
+ const match = phone.match(/(\d{3})(\d{4})(\d{4})/);
+ return match ? `${match[1]}-${match[2]}-${match[3]}` : phone;
+};
+
+export const parsePhoneNumber = (phone: string): string => {
+ const match = phone.match(/(\d{3})-(\d{4})-(\d{4})/);
+ return match ? `${match[1]}${match[2]}${match[3]}` : phone;
+};
diff --git a/src/shared/utils/phone-number/index.ts b/src/shared/utils/phone-number/index.ts
new file mode 100644
index 00000000..48b86920
--- /dev/null
+++ b/src/shared/utils/phone-number/index.ts
@@ -0,0 +1 @@
+export { formatPhoneNumber, parsePhoneNumber } from './formatPhoneNumber';