dragStart(e, index)}
- onDragEnter={(e) => dragEnter(e, index)}
+ onDragStart={() => dragStart(index)}
+ onDragEnter={() => dragEnter(index)}
onDragEnd={drop}
onDragOver={(e) => e.preventDefault()}
>
diff --git a/src/app/(intro)/components/error-boundary.tsx b/src/app/intro/components/error-boundary.tsx
similarity index 100%
rename from src/app/(intro)/components/error-boundary.tsx
rename to src/app/intro/components/error-boundary.tsx
diff --git a/src/app/(intro)/components/navigation.tsx b/src/app/intro/components/navigation.tsx
similarity index 100%
rename from src/app/(intro)/components/navigation.tsx
rename to src/app/intro/components/navigation.tsx
diff --git a/src/app/intro/page.tsx b/src/app/intro/page.tsx
new file mode 100644
index 00000000..fddc7758
--- /dev/null
+++ b/src/app/intro/page.tsx
@@ -0,0 +1,30 @@
+import Link from "next/link";
+import { ClientRoute } from "@config/route";
+
+export default function Intro() {
+ return (
+
+ {/* 스크린 리더 전용 텍스트*/}
+
+ Link At Once! 소셜 프로필 링크 관리 서비스 in my link 입니다!
+
+
시작하기 버튼을 눌러 로그인을 진행해 주세요.
+
+
+
+ link at once!
+
+
+ Lorem ipsum dolor sit amet consectetur.
+
+
+
+ START!
+
+
+
+ );
+}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 19814b3e..17dc7516 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -18,7 +18,7 @@ export default function RootLayout({
children: React.ReactNode;
}>) {
return (
-
+
{children}
);
diff --git a/src/app/link/page.tsx b/src/app/link/page.tsx
deleted file mode 100644
index ab822bb6..00000000
--- a/src/app/link/page.tsx
+++ /dev/null
@@ -1,101 +0,0 @@
-export default function LinkPage() {
- return (
- <>
-
-
-
- {/* 스타일 */}
-
-
-
-
-
-

-
-
-
-
-
-
-
-
- 스타일 *
-
- {/* item * 4 */}
-
-
- {/* style type img */}
-
-
썸네일
-
-
-
-
-
-
- {/* Info */}
-
-
- >
- );
-}
diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx
index 817f3eee..372ea7f9 100644
--- a/src/app/login/page.tsx
+++ b/src/app/login/page.tsx
@@ -1,10 +1,13 @@
"use client";
import { useState } from "react";
+import { useRouter } from "next/navigation";
+import { ClientRoute } from "@config/route";
export default function Login() {
const [userId, setUserId] = useState("");
const [password, setPassword] = useState("");
+ const router = useRouter();
async function handleLogin(e: React.FormEvent
) {
e.preventDefault();
@@ -25,7 +28,11 @@ export default function Login() {
const infor = await response.json();
if (response.ok) {
alert("성공");
+ // 세션 스토리지에 토큰 저장
sessionStorage.setItem("token", infor.data.token);
+ // 쿠키에 토큰 저장
+ document.cookie = `token=${infor.data.token}; expires=Fri, 31 Dec 9999 23:59:59 GMT; path=/`;
+ router.push(ClientRoute.MAIN as string);
} else {
alert("실패");
}
diff --git a/src/app/page.tsx b/src/app/page.tsx
new file mode 100644
index 00000000..023f57af
--- /dev/null
+++ b/src/app/page.tsx
@@ -0,0 +1,38 @@
+"use client";
+
+import { ClientRoute } from "@config/route";
+import Link from "next/link";
+import { useRouter } from "next/navigation";
+
+export default function Intro() {
+ const router = useRouter();
+
+ // 로그아웃 함수: 세션 스토리지와 쿠키에서 토큰 제거 후 리다이렉트
+ async function handleLogout() {
+ try {
+ // 인증 관련 데이터 제거
+ sessionStorage.removeItem("token");
+ document.cookie =
+ "token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
+
+ await router.push(ClientRoute.MAIN as string);
+ router.refresh();
+ } catch (error) {
+ console.error("로그아웃 중 오류 발생:", error);
+ }
+ }
+
+ return (
+ <>
+ Home
+ in my link
+
+ Admin
+
+
+
+ >
+ );
+}
diff --git a/src/config/route.tsx b/src/config/route.tsx
index 548783d3..57fb472e 100644
--- a/src/config/route.tsx
+++ b/src/config/route.tsx
@@ -1,13 +1,14 @@
import { ClientRouteType } from "@config/types";
export const ClientRoute: ClientRouteType = {
- MAIN: "/",
- LOGIN: "/login",
- JOIN: "/join",
- ADMIN: "/admin",
- MY: "/admin/my",
+ MAIN: "/", // 메인 페이지
+ INTRO: "/intro", // 랜딩 페이지
+ LOGIN: "/login", // 로그인 페이지
+ JOIN: "/join", // 회원가입 페이지
+ ADMIN: "/admin", // 관리자 페이지
+ MY: "/admin/my", // 개인 페이지
PROFILE: {
- DETAIL: "/admin/profile/detail",
- EDIT: "/admin/profile/edit",
+ DETAIL: "/admin/profile/detail", // 프로필 상세 페이지
+ EDIT: "/admin/profile/edit", // 프로필 수정 페이지
},
};
diff --git a/src/lib/check-url.ts b/src/lib/check-url.ts
new file mode 100644
index 00000000..710c7dd6
--- /dev/null
+++ b/src/lib/check-url.ts
@@ -0,0 +1,4 @@
+export const checkUrl = (strUrl: string) => {
+ const exp = /^http[s]?\:\/\//i;
+ return exp.test(strUrl);
+};
diff --git a/src/lib/post-block.ts b/src/lib/post-block.ts
new file mode 100644
index 00000000..048ae71c
--- /dev/null
+++ b/src/lib/post-block.ts
@@ -0,0 +1,40 @@
+import { getSequence } from "./get-sequence";
+import { AppRouterInstance } from "next/dist/shared/lib/app-router-context.shared-runtime";
+
+export const postBlock = async (
+ path: string,
+ params: { [index: string]: string | number },
+ router?: AppRouterInstance,
+) => {
+ const token = sessionStorage.getItem("token");
+ if (!token) {
+ if (router) router.push("/login");
+ return;
+ }
+ params["sequence"] = (await getSequence(token)) + 1;
+
+ try {
+ const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}${path}`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: `Bearer ${token}`,
+ },
+ body: JSON.stringify(params),
+ });
+ const responseJson = await response.json();
+ if (response.ok) {
+ console.log("성공");
+ return responseJson;
+ } else {
+ const { status } = response;
+ const { message } = responseJson;
+ if (status === 500) {
+ alert("서버 에러");
+ }
+ console.log(`Error: ${status}, Message: ${message || "Unknown error"}`);
+ }
+ } catch (error) {
+ throw new Error(error instanceof Error ? error.message : "알 수 없는 에러");
+ }
+};
diff --git a/src/middleware.ts b/src/middleware.ts
index b10d853d..798000a8 100644
--- a/src/middleware.ts
+++ b/src/middleware.ts
@@ -2,20 +2,37 @@
import { NextRequest, NextResponse } from "next/server";
export function middleware(request: NextRequest) {
- // const token = request.cookies.get("token"); // 쿠키에서 인증 토큰을 가져옴
+ const token = request.cookies.get("token");
- // if (
- // !token &&
- // request.nextUrl.pathname !== "/login" &&
- // request.nextUrl.pathname !== "/landing"
- // ) {
- // return NextResponse.redirect(new URL("/landing", request.url));
- // }
+ if (
+ !token &&
+ request.nextUrl.pathname !== "/login" &&
+ request.nextUrl.pathname !== "/intro"
+ ) {
+ return NextResponse.redirect(new URL("/intro", request.url));
+ }
- return NextResponse.next(); // 로그인된 사용자에 대한 요청은 통과
+ // 이미 로그인된 사용자가 로그인 또는 회원가입 페이지에 접근하면 메인 페이지로 리다이렉트
+ if (
+ token &&
+ (request.nextUrl.pathname === "/login" ||
+ request.nextUrl.pathname === "/join" ||
+ request.nextUrl.pathname === "/intro")
+ ) {
+ return NextResponse.redirect(new URL("/", request.url));
+ }
+
+ return NextResponse.next();
}
// 인증이 필요한 페이지 설정
export const config = {
- matcher: ["/main", "/profile/:path*", "/admin"], // 인증이 필요한 경로 지정
+ matcher: [
+ "/",
+ "/profile/:path*",
+ "/admin/:path*",
+ "/login",
+ "/join",
+ "/intro",
+ ], // 인증이 필요한 경로 지정
};
diff --git a/src/styles/global.css b/src/styles/global.css
index fc8a6334..60a92a06 100644
--- a/src/styles/global.css
+++ b/src/styles/global.css
@@ -32,9 +32,12 @@ body {
color: var(--foreground);
background: var(--background);
font-family: Arial, Helvetica, sans-serif;
-
+ -ms-overflow-style: none;
@apply tracking-tight;
}
+::-webkit-scrollbar {
+ display: none;
+}
input {
@apply h-12 w-full rounded-lg border-1 border-gray-200;