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
2 changes: 1 addition & 1 deletion src/apis/http.api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import axios, { AxiosInstance, AxiosRequestConfig, AxiosHeaders } from 'axios';
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
import { getToken, removeToken } from '@/utils/token'; // 토큰 유틸리티 함수 import
import { logout } from '@/store/slices/authSlice';
import { store } from '@/store/store';
Expand Down
13 changes: 13 additions & 0 deletions src/apis/mainpost.api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import httpClient from '@/apis/http.api';

export const fetchPosts = async () => {
try {
console.log('Requesting posts...');
const response = await httpClient.get('/api/main');
console.log('Response data:', response.data);
return response.data;
} catch (error) {
console.error('Error fetching posts:', error);
throw error;
}
};
34 changes: 34 additions & 0 deletions src/components/QuesitonTag.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import styled from 'styled-components';

// Styled Components
const TagsContainer = styled.div`
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 12px;
`;

const TagItem = styled.div`
background-color: #deffe2;
color: #858585;
font-family: 'Pretendard-ExtraLight', Helvetica;
font-size: 8px;
padding: 4px 8px;
border-radius: 12px;
`;

interface TagsProps {
tags: string[];
}

function QuestionTag({ tags }: TagsProps) {
return (
<TagsContainer>
{tags.map((tag, index) => (
<TagItem key={index}>{tag}</TagItem>
))}
</TagsContainer>
);
}

export default QuestionTag;
19 changes: 19 additions & 0 deletions src/components/QuestionBody.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import styled from 'styled-components';

const BodyContainer = styled.div`
font-family: 'Pretendard-ExtraLight', Helvetica;
font-size: 10px;
line-height: 1.5;
color: #333;
margin-top: 8px;
`;

interface QuestionBodyProps {
content: string;
}

function QuestionBody({ content }: QuestionBodyProps) {
return <BodyContainer>{content}</BodyContainer>;
}

export default QuestionBody;
35 changes: 35 additions & 0 deletions src/components/QuestionBottom.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import styled from 'styled-components';
import QuestionUser from './QuestionUser';
import QuestionUtil from './QuestionUtil';

const BottomContainer = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 12px;
`;

interface QuestionBottomProps {
nickname: string;
time: string;
likes: number;
comments: number;
views: number;
}

function QuestionBottom({
nickname,
time,
likes,
comments,
views,
}: QuestionBottomProps) {
return (
<BottomContainer>
<QuestionUser nickname={nickname} time={time} />
<QuestionUtil likes={likes} comments={comments} views={views} />
</BottomContainer>
);
}

export default QuestionBottom;
63 changes: 63 additions & 0 deletions src/components/QuestionBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { useEffect, useState } from 'react';
import styled from 'styled-components';
import QuestionBody from './QuestionBody';
import QuestionHeader from './QuestionHeader';
import QuestionTag from './QuesitonTag';
import QuestionBottom from './QuestionBottom';
import { fetchPosts } from '@/apis/mainpost.api';
import { PostData } from '@/types/postdata';

const QuestionBoxContainer = styled.div`
display: flex;
flex-direction: column;
gap: 20px;
`;

const QuestionItem = styled.div`
margin: 10px;
`;

function QuestionBox() {
const [posts, setPosts] = useState<PostData[]>([]);
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);

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

loadPosts();
}, []);

if (loading) return <div>데이터를 불러오는 중...</div>;
if (error) return <div>{error}</div>;

return (
<QuestionBoxContainer>
{posts.map((post) => (
<QuestionItem key={post.id}>
<QuestionHeader solved={post.solved} title={post.title} />
<QuestionBody content={post.content} />
{post.tags && <QuestionTag tags={post.tags.split(',')} />}
<QuestionBottom
nickname={post.nickname}
time={post.created_at}
likes={post.like_count}
comments={post.comment_count}
views={post.view}
/>
</QuestionItem>
))}
</QuestionBoxContainer>
);
}

export default QuestionBox;
99 changes: 99 additions & 0 deletions src/components/QuestionButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import styled from 'styled-components';

const ProblemBox = styled.div`
height: 20px;
width: 77px;

.group {
height: 20px;
left: 0;
position: relative; /* fixed → relative로 수정 */
top: 0;
}

.overlap-group {
background-color: #d9d9d9;
border-radius: 30px;
height: 20px;
position: relative;
width: 77px;
}

.text-wrapper {
color: #ffffff;
font-family: 'Pretendard-ExtraBold', Helvetica;
font-size: 10px;
height: 13px;
left: 13px;
line-height: 12px;
position: absolute;
text-align: center;
top: 3px;
white-space: nowrap;
width: 50px;
}
`;

const SolveBox = styled.div`
height: 20px;
width: 77px;

.group {
height: 20px;
left: 0;
position: relative; /* fixed → relative로 수정 */
top: 0;
}

.overlap-group {
background-color: #c9ffce;
border-radius: 30px;
height: 20px;
position: relative;
width: 77px;
}

.text-wrapper {
color: #007c0c;
font-family: 'Pretendard-ExtraBold', Helvetica;
font-size: 10px;
height: 13px;
left: 13px;
line-height: 12px;
position: absolute;
text-align: center;
top: 4px;
white-space: nowrap;
width: 50px;
}
`;

export const ProblemButton = () => {
return (
<ProblemBox className='box'>
<div className='group'>
<div className='overlap-group'>
<div className='text-wrapper'>problem</div>
</div>
</div>
</ProblemBox>
);
};

export const SolveButton = () => {
return (
<SolveBox className='box'>
<div className='group'>
<div className='overlap-group'>
<div className='text-wrapper'>solve</div>
</div>
</div>
</SolveBox>
);
};

const QuestionButton = ({ solved }: { solved: number }) => {
return solved === 1 ? <SolveButton /> : <ProblemButton />;
};

export default QuestionButton;
25 changes: 25 additions & 0 deletions src/components/QuestionHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import styled from 'styled-components';
import QuestionButton from './QuestionButton';
import QuestionTitle from './QuestionTitle';

const HeaderContainer = styled.div`
display: flex;
align-items: center;
gap: 8px;
`;

interface QuestionHeaderProps {
solved: number;
title: string;
}

function QuestionHeader({ solved, title }: QuestionHeaderProps) {
return (
<HeaderContainer>
<QuestionButton solved={solved} />
<QuestionTitle text={title} />
</HeaderContainer>
);
}

export default QuestionHeader;
18 changes: 18 additions & 0 deletions src/components/QuestionTitle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import styled from 'styled-components';

const TitleContainer = styled.div`
font-family: 'Pretendard-SemiBold', Helvetica;
font-size: 10px;
color: #000;
margin-left: 8px;
`;

interface TitleProps {
text: string;
}

function QuestionTitle({ text }: TitleProps) {
return <TitleContainer>{text}</TitleContainer>;
}

export default QuestionTitle;
25 changes: 25 additions & 0 deletions src/components/QuestionUser.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import styled from 'styled-components';

const UserContainer = styled.div`
font-family: 'Pretendard-ExtraLight', Helvetica;
font-size: 10px;
color: #666;
display: flex;
gap: 8px;
`;

interface QuestionUserProps {
nickname: string;
time: string;
}

function QuestionUser({ nickname, time }: QuestionUserProps) {
return (
<UserContainer>
<span>{nickname}</span>
<span>{time}</span>
</UserContainer>
);
}

export default QuestionUser;
Loading