issue # 회원가입 화면 구현 중

This commit is contained in:
민건희
2025-11-05 23:14:32 +09:00
parent 3a6e3eb70b
commit 917bef73b0
13 changed files with 176 additions and 91 deletions

54
package-lock.json generated
View File

@@ -50,6 +50,7 @@
"react-dom": "^19.1.1",
"react-hook-form": "^7.66.0",
"react-resizable-panels": "^3.0.6",
"react-router-dom": "^7.9.5",
"recharts": "^2.15.4",
"sonner": "^2.0.7",
"tailwind-merge": "^3.3.1",
@@ -4069,6 +4070,15 @@
"dev": true,
"license": "MIT"
},
"node_modules/cookie": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
"integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -5773,6 +5783,44 @@
"react-dom": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
}
},
"node_modules/react-router": {
"version": "7.9.5",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.5.tgz",
"integrity": "sha512-JmxqrnBZ6E9hWmf02jzNn9Jm3UqyeimyiwzD69NjxGySG6lIz/1LVPsoTCwN7NBX2XjCEa1LIX5EMz1j2b6u6A==",
"license": "MIT",
"dependencies": {
"cookie": "^1.0.1",
"set-cookie-parser": "^2.6.0"
},
"engines": {
"node": ">=20.0.0"
},
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18"
},
"peerDependenciesMeta": {
"react-dom": {
"optional": true
}
}
},
"node_modules/react-router-dom": {
"version": "7.9.5",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.9.5.tgz",
"integrity": "sha512-mkEmq/K8tKN63Ae2M7Xgz3c9l9YNbY+NHH6NNeUmLA3kDkhKXRsNb/ZpxaEunvGo2/3YXdk5EJU3Hxp3ocaBPw==",
"license": "MIT",
"dependencies": {
"react-router": "7.9.5"
},
"engines": {
"node": ">=20.0.0"
},
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18"
}
},
"node_modules/react-smooth": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.4.tgz",
@@ -5960,6 +6008,12 @@
"semver": "bin/semver.js"
}
},
"node_modules/set-cookie-parser": {
"version": "2.7.2",
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz",
"integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==",
"license": "MIT"
},
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",

View File

@@ -52,6 +52,7 @@
"react-dom": "^19.1.1",
"react-hook-form": "^7.66.0",
"react-resizable-panels": "^3.0.6",
"react-router-dom": "^7.9.5",
"recharts": "^2.15.4",
"sonner": "^2.0.7",
"tailwind-merge": "^3.3.1",

View File

@@ -1,16 +1,26 @@
import { useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'
import SignUpPage from './ui/page/signup/SignUpPage'
import { useState } from 'react';
import reactLogo from './assets/react.svg';
import viteLogo from '/vite.svg';
import './App.css';
import SignUpPage from './ui/page/signup/SignUpPage';
import Layout from './layouts/Layout';
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
import { useAuthStore } from './store/authStore';
import { PageRouting } from './data/RoutingData';
function App() {
const { authData } = useAuthStore();
return (
<div className="w-full h-full flex flex-col justify-center items-center">
<SignUpPage></SignUpPage>
</div>
)
<Router>
<Routes>
<Route element={<Layout />}>
<Route element={<SignUpPage />} path={PageRouting["SIGN_UP"].path} />
{!(authData?.isLogedIn) ? <Route element={<Navigate to={`/${PageRouting["SIGN_UP"].path}`} />} path="*" /> : null}
</Route>
</Routes>
</Router>
);
}
export default App

5
src/data/AuthData.ts Normal file
View File

@@ -0,0 +1,5 @@
export type AuthData = {
accessToken: string;
refreshToken: string;
isLogedIn: boolean;
}

20
src/data/RoutingData.ts Normal file
View File

@@ -0,0 +1,20 @@
type PageRoutingInfo = {
path: string;
title: string;
}
export const PageRouting: Record<string, PageRoutingInfo> = {
LOGIN: { path: "login", title: "" },
SIGN_UP: { path: "signup", title: "" },
RESET_PASSWORD: { path: "reset-password", title: "" },
HOME: { path: "home", title: "홈" },
SCHEDULES: { path: "schedules", title: "일정" },
SCHEDULES_NEW: { path: "schedules/new", title: "일정 생성" },
SCHEDULES_EDIT: { path: "schedules/edit", title: "일정 수정" },
SCHEDULES_DETAIL: { path: "schedules/detail", title: "일정 상세" },
USER_INFO: { path: "info", title: "사용자 정보" },
USER_FOLLOWING: { path: "info/following", title: "팔로잉 목록" },
USER_FOLLOWER: { path: "info/follower", title: "팔로워 목록" },
SETTINGS: { path: "settings", title: "설정" },
NOT_FOUD: { path: "not-found", title: "존재하지 않는 페이지" },
} as const;

5
src/data/UserInfoData.ts Normal file
View File

@@ -0,0 +1,5 @@
export type UserInfoData = {
name: string;
nickname: string;
email: string;
}

