Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
1f81b71
refactor: 질문지 QuestionList 타입을 분리
ShipFriend0516 Nov 30, 2024
86f2c97
refactor: 질문지 리스트 페이지 조회 API 리액트 쿼리로
ShipFriend0516 Nov 30, 2024
23edf6b
refactor: 질문지 리스트 페이지 위치를 pages/QuestionListPage 내로 이동
ShipFriend0516 Nov 30, 2024
0c8ea2a
refactor: 질문지리스트 페이지 이름 변경
ShipFriend0516 Nov 30, 2024
45fd8c0
refactor: 질문지 상세페이지로 이동 방식 navigate에서 Link로 변경
ShipFriend0516 Nov 30, 2024
56c6dae
refactor: 질문지 리스트 컴포넌트 분리
ShipFriend0516 Nov 30, 2024
1837eb7
refactor: 카테고리 선택과 searchParams 기능을 useCategory에 위임
ShipFriend0516 Nov 30, 2024
9236032
fix: 카테고리가 전체일때 searchParams 없애도록 수정
ShipFriend0516 Nov 30, 2024
0c53f19
style: 호버시 그림자 추가
ShipFriend0516 Nov 30, 2024
269f0c3
feat: 질문지 생성 페이지에 사이드바 레이아웃 래핑
ShipFriend0516 Nov 30, 2024
82520e2
feat: 질문지 상세 페이지에 사이드바 레이아웃 래핑
ShipFriend0516 Nov 30, 2024
fb1760f
chore: 콘솔제거
ShipFriend0516 Nov 30, 2024
d158efa
feat: button 컴포넌트 호버시 투명도 살짝 추가
ShipFriend0516 Nov 30, 2024
6ce96e7
Merge remote-tracking branch 'upstream/dev' into refactor/question-li…
ShipFriend0516 Nov 30, 2024
04eec6e
feat: 작성자 닉네임 옆에 아이콘 추가
ShipFriend0516 Nov 30, 2024
4c870c2
style: 질문 아이템 flex direction col -> row로 변경
ShipFriend0516 Nov 30, 2024
5ca9f7f
feat: 스크랩 기능 및 폴더 구조 변경
ShipFriend0516 Nov 30, 2024
54c4299
fix: 언스크랩 API params를 쓰도록 수정
ShipFriend0516 Nov 30, 2024
b8c460c
refactor: isScrapped 생길때까지만 일회성 상태 사용
ShipFriend0516 Nov 30, 2024
0041474
feat: 공유하기 버튼 기능 구현
ShipFriend0516 Nov 30, 2024
dcc32a4
refactor: 로딩, 에러처리 강화
ShipFriend0516 Nov 30, 2024
9466b6f
chore: 질문지 타이틀 로딩처리 제거
ShipFriend0516 Nov 30, 2024
a1a2bb6
style: 상세보기 페이지 다크모드 지원
ShipFriend0516 Nov 30, 2024
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
35 changes: 30 additions & 5 deletions frontend/src/api/question-list/getQuestionList.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import axios from "axios";
import { api } from "@/api/config/axios.ts";
import type { QuestionList } from "@/pages/QuestionListPage/types/QuestionList";

interface QuestionListProps {
page: number;
limit: number;
page?: number;
limit?: number;
categoryName?: string;
}

