Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
8 changes: 8 additions & 0 deletions public/robots.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
User-agent: *
Allow: /

# Sitemap
Sitemap: https://www.devpals.site

# Crawl-delay (선택사항)
Crawl-delay: 1
21 changes: 21 additions & 0 deletions public/sitemap.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://www.devpals.site/</loc>
<lastmod>2024-01-01</lastmod>
<changefreq>daily</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://www.devpals.site/main</loc>
<lastmod>2024-01-01</lastmod>
<changefreq>daily</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://www.devpals.site</loc>
<lastmod>2024-01-01</lastmod>
<changefreq>weekly</changefreq>
<priority>0.7</priority>
</url>
</urlset>
5 changes: 3 additions & 2 deletions src/components/common/avatar/Avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ import defaultImg from '../../../assets/defaultImg.png';
export interface AvatarProps {
size: string;
image: string | ReactNode;
alt?: string;
}

function Avatar({ size, image }: AvatarProps) {
function Avatar({ size, image, alt = '사용자 프로필 이미지' }: AvatarProps) {
const releasedImg =
typeof image === 'string' && image.trim() ? image : defaultImg;
return (
<S.AvatarContainer size={size}>
{typeof image === 'string' || !image ? (
<S.AvatarImg src={releasedImg} alt='Avatar' />
<S.AvatarImg src={releasedImg} alt={alt} />
) : (
image
)}
Expand Down
26 changes: 26 additions & 0 deletions src/hooks/useIsMobile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { useState, useEffect } from 'react';

const useIsMobile = () => {
const [isMobile, setIsMobile] = useState(false);

useEffect(() => {
const checkIsMobile = () => {
setIsMobile(window.innerWidth <= 768);
};

// 초기 체크
checkIsMobile();

// 리사이즈 이벤트 리스너 추가
window.addEventListener('resize', checkIsMobile);

// 클린업 함수
return () => {
window.removeEventListener('resize', checkIsMobile);
};
}, []);

return isMobile;
};

export default useIsMobile;
2 changes: 1 addition & 1 deletion src/hooks/user/CommentHooks/usePostComment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const usePostComment = (id: number) => {
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: [ProjectCommentList.projectComment, id],
exact: true,
exact: false,
});
},
onError: (error) => {
Expand Down
9 changes: 9 additions & 0 deletions src/pages/user/apply/Apply.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import LoadingSpinner from '../../../components/common/loadingSpinner/LoadingSpi
import PhoneComponent from '../../../components/user/applyComponents/phoneComponent/PhoneComponent';
import CareersComponent from '../../../components/user/applyComponents/careersComponent/CareersComponent';
import Input from '../../../components/user/projectFormComponents/inputComponent/InputComponent';
import ApplyStep from './ApplyStep';
import useIsMobile from '../../../hooks/useIsMobile';

const Apply = () => {
const { projectId } = useParams();
Expand All @@ -23,6 +25,7 @@ const Apply = () => {
const { data: projectData, isLoading, isFetching } = useGetProjectData(id);
const { applyProject } = useApplyProject({ id, handleModalOpen });
const userEmail = useAuthStore((state) => state.userData?.email);
const isMobile = useIsMobile();

const {
handleSubmit: onSubmitHandler,
Expand Down Expand Up @@ -65,6 +68,12 @@ const Apply = () => {
if (isLoading) return <LoadingSpinner />;
if (isFetching) return <LoadingSpinner />;

// 모바일 환경이면 ApplyStep 컴포넌트 렌더링
if (isMobile) {
return <ApplyStep />;
}

// 데스크톱 환경이면 기존 Apply 컴포넌트 렌더링
return (
<S.Container>
<S.Title>프로젝트 지원</S.Title>
Expand Down
40 changes: 36 additions & 4 deletions src/pages/user/projectDetail/ProjectDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,29 @@ const ProjectDetail = () => {
}
}, [data, handleModalOpen, isLoading, isFetching]);

// 간단한 메타 정보 설정
useEffect(() => {
if (data) {
document.title = `${data.title} - 프로젝트 상세`;

// 메타 설명 추가
const metaDescription = document.querySelector(
'meta[name="description"]'
);
if (metaDescription) {
metaDescription.setAttribute(
'content',
`${data.title} 프로젝트에 대한 상세 정보입니다.`
);
} else {
const newMetaDescription = document.createElement('meta');
newMetaDescription.name = 'description';
newMetaDescription.content = `${data.title} 프로젝트에 대한 상세 정보입니다.`;
document.head.appendChild(newMetaDescription);
}
}
}, [data]);

if (isLoading || isFetching) return <LoadingSpinner />;

if (!data) {
Expand Down Expand Up @@ -63,27 +86,33 @@ const ProjectDetail = () => {
<S.Title>{data.title}</S.Title>
<S.ProfileContainer>
<S.ProfileImageContainer onClick={handleMovetoUserPage}>
<Avatar size='2.5rem' image={data.user.img} />
<Avatar
size='2.5rem'
image={data.user.img}
alt={`${data.user.nickname}의 프로필 이미지`}
/>
</S.ProfileImageContainer>
<S.UserInfo>
<S.UserName onClick={handleMovetoUserPage}>
{data.user.nickname}
</S.UserName>
<S.PostDate>{formatDate(data.recruitmentEndDate)}</S.PostDate>
<S.ViewCount>
<EyeIcon />
<EyeIcon aria-label='조회수' />
{data.views}
</S.ViewCount>
</S.UserInfo>
</S.ProfileContainer>
</S.Header>

<S.Content>
<ProjectInformation data={data} />
<br></br>
<br />
<S.ProjectDescription>
<MarkdownEditorView description={data.description} />
</S.ProjectDescription>
</S.Content>

<S.ApplyButtonContainer>
{userData &&
userData.id !== data.user.id &&
Expand All @@ -99,14 +128,17 @@ const ProjectDetail = () => {
</Button>
) : null}
</S.ApplyButtonContainer>
<hr></hr>

<hr />

<CommentLayout
projectId={data.id}
createrId={data.user.id}
loginUserId={userData?.id}
/>
</S.Wrapper>
</S.Container>

<Modal
isOpen={isOpen}
onClose={handleModalClose}
Expand Down
2 changes: 1 addition & 1 deletion src/routes/AppRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const Inquiry = lazy(
);
const MyPage = lazy(() => import('../pages/user/mypage/MyPage'));
const UserPage = lazy(() => import('../pages/user/userpage/UserPage'));
const Apply = lazy(() => import('../pages/user/apply/ApplyStep'));
const Apply = lazy(() => import('../pages/user/apply/Apply'));
const CreateProject = lazy(
() => import('../pages/user/createProject/CreateProject')
);
Expand Down