23
src/layouts/Layout.tsx Normal file
View File

@@ -0,0 +1,23 @@
import SideBar from "@/ui/component/SideBar";
import { Outlet } from "react-router-dom";
import { SidebarProvider } from "@/components/ui/sidebar";
import Header from "@/ui/component/Header";
import { useAuthStore } from '@/store/authStore';
export default function Layout() {
const { authData } = useAuthStore();
return (
<SidebarProvider
defaultOpen={false}
id="root"
>
<SideBar />
<div className="flex flex-col w-full h-full">
{ authData?.isLogedIn ? <Header /> : null}
{/* <Header /> */}
<Outlet />
</div>
</SidebarProvider>
);
}

View File

13
src/store/authStore.ts Normal file
View File

@@ -0,0 +1,13 @@
import type { AuthData } from '@/data/AuthData';
import { create } from 'zustand';
interface AuthStoreProps {
authData: AuthData | undefined;
login: (data: AuthData) => void;
}
export const useAuthStore = create<AuthStoreProps>((set) => ({
authData: undefined,
login: (data: AuthData) => set({ authData: data }),
logout: () => set({ authData: undefined })
}));

View File

@@ -1,13 +1,13 @@
import { Label } from '@/components/ui/label';
import { SidebarTrigger } from '@/components/ui/sidebar';
import { Separator } from '@/components/ui/separator';
import { useState } from 'react';
import Routing from './RoutingData';
export default function Header() {
return (
<header className="flex shrink-0 items-center gap-2 border-b px-4 w-full h-12">
<SidebarTrigger className="-ml-1" />
<Separator orientation="vertical" className="mr-2 data-[orientation=vertical]:h-4"/>
<Separator orientation="vertical" className="mr-2 data-[orientation=vertical]:h-4" />
<Label>{import.meta.env.BASE_URL}</Label>
</header>
);

View File

@@ -1,20 +0,0 @@
type PageRoutingInfo = {
path: string;
title: string;
}
export const PageRouting: Record<string, PageRoutingInfo> = {
LOGIN: { path: "login", title: "" },
SIGN_UP: { path: "signup", title: "" },
RESET_PASSWORD: { path: "reset-password", title: "" },
HOME: { path: "home", title: "홈" },
SCHEDULES: { path: "schedules", title: "일정" },
SCHEDULES_NEW: { path: "schedules/new", title: "일정 생성" },
SCHEDULES_EDIT: { path: "schedules/edit", title: "일정 수정" },
SCHEDULES_DETAIL: { path: "schedules/detail", title: "일정 상세" },
USER_INFO: { path: "info", title: "사용자 정보" },
USER_FOLLOWING: { path: "info/following", title: "팔로잉 목록" },
USER_FOLLOWER: { path: "info/follower", title: "팔로워 목록" },
SETTINGS: { path: "settings", title: "설정" },
NOT_FOUD: { path: "not-found", title: "존재하지 않는 페이지" },
} as const;

View File

@@ -4,8 +4,12 @@ import {
SidebarContent,
SidebarFooter,
SidebarHeader
} from './components/ui/sidebar';
} from '@/components/ui/sidebar';
export default function SideBar() {
return (<Sidebar></Sidebar>)
return (
<Sidebar>
</Sidebar>
);
}

View File

@@ -1,58 +1,28 @@
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { useState } from 'react';
import { format } from 'date-fns';
import { Label } from '@/components/ui/label';
import { Calendar } from '@/components/ui/calendar';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle
} from '@/components/ui/card';
import { Form, FormField } from '@/components/ui/form';
export default function SignUpPage() {
const [open, setOpen] = useState<boolean>(false);
const [date, setDate] = useState<Date>(new Date());
return (
<div className="w-full h-full flex flex-row justify-center items-center">
<div className="flex flex-col gap-4 justify-center items-center">
<Label>Date Picker</Label>
<Popover
open={open}
onOpenChange={setOpen}
>
<PopoverTrigger asChild>
<Button
variant="outline"
id="date"
className="w-fit justify-between font-normal"
>
{date ? format(date, "yyyy/MM/dd") : "Select Date"}
</Button>
</PopoverTrigger>
<PopoverContent>
<Calendar
mode="single"
timeZone="Asia/Seoul"
formatters={{
formatCaption: (month) =>
format(month, "yyyy년 MM월")
}}
onSelect={(date) => {
if (date) {
setDate(date);
setOpen(false);
}
}}
selected={date}
defaultMonth={date}
captionLayout="dropdown"
/>
</PopoverContent>
</Popover>
<Input
type="time"
id="time"
defaultValue={format(date, "HH:mm")}
/>
</div>
<div className="w-full h-full flex flex-col justify-center items-center">
<Card className="w-xl h-4/6">
<CardHeader className="ml-2.5 select-none">
<CardTitle className="text-3xl"></CardTitle>
</CardHeader>
<CardContent>
<Label>a</Label>
</CardContent>
</Card>
</div>
);
}