Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Week6/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
},
"dependencies": {
"@hookform/resolvers": "^5.0.1",
"@tanstack/react-query": "^5.72.1",
"@tanstack/react-query": "^5.76.1",
"@tanstack/react-query-devtools": "^5.75.2",
"axios": "^1.8.4",
"clsx": "^2.1.1",
Expand All @@ -21,6 +21,7 @@
"react-content-loader": "^7.0.2",
"react-dom": "^19.0.0",
"react-hook-form": "^7.55.0",
"react-icons": "^5.5.0",
"react-router-dom": "^7.4.1",
"zod": "^3.24.2"
},
Expand Down
Binary file added Week6/public/Lp.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Week6/public/closed-eyes.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Week6/public/eyes.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Week6/public/profile.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion Week6/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
import HomePage from './pages/Home/HomePage';
import Layout from './layout/Layout';
import SignupPage from './pages/SignUp/SignupPage';
import Mypage from './pages/Mypage';
import Mypage from './pages/Mypage/Mypage';
import LoginPage from './pages/Login/LoginPage';
import ProtectedLayout from './layout/ProtectedLayout';
import GoogleLoginRedirectPage from './pages/Login/GoogleLoginRedirectPage';
Expand Down
23 changes: 23 additions & 0 deletions Week6/src/apis/image.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { privateAxios, publicAxios } from './axiosInstance';
import { API_UPLOADS } from '../constants/api';
import { ResponseImageDto } from '../types/image';

export const postImagePrivate = async (
file: File,
): Promise<ResponseImageDto> => {
const formData = new FormData();
formData.append('file', file); // file타입

const { data } = await privateAxios.post(
API_UPLOADS.PRIVATE_UPLOAD,
formData,
);

return data;
};

export const postImagePublic = async () => {
const { data } = await publicAxios.post(API_UPLOADS.PUBLIC_UPLOAD);

return data;
};
105 changes: 103 additions & 2 deletions Week6/src/apis/lp.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { API_COMMENTS, API_LPS } from '../constants/api';
import { API_COMMENTS, API_LIKES, API_LPS } from '../constants/api';
import { SortOrder } from '../constants/sort';
import {
ResponseLpDto,
ResponseLpDetailDto,
ResponseCommentDto,
CreateLpDto,
ResponsePostCommentDto,
ResponsePatchCommentDto,
patchLpDto,
} from '../types/lp';
import { privateAxios, publicAxios } from './axiosInstance';

Expand All @@ -25,6 +29,7 @@ export const getLpInfo = async ({
order,
},
});
console.log(data);
return data;
};

Expand All @@ -36,7 +41,7 @@ export const getLpDetail = async (
};

interface GetCommentsParms extends GetLpInfoParams {
lpId: number | string;
lpId: number;
}

