Skip to content
Open
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
45 changes: 45 additions & 0 deletions src/apis/main.api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { mainPosts, mainTags } from '@/types/main.model';
import { Pagination } from '@/types/pagination.model';
import { httpClient } from './http.api';

export interface FetchMainDataParams {
selectedTags: number[];
currentPage: number;
limit: number;
}

export interface FetchMainDataResponse {
posts: mainPosts[];
tags: mainTags[];
pagination: Pagination;
filteredPosts: mainPosts[];
}


// 기본 및 태그별 게시물 요청
export const fetchMainData = async ({ selectedTags, currentPage, limit }: FetchMainDataParams): Promise<FetchMainDataResponse> => {
try {
// 기본 게시글 데이터 요청
const responseMainData = await httpClient.get<FetchMainDataResponse>('/api/main', {
params: { page: currentPage, limit }
});

// 태그별 필터링된 게시글 데이터 요청 (선택된 태그가 있을 때만)
let filteredPosts: mainPosts[] = [];
if (selectedTags.length > 0) {
const params = new URLSearchParams();
selectedTags.forEach(tag => params.append('tags', tag.toString()));
const responsePostsByTags = await httpClient.get('/api/main/tags', { params });
filteredPosts = responsePostsByTags.data;
}

return {
posts: responseMainData.data.posts, // 기본 게시글
tags: responseMainData.data.tags, // 태그 데이터
pagination: responseMainData.data.pagination, // 페이지네이션 정보
filteredPosts, // 선택된 태그에 따라 필터링된 게시글 (없으면 빈 배열)
};
} catch {
throw new Error("Failed to fetch data");
}
}
11 changes: 0 additions & 11 deletions src/apis/maindata.api.ts

This file was deleted.

60 changes: 0 additions & 60 deletions src/components/main-page/MainTagList.tsx

This file was deleted.

67 changes: 67 additions & 0 deletions src/components/main-page/Pagination.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import styled from 'styled-components';
import { useSearchParams } from 'react-router';
import { Pagination as IPagination } from '@/types/pagination.model';

interface Props {
pagination?: IPagination;
}

const Pagination = ({pagination} : Props) => {
const [searchParams, setSearchParams] = useSearchParams();
const totalCount = pagination?.totalCount;
const page = pagination?.page;
const pages: number = Math.ceil(totalCount / 20);

const handleClickPage = (page: number) => {
const newSearchParams = new URLSearchParams(searchParams);

newSearchParams.set('page', page.toString());

setSearchParams(newSearchParams);
}
return (
<PaginationStyle>
{
pages > 0 && (
<ol>
{
Array(pages).fill(0).map((_, index) => (
<li key={index}>
<button className={ page ? 'active' : ''} onClick={() => {handleClickPage(index+1)} }>{index + 1}</button>
</li>
))
}
</ol>
)
}
</PaginationStyle>
)
}

const PaginationStyle = styled.div`
display: flex;
justify-content: start;
align-items: center;
padding: 24px;

ol {
list-style: none;
display: flex;
gap: 8px;
padding: 0;
margin: 0;
}

button {
border: 1px solid #ccc;
border-radius: 5px;
padding: 5px 6px;
cursor: pointer;

&.active {
background-color: #deffe2;
}
}
`;

export default Pagination
48 changes: 26 additions & 22 deletions src/components/main-page/QuestionBox.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { useEffect, useState } from 'react';
import styled from 'styled-components';
import QuestionBody from '../ui/molecules/mainpage-molecule/QuestionBody';
import QuestionHeader from '../ui/molecules/mainpage-molecule/QuestionHeader';
import QuestionTag from '../ui/atoms/mainpage-atom/QuesitonTag';
import QuestionBottom from '../ui/molecules/mainpage-molecule/QuestionBottom';
import { fetchMainData } from '@/apis/maindata.api';
import { mainPosts } from '@/types/main.model';

const QuestionBoxContainer = styled.div`
Expand All @@ -18,32 +16,38 @@ const QuestionItem = styled.div`
margin: 10px;
`;

function QuestionBox() {
const [posts, setPosts] = useState<mainPosts[]>([]);
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);
interface Props {
posts?: mainPosts[];
isLoading: boolean;
error?: unknown;
}

function QuestionBox({posts = [], isLoading, error} : Props) {
// const [posts, setPosts] = useState<mainPosts[]>([]);
// const [loading, setLoading] = useState<boolean>(true);
// const [error, setError] = useState<string | null>(null);

useEffect(() => {
const loadPosts = async () => {
try {
const data = await fetchMainData();
setPosts(data.posts);
} catch (err) {
setError('데이터를 불러오는 중 오류가 발생했습니다.');
} finally {
setLoading(false);
}
};
// useEffect(() => {
// const loadPosts = async () => {
// try {
// const data = await fetchMainData();
// setPosts(data.posts);
// } catch (err) {
// setError('데이터를 불러오는 중 오류가 발생했습니다.');
// } finally {
// setLoading(false);
// }
// };

loadPosts();
}, []);
// loadPosts();
// }, []);

if (loading) return <div>데이터를 불러오는 중...</div>;
if (error) return <div>{error}</div>;
if (isLoading) return <div>데이터를 불러오는 중...</div>;
if (error as boolean) return <div>데이터를 불러오는 중 오류가 발생했습니다.</div>;

return (
<QuestionBoxContainer>
{posts.map((post) => (
{Array.isArray(posts) && posts.map((post) => (
<QuestionItem key={post.id}>
<QuestionHeader solved={post.solved} title={post.title} />
<QuestionBody content={post.content} />
Expand Down
6 changes: 3 additions & 3 deletions src/components/main-page/SearchInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ const SearchInputStyle = styled.div`
margin: 0 auto;
display: flex;
justify-content: space-between;
margin-bottom: 20px;
padding: 8px 20px;
margin-bottom: 18px;
padding: 8px 15px;
border: 1px solid #727272;
border-radius: 30px;
width: 70%;
width: 80%;

input {
width: 95%;
Expand Down
54 changes: 54 additions & 0 deletions src/components/main-page/TagList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { mainTags } from '@/types/main.model';
import styled from 'styled-components';

interface TagsProps {
tags?: mainTags[] | null;
selectedTags: number[];
onTagToggle: (tagId: number) => void;
}

const TagList = ({ tags, selectedTags, onTagToggle }: TagsProps) => {
console.log(selectedTags);
return (
<TagListContainer>
{tags?.map((tag) => (
<TagButton
key={tag.id}
onClick={() => onTagToggle(tag.id as number)}
selected={selectedTags.includes(tag.id as number)}
>
{tag.name}
</TagButton>
))}
</TagListContainer>
);
};

const TagListContainer = styled.div`
display: flex;
position: relative;
flex-wrap: wrap;
justify-content: center;
align-items: center;
gap: 5px;

}
`;

interface TagButtonProps {
selected: boolean;
}

const TagButton = styled.button<TagButtonProps>`
display: block;
border-radius: 30px;
font-size: 1rem;
background-color: ${({ selected }) => (selected ? 'rgba(49, 191, 63, 0.23)' : 'transparent')};
color: #32c040;
border: 1px solid #32c040;
padding: 8px 15px;
text-decoration: none;
cursor: pointer;
transition: all 0.12s ease-in-out;
`;
export default TagList;
48 changes: 0 additions & 48 deletions src/hooks/useMainTags.ts

This file was deleted.

Loading