diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 9bd4613d..91a6b2ef 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -2,7 +2,7 @@ name: S3 deploy
on:
push:
- branches: ['Master']
+ branches: ['Weekly']
env:
AWS_REGION: ap-northeast-2
S3_BUCKET_NAME: sinitto
diff --git a/src/app/routes/index.tsx b/src/app/routes/index.tsx
index a68c45f6..a0c3e00e 100644
--- a/src/app/routes/index.tsx
+++ b/src/app/routes/index.tsx
@@ -1,8 +1,11 @@
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import { RouterPath } from './path';
-import MainPage from '@/pages/common/main';
-import RegisterPage from '@/pages/common/register';
+import MainPage from '@/pages/common/main/MainPage';
+import { RedirectPage } from '@/pages/common/redirect';
+import RegisterPage from '@/pages/common/register/RegisterPage';
+import GuideLinePage from '@/pages/guard/guide-line';
+import GuardMyPage from '@/pages/guard/mypage';
import SeniorRegisterPage from '@/pages/guard/register';
import SinittoReviewPage from '@/pages/guard/review';
import ServiceHistoryPage from '@/pages/guard/service-history';
@@ -12,7 +15,8 @@ import SinittoGuideLinePage from '@/pages/sinitto/guide-line';
import HelloCallListPage from '@/pages/sinitto/hello-call/hello-call-list';
import HelloCallReportPage from '@/pages/sinitto/hello-call/hello-call-report';
import HelloCallServicePage from '@/pages/sinitto/hello-call/hello-call-service';
-import MyPage from '@/pages/sinitto/mypage';
+import SinittoMypage from '@/pages/sinitto/mypage';
+import { Layout } from '@/shared/components';
const router = createBrowserRouter([
{
@@ -20,64 +24,52 @@ const router = createBrowserRouter([
element: ,
},
{
- path: RouterPath.REGISTER,
- element: ,
- },
- {
- path: RouterPath.MYPAGE,
- element: ,
- },
- {
- path: RouterPath.SERVICE_HISTORY,
- element: ,
- },
- {
- path: RouterPath.HELLO_CALL,
- children: [
- {
- index: true,
- element: ,
- },
- {
- path: RouterPath.HELLO_CALL_SERVICE,
- element: ,
- },
- {
- path: RouterPath.HELLO_CALL_REPORT,
- element: ,
- },
- ],
- },
- {
- path: RouterPath.SENIOR_REGISTER,
- element: ,
- },
- {
- path: RouterPath.CALL_BACK_LIST,
+ path: RouterPath.ROOT,
+ element: ,
children: [
+ { path: RouterPath.SIGNUP, element: },
+ { path: RouterPath.REDIRECT, element: },
+ { path: RouterPath.SINITTO_MYPAGE, element: },
+ { path: RouterPath.GUARD_MYPAGE, element: },
+ { path: RouterPath.GUARD_GUIDELINE, element: },
+ { path: RouterPath.SERVICE_HISTORY, element: },
{
- index: true,
- element: ,
- },
- {
- path: RouterPath.CALL_BACK_DETAIL,
+ path: RouterPath.HELLO_CALL,
children: [
+ { index: true, element: },
{
- index: true,
- element: ,
+ path: RouterPath.HELLO_CALL_SERVICE,
+ element: ,
},
{
- path: RouterPath.CALL_BACK_GUID_LINE,
- element: ,
+ path: RouterPath.HELLO_CALL_REPORT,
+ element: ,
},
],
},
+ { path: RouterPath.SENIOR_REGISTER, element: },
+ {
+ path: RouterPath.CALL_BACK_LIST,
+ children: [
+ { index: true, element: },
+ {
+ path: RouterPath.CALL_BACK_DETAIL,
+ children: [
+ { index: true, element: },
+ {
+ path: RouterPath.CALL_BACK_GUID_LINE,
+ element: ,
+ },
+ ],
+ },
+ ],
+ },
+ {
+ path: RouterPath.SINITTO_REVIEW,
+ element: ,
+ },
],
},
- {
- path: RouterPath.SINITTO_REVIEW,
- element: ,
- },
]);
export const Routes = () => {
diff --git a/src/app/routes/path.ts b/src/app/routes/path.ts
index 741f6f7e..0296f392 100644
--- a/src/app/routes/path.ts
+++ b/src/app/routes/path.ts
@@ -1,8 +1,12 @@
export const RouterPath = {
ROOT: '/',
LOGIN: '/login',
+ SIGNUP: '/signup',
REGISTER: '/register',
- MYPAGE: `/mypage`,
+ REDIRECT: '/redirection',
+ GUARD_MYPAGE: `/guard/mypage`,
+ GUARD_GUIDELINE: `/guard/guideline`,
+ SINITTO_MYPAGE: `/sinitto/mypage`,
SERVICE_HISTORY: `/service-history`,
HELLO_CALL_SERVICE: 'service',
HELLO_CALL_REPORT: 'report',
diff --git a/src/pages/common/main/index.tsx b/src/pages/common/main/MainPage.tsx
similarity index 100%
rename from src/pages/common/main/index.tsx
rename to src/pages/common/main/MainPage.tsx
diff --git a/src/pages/common/main/components/login-button/index.tsx b/src/pages/common/main/components/login-button/index.tsx
index dbb3aa94..9f63c3dd 100644
--- a/src/pages/common/main/components/login-button/index.tsx
+++ b/src/pages/common/main/components/login-button/index.tsx
@@ -1,13 +1,18 @@
+import { Link } from 'react-router-dom';
+
import Logo from '../../assets/kakao.svg';
+import { KAKAO_AUTH_URL } from '@/shared/constants';
import { Image, Text } from '@chakra-ui/react';
import styled from '@emotion/styled';
const LoginButton = () => {
return (
-
-
- 카카오톡 로그인
-
+
+
+
+ 카카오톡 로그인
+
+
);
};
diff --git a/src/pages/common/redirect/RedirectPage.tsx b/src/pages/common/redirect/RedirectPage.tsx
new file mode 100644
index 00000000..d793cd3d
--- /dev/null
+++ b/src/pages/common/redirect/RedirectPage.tsx
@@ -0,0 +1,16 @@
+import { useLocation } from 'react-router-dom';
+
+import { RedirectSection } from './components';
+
+const RedirectPage = () => {
+ const location = useLocation();
+
+ const code = new URLSearchParams(location.search).get('code');
+ if (!code) {
+ return
로그인을 다시 진행해주세요.
;
+ }
+
+ return ;
+};
+
+export default RedirectPage;
diff --git a/src/pages/common/redirect/components/index.ts b/src/pages/common/redirect/components/index.ts
new file mode 100644
index 00000000..c0b93c2e
--- /dev/null
+++ b/src/pages/common/redirect/components/index.ts
@@ -0,0 +1 @@
+export * from './redirect-section';
diff --git a/src/pages/common/redirect/components/redirect-section/RedirectSection.tsx b/src/pages/common/redirect/components/redirect-section/RedirectSection.tsx
new file mode 100644
index 00000000..c89a40db
--- /dev/null
+++ b/src/pages/common/redirect/components/redirect-section/RedirectSection.tsx
@@ -0,0 +1,41 @@
+import { useEffect } from 'react';
+import { useNavigate } from 'react-router-dom';
+
+import { useGetKakaoCallback } from '../../store/hooks';
+import { Flex, Spinner, Text } from '@chakra-ui/react';
+
+type Props = {
+ code: string;
+};
+
+const RedirectSection = ({ code }: Props) => {
+ const navigate = useNavigate();
+
+ const { data } = useGetKakaoCallback(code);
+
+ useEffect(() => {
+ if (data) {
+ const accessToken = data.accessToken;
+ const refreshToken = data.refreshToken;
+ localStorage.setItem('accessToken', accessToken);
+ localStorage.setItem('refreshToken', refreshToken);
+
+ navigate('/');
+ }
+ }, [data, navigate]);
+
+ return (
+
+
+ 로그인 진행중!
+
+ );
+};
+
+export default RedirectSection;
diff --git a/src/pages/common/redirect/components/redirect-section/index.ts b/src/pages/common/redirect/components/redirect-section/index.ts
new file mode 100644
index 00000000..b071f5e9
--- /dev/null
+++ b/src/pages/common/redirect/components/redirect-section/index.ts
@@ -0,0 +1 @@
+export { default as RedirectSection } from './RedirectSection';
diff --git a/src/pages/common/redirect/index.ts b/src/pages/common/redirect/index.ts
new file mode 100644
index 00000000..a785eba6
--- /dev/null
+++ b/src/pages/common/redirect/index.ts
@@ -0,0 +1 @@
+export { default as RedirectPage } from './RedirectPage';
diff --git a/src/pages/common/redirect/store/api/index.ts b/src/pages/common/redirect/store/api/index.ts
new file mode 100644
index 00000000..9a36a5d3
--- /dev/null
+++ b/src/pages/common/redirect/store/api/index.ts
@@ -0,0 +1 @@
+export { getKakaoCallback } from './kakao-callback.api';
diff --git a/src/pages/common/redirect/store/api/kakao-callback.api.ts b/src/pages/common/redirect/store/api/kakao-callback.api.ts
new file mode 100644
index 00000000..2863822e
--- /dev/null
+++ b/src/pages/common/redirect/store/api/kakao-callback.api.ts
@@ -0,0 +1,26 @@
+import { fetchInstance } from '@/shared/api/instance';
+
+export type KakaoCallbackResponse = {
+ accessToken: string;
+ refreshToken: string;
+ redirectUrl: string;
+ email: string;
+ isSinitto: boolean;
+ isMember: boolean;
+};
+
+const getKakaoCallbackPath = () => '/api/auth/oauth/kakao/callback';
+
+export const KakaoCallbackQueryKey = [getKakaoCallbackPath()];
+
+export const getKakaoCallback = async (
+ code: string
+): Promise => {
+ const response = await fetchInstance.get(getKakaoCallbackPath(), {
+ params: {
+ code,
+ },
+ });
+ console.log(response.data);
+ return response.data;
+};
diff --git a/src/pages/common/redirect/store/hooks/index.ts b/src/pages/common/redirect/store/hooks/index.ts
new file mode 100644
index 00000000..63f73f69
--- /dev/null
+++ b/src/pages/common/redirect/store/hooks/index.ts
@@ -0,0 +1 @@
+export { useGetKakaoCallback } from './useGetKakaoCallback';
diff --git a/src/pages/common/redirect/store/hooks/useGetKakaoCallback.ts b/src/pages/common/redirect/store/hooks/useGetKakaoCallback.ts
new file mode 100644
index 00000000..e6bcae58
--- /dev/null
+++ b/src/pages/common/redirect/store/hooks/useGetKakaoCallback.ts
@@ -0,0 +1,13 @@
+import {
+ getKakaoCallback,
+ KakaoCallbackQueryKey,
+ KakaoCallbackResponse,
+} from '../api/kakao-callback.api';
+import { useQuery } from '@tanstack/react-query';
+
+export const useGetKakaoCallback = (code: string) => {
+ return useQuery({
+ queryKey: [KakaoCallbackQueryKey, code],
+ queryFn: () => getKakaoCallback(code),
+ });
+};
diff --git a/src/pages/common/register/index.tsx b/src/pages/common/register/RegisterPage.tsx
similarity index 65%
rename from src/pages/common/register/index.tsx
rename to src/pages/common/register/RegisterPage.tsx
index 9677a74c..0451a505 100644
--- a/src/pages/common/register/index.tsx
+++ b/src/pages/common/register/RegisterPage.tsx
@@ -1,11 +1,10 @@
import { useState } from 'react';
import { useForm } from 'react-hook-form';
-import { RegisterFields } from './components/register-fields';
-import { RegisterType } from './components/register-type';
-import { Tos } from './components/tos';
+import useRegister from './api/hooks/useRegister';
+import { RegisterFields, RegisterType, Tos } from './components';
import { FormValues } from './types';
-import { BasicButton } from '@/shared/components/common/button';
+import { BasicButton } from '@/shared/components';
import { Divider } from '@chakra-ui/react';
import styled from '@emotion/styled';
@@ -17,13 +16,26 @@ const RegisterPage = () => {
formState: { errors },
} = useForm();
+ // 회원가입 처리
+ const mutation = useRegister();
+
const handleUserType = (id: string) => {
setUserType(id);
};
const onSubmit = (data: FormValues) => {
- // 회원가입 api
- console.log(userType, data);
+ // request 에 맞게 데이터 병합
+ const isSinitto = userType === 'sinitto';
+
+ const requestData = {
+ name: data.name,
+ phoneNumber: data.phoneNumber,
+ email: 'test1@example.com', // 임시 (카카오 로그인 후 넘겨받기)
+ isSinitto,
+ };
+ console.log(requestData);
+ // 회원가입 API 호출
+ mutation.mutate(requestData);
};
return (
diff --git a/src/pages/common/register/api/hooks/index.ts b/src/pages/common/register/api/hooks/index.ts
new file mode 100644
index 00000000..49ce6497
--- /dev/null
+++ b/src/pages/common/register/api/hooks/index.ts
@@ -0,0 +1 @@
+export { default as useRegister } from './useRegister';
diff --git a/src/pages/common/register/api/hooks/useRegister.ts b/src/pages/common/register/api/hooks/useRegister.ts
new file mode 100644
index 00000000..f5e201e8
--- /dev/null
+++ b/src/pages/common/register/api/hooks/useRegister.ts
@@ -0,0 +1,47 @@
+import { useNavigate } from 'react-router-dom';
+
+import { AxiosError } from 'axios';
+
+import { RouterPath } from '@/app/routes/path';
+import {
+ SignupApiResponse,
+ registerUser,
+} from '@/shared/api/auth/user-register';
+import { authLocalStorage } from '@/shared/utils/storage';
+import { useMutation } from '@tanstack/react-query';
+
+const useRegister = () => {
+ const navigate = useNavigate();
+
+ const handleSuccess = (data: SignupApiResponse) => {
+ if ('status' in data && data.status === 207) {
+ alert(data.detail);
+ } else {
+ console.log(data);
+ if ('accessToken' in data) {
+ authLocalStorage.set(data.accessToken);
+ authLocalStorage.set(data.refreshToken);
+ alert('회원가입이 완료되었습니다.');
+ navigate(data.isSinitto === 'true' ? RouterPath.ROOT : RouterPath.ROOT);
+ }
+ }
+ };
+
+ const handleError = (error: AxiosError) => {
+ if (error.response && error.response.data) {
+ alert('회원가입 중 오류가 발생했습니다.');
+ } else {
+ alert('회원가입 중 네트워크 오류가 발생했습니다.');
+ }
+ };
+
+ const mutation = useMutation({
+ mutationFn: registerUser,
+ onSuccess: handleSuccess,
+ onError: handleError,
+ });
+
+ return mutation;
+};
+
+export default useRegister;
diff --git a/src/pages/common/register/api/index.ts b/src/pages/common/register/api/index.ts
new file mode 100644
index 00000000..4cc90d02
--- /dev/null
+++ b/src/pages/common/register/api/index.ts
@@ -0,0 +1 @@
+export * from './hooks';
diff --git a/src/pages/common/register/components/index.ts b/src/pages/common/register/components/index.ts
new file mode 100644
index 00000000..4bd07f13
--- /dev/null
+++ b/src/pages/common/register/components/index.ts
@@ -0,0 +1,6 @@
+export * from './register-fields';
+export * from './register-fields/form-fields';
+export * from './register-type';
+export * from './register-type/type-button';
+export * from './tos';
+export * from './tos/content';
diff --git a/src/pages/common/register/components/register-fields/index.tsx b/src/pages/common/register/components/register-fields/RegisterFields.tsx
similarity index 95%
rename from src/pages/common/register/components/register-fields/index.tsx
rename to src/pages/common/register/components/register-fields/RegisterFields.tsx
index cf948735..56a27be9 100644
--- a/src/pages/common/register/components/register-fields/index.tsx
+++ b/src/pages/common/register/components/register-fields/RegisterFields.tsx
@@ -1,7 +1,7 @@
import { FieldErrors, UseFormRegister } from 'react-hook-form';
import type { FormValues } from '../../types';
-import { FormField } from './form-fileds';
+import { FormField } from './form-fields';
import styled from '@emotion/styled';
type Props = {
diff --git a/src/pages/common/register/components/register-fields/form-fileds/index.tsx b/src/pages/common/register/components/register-fields/form-fields/FormField.tsx
similarity index 100%
rename from src/pages/common/register/components/register-fields/form-fileds/index.tsx
rename to src/pages/common/register/components/register-fields/form-fields/FormField.tsx
diff --git a/src/pages/common/register/components/register-fields/form-fields/index.ts b/src/pages/common/register/components/register-fields/form-fields/index.ts
new file mode 100644
index 00000000..0e97de67
--- /dev/null
+++ b/src/pages/common/register/components/register-fields/form-fields/index.ts
@@ -0,0 +1 @@
+export { FormField } from './FormField';
diff --git a/src/pages/common/register/components/register-fields/index.ts b/src/pages/common/register/components/register-fields/index.ts
new file mode 100644
index 00000000..bd4ac734
--- /dev/null
+++ b/src/pages/common/register/components/register-fields/index.ts
@@ -0,0 +1 @@
+export { RegisterFields } from './RegisterFields';
diff --git a/src/pages/common/register/components/register-type/index.tsx b/src/pages/common/register/components/register-type/RegisterType.tsx
similarity index 95%
rename from src/pages/common/register/components/register-type/index.tsx
rename to src/pages/common/register/components/register-type/RegisterType.tsx
index ece96f2c..f99d770d 100644
--- a/src/pages/common/register/components/register-type/index.tsx
+++ b/src/pages/common/register/components/register-type/RegisterType.tsx
@@ -1,4 +1,4 @@
-import { TypeButton } from './type-button.tsx';
+import { TypeButton } from './type-button';
import styled from '@emotion/styled';
type Props = {
diff --git a/src/pages/common/register/components/register-type/index.ts b/src/pages/common/register/components/register-type/index.ts
new file mode 100644
index 00000000..7894d59a
--- /dev/null
+++ b/src/pages/common/register/components/register-type/index.ts
@@ -0,0 +1 @@
+export { RegisterType } from './RegisterType';
diff --git a/src/pages/common/register/components/register-type/type-button.tsx/index.tsx b/src/pages/common/register/components/register-type/type-button/TypeButton.tsx
similarity index 100%
rename from src/pages/common/register/components/register-type/type-button.tsx/index.tsx
rename to src/pages/common/register/components/register-type/type-button/TypeButton.tsx
diff --git a/src/pages/common/register/components/register-type/type-button/index.ts b/src/pages/common/register/components/register-type/type-button/index.ts
new file mode 100644
index 00000000..8436efb3
--- /dev/null
+++ b/src/pages/common/register/components/register-type/type-button/index.ts
@@ -0,0 +1 @@
+export { TypeButton } from './TypeButton';
diff --git a/src/pages/common/register/components/tos/index.tsx b/src/pages/common/register/components/tos/Tos.tsx
similarity index 100%
rename from src/pages/common/register/components/tos/index.tsx
rename to src/pages/common/register/components/tos/Tos.tsx
diff --git a/src/pages/common/register/components/tos/content/index.tsx b/src/pages/common/register/components/tos/content/TosContent.tsx
similarity index 100%
rename from src/pages/common/register/components/tos/content/index.tsx
rename to src/pages/common/register/components/tos/content/TosContent.tsx
diff --git a/src/pages/common/register/components/tos/content/index.ts b/src/pages/common/register/components/tos/content/index.ts
new file mode 100644
index 00000000..3915821b
--- /dev/null
+++ b/src/pages/common/register/components/tos/content/index.ts
@@ -0,0 +1 @@
+export { TosContent } from './TosContent';
diff --git a/src/pages/common/register/components/tos/index.ts b/src/pages/common/register/components/tos/index.ts
new file mode 100644
index 00000000..132d4984
--- /dev/null
+++ b/src/pages/common/register/components/tos/index.ts
@@ -0,0 +1 @@
+export { Tos } from './Tos';
diff --git a/src/pages/guard/guide-line/.gitkeep b/src/pages/guard/guide-line/.gitkeep
deleted file mode 100644
index e69de29b..00000000
diff --git a/src/pages/guard/guide-line/components/guide-info-box/index.tsx b/src/pages/guard/guide-line/components/guide-info-box/index.tsx
new file mode 100644
index 00000000..6a05ae6d
--- /dev/null
+++ b/src/pages/guard/guide-line/components/guide-info-box/index.tsx
@@ -0,0 +1,49 @@
+import { Box, Flex, Text } from '@chakra-ui/react';
+import styled from '@emotion/styled';
+
+type GuidelineType = {
+ title: string;
+ content: string;
+};
+
+const GuideLineInfo = ({ guideline }: { guideline: GuidelineType }) => {
+ return (
+
+
+
+ {guideline.title}
+
+
+ {guideline.content}
+
+
+
+ );
+};
+
+export default GuideLineInfo;
+
+const GuideLineInfoContainer = styled(Flex)`
+ width: 100%;
+ max-width: 330px;
+ min-height: 8rem;
+ background-color: var(--color-white);
+ border: 1px solid var(--color-white);
+ border-radius: 10px;
+ box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
+ margin: 0.5rem 0;
+ padding: 1rem;
+`;
+
+const InfoText = styled(Text)`
+ font-size: 0.8rem;
+ color: var(--color-black);
+`;
+
+const InfoBox = styled(Box)`
+ width: 100%;
+ max-width: 300px;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+`;
diff --git a/src/pages/guard/guide-line/data/index.tsx b/src/pages/guard/guide-line/data/index.tsx
new file mode 100644
index 00000000..01108e2e
--- /dev/null
+++ b/src/pages/guard/guide-line/data/index.tsx
@@ -0,0 +1,39 @@
+const GUIDELINE_DATA = [
+ {
+ id: 1,
+ title: '산격초등학교',
+ content: '산격초등학교에 자주 내리시는 데 집은 어디어디입니다.',
+ },
+ {
+ id: 2,
+ title: '경로당',
+ content:
+ '수지고등학교 회전 교차로 오른쪽 작은 길로 진입하여 우회전 후 마지막에 위치한 단독 건물입니다!',
+ },
+ {
+ id: 3,
+ title: '경로당',
+ content:
+ '수지고등학교 회전 교차로 오른쪽 작은 길로 진입하여 우회전 후 마지막에 위치한 단독 건물입니다!',
+ },
+ {
+ id: 4,
+ title: '경로당',
+ content:
+ '수지고등학교 회전 교차로 오른쪽 작은 길로 진입하여 우회전 후 마지막에 위치한 단독 건물입니다!',
+ },
+ {
+ id: 5,
+ title: '경로당',
+ content:
+ '수지고등학교 회전 교차로 오른쪽 작은 길로 진입하여 우회전 후 마지막에 위치한 단독 건물입니다!',
+ },
+ {
+ id: 6,
+ title: '경로당',
+ content:
+ '수지고등학교 회전 교차로 오른쪽 작은 길로 진입하여 우회전 후 마지막에 위치한 단독 건물입니다!',
+ },
+];
+
+export default GUIDELINE_DATA;
diff --git a/src/pages/guard/guide-line/index.tsx b/src/pages/guard/guide-line/index.tsx
new file mode 100644
index 00000000..8b492c5a
--- /dev/null
+++ b/src/pages/guard/guide-line/index.tsx
@@ -0,0 +1,105 @@
+import GuideLineInfo from './components/guide-info-box';
+import GUIDELINE_DATA from './data';
+import { Box, Flex, Input, Text, Textarea } from '@chakra-ui/react';
+import styled from '@emotion/styled';
+
+const GuideLinePage = () => {
+ const guidelines = GUIDELINE_DATA;
+
+ return (
+
+
+ {guidelines.map((guideline) => (
+
+ ))}
+
+
+
+ 가이드라인 제목
+
+
+
+ 가이드라인 내용
+
+
+ 가이드라인 추가하기
+
+
+ );
+};
+
+export default GuideLinePage;
+
+const Container = styled(Box)`
+ position: relative;
+ height: 100vh;
+`;
+const RegisterBox = styled(Box)`
+ position: absolute;
+ bottom: 0;
+ width: 100%;
+ height: 350px;
+ 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;
+ flex-direction: column;
+ margin: 0.5rem;
+`;
+
+const GuideLineContentInput = styled(Textarea)`
+ background-color: var(--color-white);
+ border: none;
+ font-size: 1rem;
+`;
+
+const InputText = styled(Text)`
+ font-size: 18px;
+ font-weight: bold;
+ margin-bottom: 0.5rem;
+`;
+
+const GuideLineInput = styled(Input)`
+ background-color: var(--color-white);
+ border: none;
+ font-size: 1rem;
+`;
+
+const StyledButton = styled.button`
+ position: absolute;
+ bottom: 1rem;
+ 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);
+ }
+`;
diff --git a/src/pages/guard/guide-line/store/api/view-specific-guideline.api.ts b/src/pages/guard/guide-line/store/api/view-specific-guideline.api.ts
new file mode 100644
index 00000000..11d200e0
--- /dev/null
+++ b/src/pages/guard/guide-line/store/api/view-specific-guideline.api.ts
@@ -0,0 +1,27 @@
+import { fetchInstance } from '@/shared/api/instance';
+
+export type ViewSpecificGuidelineResponse = {
+ title: string;
+ content: string;
+}[];
+
+const getViewSpecificGuidelinePath = (guidelineId: number) =>
+ `/api/guideline/${guidelineId}`;
+
+export const getViewSpecificGuidelineQueryKey = (guidelineId: number) => [
+ getViewSpecificGuidelinePath(guidelineId),
+];
+
+export const getViewSpecificGuideline = async (
+ guidelineId: number
+): Promise => {
+ const response = await fetchInstance.get(
+ getViewSpecificGuidelinePath(guidelineId),
+ {
+ params: {
+ guidelineId,
+ },
+ }
+ );
+ return response.data;
+};
diff --git a/src/pages/guard/guide-line/store/hooks/getViewSpecificGuideline.ts b/src/pages/guard/guide-line/store/hooks/getViewSpecificGuideline.ts
new file mode 100644
index 00000000..c7ebc26a
--- /dev/null
+++ b/src/pages/guard/guide-line/store/hooks/getViewSpecificGuideline.ts
@@ -0,0 +1,13 @@
+import {
+ getViewSpecificGuideline,
+ getViewSpecificGuidelineQueryKey,
+ ViewSpecificGuidelineResponse,
+} from '../api/view-specific-guideline.api';
+import { useQuery } from '@tanstack/react-query';
+
+export const useGetViewSpecificGuideline = (guidelineId: number) => {
+ return useQuery({
+ queryKey: [getViewSpecificGuidelineQueryKey(guidelineId)],
+ queryFn: () => getViewSpecificGuideline(guidelineId),
+ });
+};
diff --git a/src/pages/sinitto/mypage/components/ProfileBox/index.tsx b/src/pages/guard/mypage/components/profile-box/index.tsx
similarity index 97%
rename from src/pages/sinitto/mypage/components/ProfileBox/index.tsx
rename to src/pages/guard/mypage/components/profile-box/index.tsx
index 3431a621..0a838365 100644
--- a/src/pages/sinitto/mypage/components/ProfileBox/index.tsx
+++ b/src/pages/guard/mypage/components/profile-box/index.tsx
@@ -6,7 +6,7 @@ const ProfileBox = () => {
- 홍길동씨 환영합니다.
+ 홍길동님 환영합니다.
서비스 이용 방법 한번에 이해하기!
diff --git a/src/pages/guard/mypage/index.tsx b/src/pages/guard/mypage/index.tsx
new file mode 100644
index 00000000..a02a9c87
--- /dev/null
+++ b/src/pages/guard/mypage/index.tsx
@@ -0,0 +1,22 @@
+import ProfileBox from './components/profile-box';
+import { PointBox, UseDetailBox } from '@/shared/components';
+import { Box } from '@chakra-ui/react';
+import styled from '@emotion/styled';
+
+const GuardMyPage = () => {
+ return (
+
+
+
+
+
+ );
+};
+
+export default GuardMyPage;
+
+const MyPageLayout = styled(Box)`
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+`;
diff --git a/src/pages/guard/review/index.tsx b/src/pages/guard/review/index.tsx
index 06a0b0b0..0a350ff8 100644
--- a/src/pages/guard/review/index.tsx
+++ b/src/pages/guard/review/index.tsx
@@ -1,8 +1,7 @@
import { useState } from 'react';
import starIcon from './asset/star-icon.svg';
-import { BasicButton } from '@/shared/components/common/button';
-import Notice from '@/shared/components/features/notice';
+import { BasicButton, Notice } from '@/shared/components';
import { Text, Flex, Box, Textarea, Image, Button } from '@chakra-ui/react';
import styled from '@emotion/styled';
@@ -22,18 +21,18 @@ const SinittoReviewPage = () => {
return (
-
+
-
+
시니또 정보
김춘식 / 22세 / 대학생
-
+
평가하기
{[
@@ -75,11 +74,11 @@ const SinittoReviewPage = () => {
-
+
전체 평가 내용 (선택)
-
+
제출하기
@@ -98,7 +97,7 @@ const ReviewBox = styled(Box)`
flex-direction: column;
align-items: center;
width: 100%;
- max-width: 16rem;
+ max-width: 18rem;
border: 1px solid var(--color-white-gray);
border-radius: 10px;
background-color: var(--color-white-gray);
@@ -108,7 +107,7 @@ const ReviewBox = styled(Box)`
const ReviewTextBox = styled(Textarea)`
width: 100%;
- max-width: 16rem;
+ max-width: 18rem;
height: 110px;
border: 1px solid var(--color-white-gray);
border-radius: 10px;
diff --git a/src/pages/sinitto/call-back/detail/components/menu/post-accept/index.tsx b/src/pages/sinitto/call-back/detail/components/menu/post-accept/index.tsx
index 167734b3..5274e9aa 100644
--- a/src/pages/sinitto/call-back/detail/components/menu/post-accept/index.tsx
+++ b/src/pages/sinitto/call-back/detail/components/menu/post-accept/index.tsx
@@ -1,4 +1,4 @@
-import { BasicButton } from '@/shared/components/common/button';
+import { BasicButton } from '@/shared/components';
import styled from '@emotion/styled';
type Props = {
diff --git a/src/pages/sinitto/call-back/detail/components/menu/pre-accept/index.tsx b/src/pages/sinitto/call-back/detail/components/menu/pre-accept/index.tsx
index 7ed3412e..e761a13b 100644
--- a/src/pages/sinitto/call-back/detail/components/menu/pre-accept/index.tsx
+++ b/src/pages/sinitto/call-back/detail/components/menu/pre-accept/index.tsx
@@ -1,4 +1,4 @@
-import { BasicButton } from '@/shared/components/common/button';
+import { BasicButton } from '@/shared/components';
import styled from '@emotion/styled';
type Props = {
diff --git a/src/pages/sinitto/call-back/detail/index.tsx b/src/pages/sinitto/call-back/detail/index.tsx
index 43f7cd40..37e730ad 100644
--- a/src/pages/sinitto/call-back/detail/index.tsx
+++ b/src/pages/sinitto/call-back/detail/index.tsx
@@ -4,7 +4,7 @@ import { useParams, Outlet } from 'react-router-dom';
import { GuideLineList } from './components/guide-line-list';
import { PostAcceptMenu } from './components/menu/post-accept';
import { PreAcceptMenu } from './components/menu/pre-accept';
-import Notice from '@/shared/components/features/notice';
+import { Notice } from '@/shared/components';
import { Divider } from '@chakra-ui/react';
import styled from '@emotion/styled';
diff --git a/src/pages/sinitto/hello-call/hello-call-service/index.tsx b/src/pages/sinitto/hello-call/hello-call-service/index.tsx
index 58f69c57..4b1cb526 100644
--- a/src/pages/sinitto/hello-call/hello-call-service/index.tsx
+++ b/src/pages/sinitto/hello-call/hello-call-service/index.tsx
@@ -5,7 +5,7 @@ import TitleImg from './asserts/title-icon.png';
import ServiceDetail from './components/service-detail';
import { SERVICE_NOTICE } from './data/notice';
import { RouterPath } from '@/app/routes/path';
-import Notice from '@/shared/components/features/notice';
+import { Notice } from '@/shared/components';
import { Box, Button, Divider, Image, Text } from '@chakra-ui/react';
import styled from '@emotion/styled';
diff --git a/src/pages/sinitto/mypage/components/account-info-box/index.tsx b/src/pages/sinitto/mypage/components/account-info-box/index.tsx
new file mode 100644
index 00000000..2c10ea05
--- /dev/null
+++ b/src/pages/sinitto/mypage/components/account-info-box/index.tsx
@@ -0,0 +1,50 @@
+import { Box, Text } from '@chakra-ui/react';
+import styled from '@emotion/styled';
+
+const AccountInfoBox = () => {
+ return (
+
+
+
+ 계좌번호
+
+
+ 카카오뱅크 3333-3333-33333
+
+
+
+
+ 계좌 인증 여부
+
+
+ 인증 완료
+
+
+
+ );
+};
+
+export default AccountInfoBox;
+
+const AccountBoxLayout = styled(Box)`
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ background-color: #f2f2f2;
+ width: 100%;
+ max-width: 338px;
+ height: 100px;
+ border: 1px solid #909090;
+ border-radius: 5px;
+ margin-top: 0.5rem;
+`;
diff --git a/src/pages/sinitto/mypage/components/profile-box/index.tsx b/src/pages/sinitto/mypage/components/profile-box/index.tsx
new file mode 100644
index 00000000..a07663bb
--- /dev/null
+++ b/src/pages/sinitto/mypage/components/profile-box/index.tsx
@@ -0,0 +1,52 @@
+import { Box, Text } from '@chakra-ui/react';
+import styled from '@emotion/styled';
+
+const ProfileBox = () => {
+ return (
+
+
+ 시니또님 환영합니다.
+
+
+
+ 이름
+
+
+ 시니또
+
+
+
+
+ 전화번호
+
+
+ 010-1111-1111
+
+
+
+ );
+};
+
+export default ProfileBox;
+
+const ProfileBoxLayout = styled(Box)`
+ display: flex;
+ flex-direction: column;
+ background-color: #f2f2f2;
+ width: 100%;
+ max-width: 338px;
+ height: 130px;
+ border: 1px solid #909090;
+ border-radius: 5px;
+ margin-top: 0.5rem;
+`;
diff --git a/src/pages/sinitto/mypage/index.tsx b/src/pages/sinitto/mypage/index.tsx
index 6dcde85a..4604c7b2 100644
--- a/src/pages/sinitto/mypage/index.tsx
+++ b/src/pages/sinitto/mypage/index.tsx
@@ -1,20 +1,27 @@
-import PointBox from './components/PointBox';
-import ProfileBox from './components/ProfileBox';
-import UseDetailBox from './components/UseDetail';
+import AccountInfoBox from './components/account-info-box';
+import ProfileBox from './components/profile-box';
+import { BasicButton, PointBox, UseDetailBox } from '@/shared/components';
import { Box } from '@chakra-ui/react';
import styled from '@emotion/styled';
-const MyPage = () => {
+const SinittoMypage = () => {
return (
+
+ 내 정보 수정하기
+
+
+
+ 계좌번호 수정하기
+
);
};
-export default MyPage;
+export default SinittoMypage;
const MyPageLayout = styled(Box)`
display: flex;
diff --git a/src/shared/api/auth/user-register.ts b/src/shared/api/auth/user-register.ts
new file mode 100644
index 00000000..f628e925
--- /dev/null
+++ b/src/shared/api/auth/user-register.ts
@@ -0,0 +1,53 @@
+import { fetchInstance } from '../instance';
+
+// request(요청) 타입
+export type SignupReguestParams = {
+ name: string;
+ phoneNumber: string;
+ email: string;
+ isSinitto: boolean;
+};
+
+// response(응답) 타입 - 성공
+export type SignupResponse = {
+ accessToken: string;
+ refreshToken: string;
+ isSinitto?: 'true' | 'false';
+};
+
+// 에러(아직 정확히 에러코드 확인 x) or 예외
+export type SignupErrorResponse = {
+ status: number;
+ detail: string;
+};
+
+// 공통 타입 정의 (onSuccess 내부에서 분기)
+export type SignupApiResponse = SignupResponse | SignupErrorResponse;
+
+export const registerUser = async ({
+ name,
+ phoneNumber,
+ email,
+ isSinitto,
+}: SignupReguestParams): Promise => {
+ try {
+ // 시니또 보호자에 따라 API 엔드포인트 구분
+ const endpoint = isSinitto ? 'sinitto' : 'guard';
+
+ const response = await fetchInstance.post(`/api/members/${endpoint}`, {
+ name,
+ phoneNumber,
+ email,
+ isSinitto,
+ });
+ if (response.status === 207) {
+ return {
+ status: response.status,
+ detail: response.data.detail,
+ } as SignupErrorResponse; // 207 (예외 - 중복 이메일)
+ }
+ return response.data; // 200
+ } catch (err) {
+ throw new Error('회원가입 실패');
+ }
+};
diff --git a/src/shared/api/instance/index.ts b/src/shared/api/instance/index.ts
index 439db8ec..6f4dcd9f 100644
--- a/src/shared/api/instance/index.ts
+++ b/src/shared/api/instance/index.ts
@@ -1,6 +1,11 @@
-import type { AxiosInstance, AxiosRequestConfig } from 'axios';
+import type {
+ AxiosInstance,
+ AxiosRequestConfig,
+ InternalAxiosRequestConfig,
+} from 'axios';
import axios from 'axios';
+import { BASE_URI } from '@/shared/constants';
import { QueryClient } from '@tanstack/react-query';
const initInstance = (config: AxiosRequestConfig): AxiosInstance => {
@@ -10,6 +15,8 @@ const initInstance = (config: AxiosRequestConfig): AxiosInstance => {
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
+ 'Cross-Control-Allow-Origin': '*',
+
...config.headers,
},
});
@@ -18,7 +25,7 @@ const initInstance = (config: AxiosRequestConfig): AxiosInstance => {
};
export const fetchInstance = initInstance({
- baseURL: 'https://api.example.com',
+ baseURL: BASE_URI,
});
export const queryClient = new QueryClient({
@@ -31,3 +38,17 @@ export const queryClient = new QueryClient({
},
},
});
+
+fetchInstance.interceptors.request.use(
+ (config: InternalAxiosRequestConfig) => {
+ const accessToken = localStorage.getItem('accessToken');
+ if (accessToken !== undefined) {
+ config.headers['Content-Type'] = 'application/json';
+ config.headers.Authorization = `Bearer ${accessToken}`;
+ }
+ return config;
+ },
+ (error) => {
+ return Promise.reject(error);
+ }
+);
diff --git a/src/shared/components/common/button/index.tsx b/src/shared/components/common/button/BasicButton.tsx
similarity index 100%
rename from src/shared/components/common/button/index.tsx
rename to src/shared/components/common/button/BasicButton.tsx
diff --git a/src/shared/components/common/button/index.ts b/src/shared/components/common/button/index.ts
new file mode 100644
index 00000000..c0cfceb8
--- /dev/null
+++ b/src/shared/components/common/button/index.ts
@@ -0,0 +1 @@
+export { BasicButton } from './BasicButton';
diff --git a/src/shared/components/common/index.ts b/src/shared/components/common/index.ts
new file mode 100644
index 00000000..243b7344
--- /dev/null
+++ b/src/shared/components/common/index.ts
@@ -0,0 +1,2 @@
+export * from './button';
+export * from './layout';
diff --git a/src/shared/components/common/layout/Layout.tsx b/src/shared/components/common/layout/Layout.tsx
new file mode 100644
index 00000000..3f1e1633
--- /dev/null
+++ b/src/shared/components/common/layout/Layout.tsx
@@ -0,0 +1,51 @@
+import { Outlet, useLocation } from 'react-router-dom';
+
+import { RouterPath } from '@/app/routes/path';
+import { Header } from '@/shared/components';
+
+const Layout = () => {
+ const location = useLocation();
+ let title;
+
+ // 현재 경로에 따라 제목을 설정
+ switch (location.pathname) {
+ case RouterPath.REGISTER:
+ title = '회원가입';
+ break;
+ case RouterPath.SINITTO_MYPAGE:
+ title = '마이페이지';
+ break;
+ case RouterPath.GUARD_MYPAGE:
+ title = '마이페이지';
+ break;
+ case RouterPath.GUARD_GUIDELINE:
+ title = '요청 가이드라인';
+ break;
+ case RouterPath.SERVICE_HISTORY:
+ title = '서비스 이용 내역';
+ break;
+ case RouterPath.HELLO_CALL:
+ title = '안부전화 서비스';
+ break;
+ case RouterPath.SENIOR_REGISTER:
+ title = '시니어 등록';
+ break;
+ case RouterPath.CALL_BACK_LIST:
+ title = '콜백 요청';
+ break;
+ case RouterPath.SINITTO_REVIEW:
+ title = '시니또 평가';
+ break;
+ default:
+ title = '나만의 작은 시니또';
+ }
+
+ return (
+ <>
+
+
+ >
+ );
+};
+
+export default Layout;
diff --git a/src/shared/components/common/layout/index.ts b/src/shared/components/common/layout/index.ts
new file mode 100644
index 00000000..6c48faec
--- /dev/null
+++ b/src/shared/components/common/layout/index.ts
@@ -0,0 +1 @@
+export { default as Layout } from './Layout';
diff --git a/src/shared/components/features/header/index.tsx b/src/shared/components/features/header/Header.tsx
similarity index 100%
rename from src/shared/components/features/header/index.tsx
rename to src/shared/components/features/header/Header.tsx
diff --git a/src/shared/components/features/header/index.ts b/src/shared/components/features/header/index.ts
new file mode 100644
index 00000000..5653319d
--- /dev/null
+++ b/src/shared/components/features/header/index.ts
@@ -0,0 +1 @@
+export { default as Header } from './Header';
diff --git a/src/shared/components/features/index.ts b/src/shared/components/features/index.ts
new file mode 100644
index 00000000..2ffa5198
--- /dev/null
+++ b/src/shared/components/features/index.ts
@@ -0,0 +1,3 @@
+export * from './header';
+export * from './mypage';
+export * from './notice';
diff --git a/src/shared/components/features/mypage/hooks/index.ts b/src/shared/components/features/mypage/hooks/index.ts
new file mode 100644
index 00000000..1689a4dc
--- /dev/null
+++ b/src/shared/components/features/mypage/hooks/index.ts
@@ -0,0 +1 @@
+export { useToggleDetailBox } from './useToggleDetailBox';
diff --git a/src/shared/components/features/mypage/hooks/useToggleDetailBox.ts b/src/shared/components/features/mypage/hooks/useToggleDetailBox.ts
new file mode 100644
index 00000000..f3fe55c1
--- /dev/null
+++ b/src/shared/components/features/mypage/hooks/useToggleDetailBox.ts
@@ -0,0 +1,25 @@
+import { useState } from 'react';
+
+import { DUMMY_DATA } from '@/pages/sinitto/mypage/data/detail';
+
+export const useToggleDetailBox = () => {
+ // 처음에 5개 보여주고, 더보기를 눌렀을 때 나머지 전부를 보여주기
+ const [visibleCount, setVisibleCount] = useState(5); // 기본적으로 5개 보여줌
+ const [enabled, setEnabled] = useState(false); // 더보기, 숨기기 상태
+
+ // 더보기, 숨기기 버튼을 눌렀을 때 동작
+ const toggle = () => {
+ if (enabled) {
+ // 숨기기 동작
+ setVisibleCount(5);
+ } else {
+ // 더보기 동작
+ setVisibleCount(DUMMY_DATA.length);
+ }
+ setEnabled(!enabled);
+ };
+
+ const data = DUMMY_DATA.slice(0, visibleCount);
+
+ return { data, enabled, toggle };
+};
diff --git a/src/shared/components/features/mypage/index.ts b/src/shared/components/features/mypage/index.ts
new file mode 100644
index 00000000..93ba6edf
--- /dev/null
+++ b/src/shared/components/features/mypage/index.ts
@@ -0,0 +1,3 @@
+export * from './hooks';
+export * from './point-box';
+export * from './use-detail';
diff --git a/src/pages/sinitto/mypage/components/PointBox/index.tsx b/src/shared/components/features/mypage/point-box/PointBox.tsx
similarity index 100%
rename from src/pages/sinitto/mypage/components/PointBox/index.tsx
rename to src/shared/components/features/mypage/point-box/PointBox.tsx
diff --git a/src/shared/components/features/mypage/point-box/index.ts b/src/shared/components/features/mypage/point-box/index.ts
new file mode 100644
index 00000000..3381b17e
--- /dev/null
+++ b/src/shared/components/features/mypage/point-box/index.ts
@@ -0,0 +1 @@
+export { default as PointBox } from './PointBox';
diff --git a/src/pages/sinitto/mypage/components/UseDetail/index.tsx b/src/shared/components/features/mypage/use-detail/UseDetailBox.tsx
similarity index 64%
rename from src/pages/sinitto/mypage/components/UseDetail/index.tsx
rename to src/shared/components/features/mypage/use-detail/UseDetailBox.tsx
index e9a4c1e3..cbd5e610 100644
--- a/src/pages/sinitto/mypage/components/UseDetail/index.tsx
+++ b/src/shared/components/features/mypage/use-detail/UseDetailBox.tsx
@@ -1,39 +1,7 @@
-import { useState } from 'react';
-
-import { DUMMY_DATA } from '../../data/detail';
+import { useToggleDetailBox } from '../hooks/useToggleDetailBox';
import { Box, Text } from '@chakra-ui/react';
import styled from '@emotion/styled';
-// 컴포넌트는 data를 어떻게 처리하는지에 대한 관심이 없다.
-// output만 있으면 되는..
-// output을 만들어내는 과정을 분리하면 어떨까?
-
-// 관심사를 분리하기
-const useToggleDetailBox = () => {
- // 처음에 5개 보여주고, 더보기를 눌렀을 때 나머지 전부를 보여주기
- const [visibleCount, setVisibleCount] = useState(5); // 기본적으로 5개 보여줌
- const [enabled, setEnabled] = useState(false); // 더보기, 숨기기 상태
-
- // 더보기, 숨기기 버튼을 눌렀을 때 동작
- // toggleView 라는 이벤트가 발생했을 때 처리하는 이벤트 핸들러가 handleToggleView 인데
- // 이건 toggleView라는 이벤트가 발생했을 때 처리하는게 아니라, toggleView라는 행위를 하는 함수임.
- const toggle = () => {
- if (enabled) {
- // 숨기기 동작
- setVisibleCount(5);
- } else {
- // 더보기 동작
- setVisibleCount(DUMMY_DATA.length);
- }
- setEnabled(!enabled);
- };
-
- const data = DUMMY_DATA.slice(0, visibleCount);
-
- return { data, enabled, toggle };
-};
-
-// 컴포넌트는 데이터 처리에 대해 관심있는게 아니라, "어떤 데이터"를 가지고 그리는지에 관심 있음
const UseDetailBox = () => {
const { data, enabled, toggle } = useToggleDetailBox();
@@ -95,6 +63,8 @@ const DetailBox = styled(Box)`
flex-direction: column;
align-items: center;
width: 100%;
+ // TODO: 높이 지정해주세요.
+ /* height : */
max-width: 338px;
`;
@@ -103,7 +73,7 @@ const DetailFactor = styled(Box)`
flex-direction: row;
width: 100%;
max-width: 310px;
- height: 2.5rem;
+ min-height: 55px;
background-color: #fff;
margin: 0.3rem 0;
border: 1px solid #fff;
diff --git a/src/shared/components/features/mypage/use-detail/index.ts b/src/shared/components/features/mypage/use-detail/index.ts
new file mode 100644
index 00000000..6961f8d0
--- /dev/null
+++ b/src/shared/components/features/mypage/use-detail/index.ts
@@ -0,0 +1 @@
+export { default as UseDetailBox } from './UseDetailBox';
diff --git a/src/shared/components/features/notice/index.tsx b/src/shared/components/features/notice/Notice.tsx
similarity index 100%
rename from src/shared/components/features/notice/index.tsx
rename to src/shared/components/features/notice/Notice.tsx
diff --git a/src/shared/components/features/notice/index.ts b/src/shared/components/features/notice/index.ts
new file mode 100644
index 00000000..85474929
--- /dev/null
+++ b/src/shared/components/features/notice/index.ts
@@ -0,0 +1 @@
+export { default as Notice } from './Notice';
diff --git a/src/shared/components/index.ts b/src/shared/components/index.ts
new file mode 100644
index 00000000..1aacf692
--- /dev/null
+++ b/src/shared/components/index.ts
@@ -0,0 +1,2 @@
+export * from './common';
+export * from './features';
diff --git a/src/shared/constants/.gitkeep b/src/shared/constants/.gitkeep
deleted file mode 100644
index e69de29b..00000000
diff --git a/src/shared/constants/URI.ts b/src/shared/constants/URI.ts
new file mode 100644
index 00000000..1512962c
--- /dev/null
+++ b/src/shared/constants/URI.ts
@@ -0,0 +1,3 @@
+export const BASE_URI = import.meta.env.VITE_APP_BASE_URL;
+
+export const KAKAO_AUTH_URL: string = `${BASE_URI}/api/auth/oauth/kakao`;
diff --git a/src/shared/constants/index.ts b/src/shared/constants/index.ts
new file mode 100644
index 00000000..28073524
--- /dev/null
+++ b/src/shared/constants/index.ts
@@ -0,0 +1 @@
+export * from './URI';
diff --git a/src/shared/utils/storage/index.ts b/src/shared/utils/storage/index.ts
new file mode 100644
index 00000000..c562a0b8
--- /dev/null
+++ b/src/shared/utils/storage/index.ts
@@ -0,0 +1,24 @@
+type StorageKey = {
+ accessToken?: string;
+};
+
+const initStorage = (key: T, storage: Storage) => {
+ const storageKey = `${key}`;
+
+ const get = (): StorageKey[T] => {
+ const value = storage.getItem(storageKey);
+ return value as StorageKey[T];
+ };
+
+ const set = (value: StorageKey[T]) => {
+ if (value == undefined || value == null) {
+ return storage.removeItem(storageKey);
+ }
+ const stringifiedValue = JSON.stringify(value);
+ storage.setItem(storageKey, stringifiedValue);
+ };
+
+ return { get, set };
+};
+
+export const authLocalStorage = initStorage('accessToken', localStorage);