diff --git a/src/pages/assets/guard-main/list.svg b/src/pages/assets/guard-main/list.svg deleted file mode 100644 index 516d8b09..00000000 --- a/src/pages/assets/guard-main/list.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/pages/guard/guard-main/GuardMainPage.tsx b/src/pages/guard/guard-main/GuardMainPage.tsx index 75e9e242..a6296987 100644 --- a/src/pages/guard/guard-main/GuardMainPage.tsx +++ b/src/pages/guard/guard-main/GuardMainPage.tsx @@ -3,6 +3,7 @@ import { useState } from 'react'; import { GuideLineList } from './components/guideline-list'; import { Header } from './components/header/Header'; import { HelloCallApply } from './components/hello-call-apply'; +import { Box, Text } from '@chakra-ui/react'; import styled from '@emotion/styled'; export const GuardMainPage = () => { @@ -14,6 +15,25 @@ export const GuardMainPage = () => { currentSenior={currentSenior} setCurrentSenior={setCurrentSenior} /> + + + 시니어가 사용할 서비스 번호 + + + 010-4163-8098 + + @@ -27,3 +47,18 @@ const GuardMainPageLayout = styled.div` width: 100%; padding: 0 2rem; `; + +const CallbackNumber = styled.div` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 100%; + border-radius: 20px; + max-width: 338px; + padding: 0.5rem; + background-color: var(--color-primary); + color: white; + font-weight: bold; + margin-top: 1rem; +`; diff --git a/src/pages/guard/guard-main/components/header/Header.tsx b/src/pages/guard/guard-main/components/header/Header.tsx index 9ebbd697..641beeb9 100644 --- a/src/pages/guard/guard-main/components/header/Header.tsx +++ b/src/pages/guard/guard-main/components/header/Header.tsx @@ -2,7 +2,6 @@ import { ChangeEvent, Dispatch, SetStateAction } from 'react'; import { Link } from 'react-router-dom'; import { RouterPath } from '@/app/routes'; -import IconList from '@/pages/assets/guard-main/list.svg'; import IconUser from '@/pages/assets/shared/user.svg'; import { HEADER_HEIGHT, useAllSeniorInfo } from '@/shared'; import { Flex, Image, Select } from '@chakra-ui/react'; @@ -22,7 +21,6 @@ export const Header = ({ currentSenior, setCurrentSenior }: HeaderProps) => { return ( - icon-list setAccountNumber(e.target.value)} - placeholder='계좌번호 입력' - size='sm' + fontSize='16px' + fontWeight='bold' width='60%' + h='1.5rem' bg='var(--color-white)' /> ) : ( @@ -77,61 +88,105 @@ const AccountInfoBox = () => { )} - + 은행 이름 - {isEditingAccount ? ( + {isEditingAccount || isRegistering ? ( setBankName(e.target.value)} - placeholder='해당 은행 기입' - size='sm' + fontSize='16px' + fontWeight='bold' width='40%' + h='1.5rem' bg='var(--color-white)' /> ) : ( - + {sinittoBankInfo?.bankName} )} - + 계좌 인증 여부 - + {sinittoBankInfo?.accountNumber ? '인증 완료' : '인증 미완료'} {sinittoBankInfo?.accountNumber === null ? ( - - 계좌번호 등록하기 - + isRegistering ? ( + + + + + ) : ( + setIsRegistering(true)} + > + 계좌번호 등록하기 + + ) ) : isEditingAccount ? ( ) : ( diff --git a/src/pages/sinitto/mypage/components/profile-box/SinittoProfileBox.tsx b/src/pages/sinitto/mypage/components/profile-box/SinittoProfileBox.tsx index ea83363c..b9ad5afb 100644 --- a/src/pages/sinitto/mypage/components/profile-box/SinittoProfileBox.tsx +++ b/src/pages/sinitto/mypage/components/profile-box/SinittoProfileBox.tsx @@ -1,8 +1,8 @@ import { useEffect, useState } from 'react'; import { useModifySinittoInformation } from '@/pages'; -import { Logout, useSinittoInfo } from '@/shared'; -import { Box, Text, Button, Input } from '@chakra-ui/react'; +import { formatPhoneNumber, Logout, useSinittoInfo } from '@/shared'; +import { Box, Text, Button, Input, Flex } from '@chakra-ui/react'; import styled from '@emotion/styled'; type Props = { @@ -40,18 +40,20 @@ const SinittoProfileBox = ({ isEditing, setIsEditing }: Props) => { return ( + + + {seniorInfo?.name} 님 환영합니다. + + + - - {seniorInfo?.name} 님 환영합니다. - - - - { {isEditing ? ( setName(e.target.value)} - placeholder='이름 입력' - size='sm' - width='40%' + width='5rem' + height='100%' bg='var(--color-white)' /> ) : ( - + {seniorInfo?.name} )} - + { {isEditing ? ( setPhoneNumber(e.target.value)} - placeholder='전화번호 입력' - size='sm' - width='60%' + width='9rem' + height='100%' bg='var(--color-white)' /> ) : ( - - {seniorInfo?.phoneNumber} + + {formatPhoneNumber(String(seniorInfo?.phoneNumber))} )} - + {isEditing ? ( <> ) : null} @@ -135,7 +148,7 @@ export default SinittoProfileBox; const SinittoProfileBoxLayout = styled(Box)` display: flex; flex-direction: column; - background-color: #f2f2f2; + background-color: var(--color-white-gray); width: 100%; max-width: 338px; height: auto; diff --git a/src/shared/api/hooks/useWithdrawal.ts b/src/shared/api/hooks/useWithdrawal.ts new file mode 100644 index 00000000..f51c1d00 --- /dev/null +++ b/src/shared/api/hooks/useWithdrawal.ts @@ -0,0 +1,20 @@ +import { useNavigate } from 'react-router-dom'; + +import { RouterPath } from '@/app/routes'; +import { userWithdrawal } from '@/shared'; +import { authStorage } from '@/shared/utils'; +import { useMutation } from '@tanstack/react-query'; + +export const useWithdrawal = () => { + const navigate = useNavigate(); + + return useMutation({ + mutationFn: userWithdrawal, + onSuccess: () => { + authStorage.accessToken.set(undefined); + authStorage.refreshToken.set(undefined); + alert('회원 탈퇴되었습니다.'); + navigate(RouterPath.ROOT); + }, + }); +}; diff --git a/src/shared/api/index.ts b/src/shared/api/index.ts index 075b7a60..3f878374 100644 --- a/src/shared/api/index.ts +++ b/src/shared/api/index.ts @@ -1,5 +1,6 @@ export { getCallback } from './get-call-back.api'; export { userLogout } from './logout.api'; +export { userWithdrawal } from './withdrawal.api'; export * from './instance'; export * from './hooks'; export * from './point'; diff --git a/src/shared/api/logout.api.ts b/src/shared/api/logout.api.ts index 51cb9c53..ea2a35f8 100644 --- a/src/shared/api/logout.api.ts +++ b/src/shared/api/logout.api.ts @@ -1,8 +1,8 @@ import { fetchInstance } from '@/shared/api/instance'; -const getLogoutPath = '/api/members/logout'; +const LOGOUT_PATH = '/api/members/logout'; export const userLogout = async () => { - const response = await fetchInstance.delete(getLogoutPath); + const response = await fetchInstance.delete(LOGOUT_PATH); return response.data; }; diff --git a/src/shared/api/withdrawal.api.ts b/src/shared/api/withdrawal.api.ts new file mode 100644 index 00000000..c2cff648 --- /dev/null +++ b/src/shared/api/withdrawal.api.ts @@ -0,0 +1,8 @@ +import { fetchInstance } from '@/shared/api/instance'; + +const WITHDRAWAL_PATH = 'api/members/withdrawal'; + +export const userWithdrawal = async () => { + const response = await fetchInstance.delete(WITHDRAWAL_PATH); + return response.data; +}; diff --git a/src/shared/components/features/mypage/index.ts b/src/shared/components/features/mypage/index.ts index bcb65af8..5c50ddaf 100644 --- a/src/shared/components/features/mypage/index.ts +++ b/src/shared/components/features/mypage/index.ts @@ -1,3 +1,4 @@ export * from './point-box'; export * from './point-log-box'; export * from './logout-button'; +export * from './withdrawal-button'; diff --git a/src/shared/components/features/mypage/point-box/PointBox.tsx b/src/shared/components/features/mypage/point-box/PointBox.tsx index 2ea4b1ab..7c9e667e 100644 --- a/src/shared/components/features/mypage/point-box/PointBox.tsx +++ b/src/shared/components/features/mypage/point-box/PointBox.tsx @@ -8,8 +8,12 @@ import { import { Box, Spinner, Button, Input } from '@chakra-ui/react'; import styled from '@emotion/styled'; -const PointBox = () => { - const { data: pointData, isLoading, refetch } = useGetPointInfo(); +type Props = { + isSinitto: boolean; +}; + +const PointBox = ({ isSinitto }: Props) => { + const { data: pointData, isLoading } = useGetPointInfo(); const chargePointMutation = useChargePoint(); const withdrawPointMutation = useWithdrawPoint(); const [actionType, setActionType] = useState(''); @@ -26,11 +30,13 @@ const PointBox = () => { const handleWithdrawButtonClick = () => { const parsedAmount = Number(amount); - if (parsedAmount > 0) { + if (parsedAmount > 0 && parsedAmount <= Number(pointData?.price)) { withdrawPointMutation.mutate(parsedAmount); setAmount(''); setActionType(''); - refetch(); + } else { + alert('보유 포인트보다 더 많은 금액을 출금할 수 없습니다.'); + setAmount(''); } }; @@ -72,6 +78,8 @@ const PointBox = () => { m={1} w='100%' h='40px' + bg='var(--color-white)' + fontSize='16px' placeholder={ actionType === 'charge' ? '충전할 포인트' : '출금할 포인트' } @@ -85,37 +93,60 @@ const PointBox = () => { w='100px' h='40px' fontSize='16px' + bg='var(--color-primary)' + color='var(--color-white)' + fontWeight='bold' + mr={2} onClick={ actionType === 'charge' ? handleChargeButtonClick : handleWithdrawButtonClick } - colorScheme='teal' > - {actionType === 'charge' ? '충전' : '출금'} + {actionType === 'charge' ? '충전 신청' : '출금 신청'} ) : ( - - setActionType('charge')}> - 충전하기 - - setActionType('withdraw')}> - 출금하기 - - + <> + + {isSinitto ? null : '보낼 계좌 : 3333-17-1913-736'} + + + {isSinitto ? ( + setActionType('withdraw')}> + 출금하기 + + ) : ( + setActionType('charge')}> + 충전하기 + + )} + + )} ); @@ -131,8 +162,7 @@ const PointBoxLayout = styled(Box)` flex-direction: column; justify-content: center; align-items: center; - background-color: #f6e4e4; - border: 1px solid #f6e4e4; + background-color: var(--color-secondary); border-radius: 10px; margin-top: 0.5rem; `; @@ -141,26 +171,23 @@ const ButtonContainer = styled(Box)` display: flex; flex-direction: row; align-items: center; - justify-content: space-around; + justify-content: center; width: 100%; max-width: 338px; - height: 30%; - max-height: 40px; + max-height: 70px; margin-bottom: 10px; `; -const ButtonBox = styled(Box)` +const ActingButton = styled.button` display: flex; justify-content: center; align-items: center; - width: 100%; - max-width: 145px; - height: 100%; - max-height: 30px; + width: 90%; + height: 30px; font-size: 16px; font-weight: 600; - background-color: #fff; - border: 1px solid #fff; + background-color: var(--color-white); + border: 1px solid var(--color-white); border-radius: 5px; cursor: pointer; `; 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 50a0da96..e135fe2a 100644 --- a/src/shared/components/features/mypage/point-log-box/PointLogBox.tsx +++ b/src/shared/components/features/mypage/point-log-box/PointLogBox.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useState, useCallback } from 'react'; import PointLogImg from '../../../../assets/point-log-icon.png'; import { getPointStatusLabel, useGetPointLogs } from '@/shared/hooks'; @@ -8,9 +8,17 @@ import styled from '@emotion/styled'; const PointLogBox = () => { const [currentPage, setCurrentPage] = useState(0); const pageSize = 5; - const { data, isLoading } = useGetPointLogs(currentPage, pageSize); + const { data, isLoading, refetch } = useGetPointLogs(currentPage, pageSize); const totalPages = data?.totalPages || 1; + const handlePageChange = useCallback( + (page: number) => { + setCurrentPage(page); + refetch(); + }, + [refetch] + ); + if (isLoading) { return ( @@ -35,15 +43,15 @@ const PointLogBox = () => { /> - + {new Date(item.postTime).toLocaleDateString()} - + {getPointStatusLabel(item.status)} - {item.content} + {item.content} { setCurrentPage((prev) => Math.max(prev - 1, 0))} + onClick={() => handlePageChange(Math.max(currentPage - 1, 0))} disabled={currentPage === 0} > 이전 @@ -81,7 +89,7 @@ const PointLogBox = () => { 페이지 {currentPage + 1} / {data?.totalPages ? data.totalPages : 1} setCurrentPage((prev) => prev + 1)} + onClick={() => handlePageChange(currentPage + 1)} disabled={currentPage >= totalPages - 1} > 다음 @@ -92,7 +100,6 @@ const PointLogBox = () => { }; export default PointLogBox; - const UseDetailBoxLayout = styled(Box)` display: flex; flex-direction: column; @@ -170,6 +177,14 @@ const PaginationButton = styled.button` `; const DetailText = styled(Box)` + width: 45%; + display: flex; + align-items: center; + font-size: 16px; + font-weight: 600; +`; + +const ContentText = styled(Box)` width: 100%; display: flex; align-items: center; diff --git a/src/shared/components/features/mypage/withdrawal-button/Withdrawal.tsx b/src/shared/components/features/mypage/withdrawal-button/Withdrawal.tsx new file mode 100644 index 00000000..f9b524bb --- /dev/null +++ b/src/shared/components/features/mypage/withdrawal-button/Withdrawal.tsx @@ -0,0 +1,31 @@ +import { useWithdrawal } from '@/shared/api/hooks/useWithdrawal'; +import styled from '@emotion/styled'; + +const Withdrawal = () => { + const { mutate: withdrawal } = useWithdrawal(); + + const Dowithdrawal = () => { + const isConfirmed = window.confirm('정말 회원 탈퇴하시겠습니까?'); + if (isConfirmed) { + withdrawal(); + } + }; + + return ( + 회원 탈퇴하기 + ); +}; + +export default Withdrawal; + +const WithdrawalButton = styled.button` + cursor: pointer; + width: 100%; + max-width: 338px; + color: white; + font-size: 18px; + font-weight: bold; + height: 40px; + background-color: #ff4d68; + border-radius: 10px; +`; diff --git a/src/shared/components/features/mypage/withdrawal-button/index.ts b/src/shared/components/features/mypage/withdrawal-button/index.ts new file mode 100644 index 00000000..408c2579 --- /dev/null +++ b/src/shared/components/features/mypage/withdrawal-button/index.ts @@ -0,0 +1 @@ +export { default as Withdrawal } from './Withdrawal'; diff --git a/src/shared/hooks/point/useChargePoint.ts b/src/shared/hooks/point/useChargePoint.ts index 69c1b93a..a99198a5 100644 --- a/src/shared/hooks/point/useChargePoint.ts +++ b/src/shared/hooks/point/useChargePoint.ts @@ -1,4 +1,9 @@ -import { chargePoint, ChargePointResponse } from '@/shared/api/point/point.api'; +import { queryClient } from '@/shared/api'; +import { + chargePoint, + ChargePointResponse, + getPointInfoQueryKey, +} from '@/shared/api/point/point.api'; import { useMutation, UseMutationResult } from '@tanstack/react-query'; // 포인트 충전 @@ -11,6 +16,10 @@ export const useChargePoint = (): UseMutationResult< mutationFn: (price) => chargePoint(price), onSuccess: () => { alert('포인트 충전 요청 완료했습니다.'); + queryClient.invalidateQueries({ queryKey: getPointInfoQueryKey }); + queryClient.invalidateQueries({ + queryKey: ['pointLogs'], + }); }, onError: (error: Error) => { console.error(error); diff --git a/src/shared/hooks/point/useWithdrawPoint.ts b/src/shared/hooks/point/useWithdrawPoint.ts index 8f2ab548..e5604abe 100644 --- a/src/shared/hooks/point/useWithdrawPoint.ts +++ b/src/shared/hooks/point/useWithdrawPoint.ts @@ -1,4 +1,6 @@ +import { queryClient } from '@/shared/api'; import { withdrawPoint } from '@/shared/api/point'; +import { getPointInfoQueryKey } from '@/shared/api/point/point.api'; import { useMutation, UseMutationResult } from '@tanstack/react-query'; // 포인트 출금 @@ -11,6 +13,10 @@ export const useWithdrawPoint = (): UseMutationResult< mutationFn: (price) => withdrawPoint(price), onSuccess: (price: number) => { alert(`${price} 포인트 출금 신청 완료되었습니다.`); + queryClient.invalidateQueries({ queryKey: getPointInfoQueryKey }); + queryClient.invalidateQueries({ + queryKey: ['pointLogs'], + }); }, onError: (error: Error) => { console.error(error);