export const getComments = async ({
Expand All @@ -51,3 +56,99 @@ export const getComments = async ({
);
return data;
};

export const postComment = async ({
lpId,
content,
}: {
lpId: number;
content: string;
}) => {
const { data } = await privateAxios.post<ResponsePostCommentDto>(
API_COMMENTS.CREATE(lpId),
{ content },
);
return data;
};

export const patchComment = async ({
lpId,
commentId,
content,
}: {
lpId: number;
commentId: number;
content: string;
}) => {
const { data } = await privateAxios.patch<ResponsePostCommentDto>(
API_COMMENTS.UPDATE(lpId, commentId),
{ content },
);
return data;
};

export const deleteComment = async ({
lpId,
commentId,
}: {
lpId: number;
commentId: number;
}) => {
const { data } = await privateAxios.delete<ResponsePatchCommentDto>(
API_COMMENTS.DELETE(lpId, commentId),
);

return data;
};

export const postLp = async ({
title,
content,
thumbnail,
tags,
published = true,
}: CreateLpDto) => {
const { data } = await privateAxios.post(API_LPS.CREATE, {
title,
content,
thumbnail,
tags,
published,
});

return data;
};

export const patchLp = async ({
lpId,
title,
content,
thumbnail,
tags,
published = true,
}: patchLpDto) => {
const { data } = await privateAxios.patch(API_LPS.UPDATE(lpId), {
title,
content,
thumbnail,
tags,
published,
});

return data;
};

export const deleteLp = async (lpId: number) => {
const { data } = await privateAxios.delete(API_LPS.DELETE(lpId));
return data;
};

export const postLike = async (lpId: number) => {
const { data } = await privateAxios.post(API_LIKES.LIKE(lpId));
return data;
};

export const deleteLike = async (lpId: number) => {
const { data } = await privateAxios.delete(API_LIKES.UNLIKE(lpId));
return data;
};
24 changes: 24 additions & 0 deletions Week6/src/apis/users.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { API_USERS } from '../constants/api';
import { privateAxios } from './axiosInstance';

interface patchUsersProps {
name: string;
bio: string;
avatar: string;
}

export const patchUsers = async ({ name, bio, avatar }: patchUsersProps) => {
const { data } = await privateAxios.patch(API_USERS.UPDATE_USER, {
name,
bio,
avatar,
});

return data;
};

export const deleteUser = async () => {
const { data } = await privateAxios.delete(API_USERS.DELETE_USER);

return data;
};
16 changes: 16 additions & 0 deletions Week6/src/components/LogoutButton/LogoutButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { useAuth } from '../../context/AuthContext';

function LogoutButton() {
const { logout } = useAuth();

return (
<button
onClick={logout}
className="px-4 py-2 text-white transition-colors duration-100 rounded-md bg-sky-600 hover:bg-sky-400"
>
로그아웃
</button>
);
}

export default LogoutButton;
56 changes: 56 additions & 0 deletions Week6/src/components/Modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { PropsWithChildren } from 'react';
import { createPortal } from 'react-dom';

interface ModalProps extends PropsWithChildren {
message: string;
onConfirm: () => void;
onCancel: () => void;
/** 버튼 레이블(기본값: “예”) */
confirmText?: string;
/** 버튼 레이블(기본값: “아니오”) */
cancelText?: string;
}

export default function Modal({
message,
onConfirm,
onCancel,
confirmText = '예',
cancelText = '아니오',
}: ModalProps) {
// DOM 계층 구조 바깥에 렌더링
// createPortal(ReactNode, DOMElement)
return createPortal(
<div className="fixed inset-0 z-50 flex items-center justify-center">
{/* overlay */}
<div
className="absolute inset-0 bg-black opacity-60"
onClick={onCancel}
/>
{/* dialog */}
<div className="relative z-10 w-full max-w-sm p-8 bg-white rounded-lg shadow-lg">
{/* 메시지 */}
<p className="mb-6 text-center text-gray-900">{message}</p>

{/* 버튼 그룹 */}
<div className="flex justify-center gap-4">
<button
type="button"
onClick={onConfirm}
className="flex-1 py-2 text-gray-900 transition bg-gray-200 rounded-md hover:bg-gray-300"
>
{confirmText}
</button>
<button
type="button"
onClick={onCancel}
className="flex-1 py-2 text-white transition bg-red-500 rounded-md hover:bg-red-600"
>
{cancelText}
</button>
</div>
</div>
</div>,
document.body,
);
}
18 changes: 9 additions & 9 deletions Week6/src/constants/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,24 @@ export const API_LPS = {
CREATE: '/v1/lps',
LIST_BY_USER_ID: (userId: string) => `/v1/lps/user/${userId}`,
LIST_MY: '/v1/lps/user',
DETAIL: (lpId: string | number) => `/v1/lps/${lpId}`,
UPDATE: (lpId: string | number) => `/v1/lps/${lpId}`,
DELETE: (lpId: string) => `/v1/lps/${lpId}`,
DETAIL: (lpId: number) => `/v1/lps/${lpId}`,
UPDATE: (lpId: number) => `/v1/lps/${lpId}`,
DELETE: (lpId: number) => `/v1/lps/${lpId}`,
LIST_BY_TAG: (tagName: string) => `/v1/lps/tag/${tagName}`,
};

export const API_COMMENTS = {
LIST: (lpId: string | number) => `/v1/lps/${lpId}/comments`,
CREATE: (lpId: string) => `/v1/lps/${lpId}/comments`,
UPDATE: (lpId: string, commentId: string) =>
LIST: (lpId: number) => `/v1/lps/${lpId}/comments`,
CREATE: (lpId: number) => `/v1/lps/${lpId}/comments`,
UPDATE: (lpId: number, commentId: number) =>
`/v1/lps/${lpId}/comments/${commentId}`,
DELETE: (lpId: string, commentId: string) =>
DELETE: (lpId: number, commentId: number) =>
`/v1/lps/${lpId}/comments/${commentId}`,
};

export const API_LIKES = {
LIKE: (lpId: string) => `/v1/lps/${lpId}/likes`,
UNLIKE: (lpId: string) => `/v1/lps/${lpId}/likes`,
LIKE: (lpId: number) => `/v1/lps/${lpId}/likes`,
UNLIKE: (lpId: number) => `/v1/lps/${lpId}/likes`,
LIST_MY_LIKES: '/v1/lps/likes/me',
LIST_USER_LIKES: (userId: string) => `/v1/lps/likes/${userId}`,
};
Expand Down
6 changes: 5 additions & 1 deletion Week6/src/constants/images.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
export const IMAGE_PATH = {
GOOGLE_LOGO: '/google-logo.png',
PROFILE: '/my.png',
MY: '/my.png',
SEARCH_ICON: '/search.png',
LOGO: '/Logo.png',
EYE: '/eyes.png',
CLOSED_EYE: '/closed-eyes.png',
LP: '/Lp.png',
PROFILE: '/profile.png',
} as const;
7 changes: 7 additions & 0 deletions Week6/src/constants/key.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,10 @@ export const LOCAL_STORAGE_KEY = {
accessToken: 'accessToken',
refreshToken: 'refreshToken',
} as const;

export const QUERY_KEY = {
users: 'users',
lpInfo: 'lpInfo',
lpDetail: 'lpDetail',
comments: 'comments',
} as const;
Loading