export const getQuestionList = async ({ page, limit }: QuestionListProps) => {
const response = await axios.get("/api/question-list", {
export const getQuestionList = async ({
page,
limit,
}: QuestionListProps): Promise<QuestionList[]> => {
const response = await api.get("/api/question-list", {
params: {
page,
limit,
Expand All @@ -15,3 +20,23 @@ export const getQuestionList = async ({ page, limit }: QuestionListProps) => {

return response.data.data.allQuestionLists;
};

export const getQuestionListWithCategory = async ({
categoryName,
page,
limit,
}: QuestionListProps): Promise<QuestionList[]> => {
const response = await api.post(
`/api/question-list/category`,
{
categoryName,
},
{
params: {
page,
limit,
},
}
);
return response.data.data.allQuestionLists;
};
2 changes: 1 addition & 1 deletion frontend/src/components/common/Button/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const Button = ({ text, type, icon: Icon, onClick }: ButtonProps) => {

return (
<button
className={`w-full h-12 flex flex-row items-center justify-center gap-2 rounded-custom-m text-semibold-m ${buttonColor}`}
className={`w-full h-12 flex flex-row items-center justify-center gap-2 rounded-custom-m text-semibold-m ${buttonColor} hover:opacity-80`}
onClick={onClick}
>
{Icon ? <Icon /> : null}
Expand Down
14 changes: 6 additions & 8 deletions frontend/src/components/questions/QuestionsPreviewCard.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { FaStar, FaUsers } from "react-icons/fa6";
import { Link } from "react-router-dom";

interface QuestionCardProps {
id: number;
Expand All @@ -7,21 +8,20 @@ interface QuestionCardProps {
usage: number;
isStarred?: boolean;
category: string;
onClick: () => void;
}

const QuestionCard = ({
id,
title,
questionCount,
usage,
isStarred = false,
category,
onClick,
}: QuestionCardProps) => {
return (
<div
className="bg-white backdrop-blur-sm border border-gray-200 rounded-xl p-4 hover:bg-gray-200/70 transition-all cursor-pointer group dark:bg-gray-900/80 dark:border-gray-700 dark:hover:bg-gray-600/70"
onClick={onClick}
<Link
to={`/questions/${id}`}
className="bg-white backdrop-blur-sm border border-gray-200 rounded-xl p-4 hover:bg-gray-200/70 transition-all cursor-pointer group dark:bg-gray-900/80 dark:border-gray-700 dark:hover:bg-gray-600/70 hover:shadow-lg"
>
<div className="flex justify-between items-start mb-3 pt-1">
<span className="px-3 py-0.5 bg-emerald-50 text-emerald-600 dark:bg-emerald-600/20 dark:text-emerald-400 text-sm rounded-full">
Expand All @@ -35,11 +35,9 @@ const QuestionCard = ({
}`}
/>
</div>

<h3 className="text-lg font-semibold text-black dark:text-white pl-1 mb-4 line-clamp-2">
{title}
</h3>

<div className="flex items-center justify-between text-sm text-gray-400 dark:text-gray-100">
<div className="flex items-center gap-1 pl-1">
<span>{questionCount}</span>
Expand All @@ -50,7 +48,7 @@ const QuestionCard = ({
<span>{usage}</span>
</div>
</div>
</div>
</Link>
);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,33 @@
import Button from "@components/common/Button";
import { FaBookmark } from "react-icons/fa";
import { FaBookmark, FaRegBookmark } from "react-icons/fa";
import { IoMdShare } from "react-icons/io";

const ButtonSection = () => {
interface ButtonSectionProps {
scrapQuestionList: () => void;
unScrapQuestionList: () => void;
isScrapped: boolean;
shareQuestionList: () => void;
}

const ButtonSection = ({
scrapQuestionList,
unScrapQuestionList,
isScrapped,
shareQuestionList,
}: ButtonSectionProps) => {
return (
<div className="flex w-full gap-4 mt-4">
<Button text="공유하기" type="gray" icon={IoMdShare} onClick={() => {}} />
<Button
text="스크랩하기"
type="green"
icon={FaBookmark}
onClick={() => {}}
text="공유하기"
type="gray"
icon={IoMdShare}
onClick={shareQuestionList}
/>
<Button
text={isScrapped ? "스크랩 취소" : "스크랩하기"}
type={isScrapped ? "gray" : "green"}
icon={isScrapped ? FaBookmark : FaRegBookmark}
onClick={isScrapped ? unScrapQuestionList : scrapQuestionList}
/>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ interface QuestionItemProps {

const QuestionItem = ({ index, content }: QuestionItemProps) => {
return (
<div className="flex flex-col gap-1 border-custom-s border-gray-200 rounded-custom-m p-3">
<h3 className="text-semibold-m text-gray-black">Q{index + 1}</h3>
<div className="flex gap-1 border-custom-s border-gray-200 rounded-custom-m p-3">
<h3 className="text-semibold-m">Q{index + 1}.</h3>
<p className="text-medium-l">{content}</p>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { useGetQuestionContent } from "@/hooks/api/useGetQuestionContent";
import QuestionItem from "./QuestionItem";
import ErrorBlock from "@components/common/Error/ErrorBlock.tsx";
import LoadingIndicator from "@components/common/LoadingIndicator.tsx";

const QuestionList = ({ questionId }: { questionId: string }) => {
const {
Expand All @@ -8,8 +10,14 @@ const QuestionList = ({ questionId }: { questionId: string }) => {
error,
} = useGetQuestionContent(Number(questionId));

if (isLoading) return <div>로딩 중</div>;
if (error) return <div>에러가 발생</div>;
if (isLoading) return <LoadingIndicator loadingState={isLoading} />;
if (error)
return (
<ErrorBlock
error={error}
message={"질문지 내용을 불러오는데 실패했습니다."}
/>
);
if (!question) return null;

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { useGetQuestionContent } from "@/hooks/api/useGetQuestionContent";
import { MdEdit } from "react-icons/md";
import { RiDeleteBin6Fill } from "react-icons/ri";
import { FaRegBookmark } from "react-icons/fa";
import { FaRegBookmark, FaRegUser } from "react-icons/fa";
import ErrorBlock from "@components/common/Error/ErrorBlock.tsx";

const QuestionTitle = ({ questionId }: { questionId: string }) => {
const {
Expand All @@ -10,27 +11,34 @@ const QuestionTitle = ({ questionId }: { questionId: string }) => {
error,
} = useGetQuestionContent(Number(questionId));

if (isLoading) return <div>로딩 중</div>;
if (error) return <div>에러 발생</div>;
if (isLoading) return <div></div>;
if (error)
return (
<ErrorBlock
error={error}
message={"질문지 제목을 불러오는데 실패했습니다."}
/>
);
if (!question) return null;

return (
<div className="mb-4 flex flex-col gap-2">
<div className="flex justify-between">
<h3 className="text-semibold-l">{question.title}</h3>
<div className="flex gap-3 text-gray-500">
<div className="flex gap-3 text-gray-500 dark:text-gray-200">
<button>
<MdEdit className="w-6 h-6 hover:text-gray-black" />
<MdEdit className="w-6 h-6 hover:text-gray-black dark:hover:text-white" />
</button>
<button>
<RiDeleteBin6Fill className="w-6 h-6 hover:text-gray-black" />
<RiDeleteBin6Fill className="w-6 h-6 hover:text-gray-black dark:hover:text-white" />
</button>
</div>
</div>
<div className="flex gap-3">
<span className="text-medium-m text-gray-400">
<div className="inline-flex items-center gap-1 text-medium-m text-gray-400 dark:text-gray-200">
<FaRegUser />
작성자 {question.username} • {question.contents.length}개의 질문
</span>
</div>
<div className="flex gap-1 items-center">
<FaRegBookmark />
<span>{question.usage}</span>
Expand Down
22 changes: 15 additions & 7 deletions frontend/src/hooks/api/useGetQuestionList.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,30 @@
import { getQuestionList } from "@/api/question-list/getQuestionList";
import {
getQuestionList,
getQuestionListWithCategory,
} from "@/api/question-list/getQuestionList";
import { useQuery } from "@tanstack/react-query";

interface UseGetQuestionListProps {
page: number;
limit: number;
page?: number;
limit?: number;
category: string;
}

export const useCreateQuestionList = ({
export const useQuestionList = ({
page,
limit,
category = "전체",
}: UseGetQuestionListProps) => {
const { data, isLoading, error } = useQuery({
queryKey: ["questions", page, limit],
queryFn: () => getQuestionList({ page, limit }),
queryKey: ["questions", page, limit, category],
queryFn: () =>
category !== "전체"
? getQuestionListWithCategory({ categoryName: category, page, limit })
: getQuestionList({ page, limit }),
});

return {
questions: data,
data,
isLoading,
error,
};
Expand Down
31 changes: 17 additions & 14 deletions frontend/src/pages/CreateQuestionPage.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
import QuestionForm from "@/components/questions/create/QuestionForm";
import { IoArrowBackSharp } from "react-icons/io5";
import { Link } from "react-router-dom";
import SidebarPageLayout from "@components/layout/SidebarPageLayout.tsx";

const CreateQuestionPage = () => {
return (
<div className="m-20">
<Link
to={"/questions"}
className="flex items-center gap-4 mb-5 text-gray-black text-medium-l"
>
<IoArrowBackSharp className="w-5 h-5" />
<span>면접 리스트로 돌아가기</span>
</Link>
<h1 className="text-bold-l mb-2">새로운 면접 질문 리스트 만들기</h1>
<p className="text-medium-l text-gray-400 mb-8">
면접 스터디를 위한 새로운 질문지를 생성합니다.
</p>
<QuestionForm />
</div>
<SidebarPageLayout>
<div className="m-20">
<Link
to={"/questions"}
className="flex items-center gap-4 mb-5 text-gray-black text-medium-l"
>
<IoArrowBackSharp className="w-5 h-5" />
<span>면접 리스트로 돌아가기</span>
</Link>
<h1 className="text-bold-l mb-2">새로운 면접 질문 리스트 만들기</h1>
<p className="text-medium-l text-gray-400 mb-8">
면접 스터디를 위한 새로운 질문지를 생성합니다.
</p>
<QuestionForm />
</div>
</SidebarPageLayout>
);
};

Expand Down
48 changes: 0 additions & 48 deletions frontend/src/pages/QuestionDetailPage.tsx

This file was deleted.

Loading