diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 00000000..1cb1c273 --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,8 @@ +User-agent: * +Allow: / + +# Sitemap +Sitemap: https://www.devpals.site/sitemap.xml + +# Crawl-delay (선택사항) +Crawl-delay: 1 \ No newline at end of file diff --git a/public/sitemap.xml b/public/sitemap.xml new file mode 100644 index 00000000..3cb11ee5 --- /dev/null +++ b/public/sitemap.xml @@ -0,0 +1,21 @@ + + + + https://www.devpals.site/ + 2024-01-01 + daily + 1.0 + + + https://www.devpals.site/main + 2024-01-01 + daily + 0.9 + + + https://www.devpals.site + 2024-01-01 + weekly + 0.7 + + \ No newline at end of file diff --git a/src/components/common/avatar/Avatar.tsx b/src/components/common/avatar/Avatar.tsx index 61accdcc..6b7e8e45 100644 --- a/src/components/common/avatar/Avatar.tsx +++ b/src/components/common/avatar/Avatar.tsx @@ -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 ( {typeof image === 'string' || !image ? ( - + ) : ( image )} diff --git a/src/hooks/useIsMobile.ts b/src/hooks/useIsMobile.ts new file mode 100644 index 00000000..38f40e56 --- /dev/null +++ b/src/hooks/useIsMobile.ts @@ -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; diff --git a/src/hooks/user/CommentHooks/usePostComment.ts b/src/hooks/user/CommentHooks/usePostComment.ts index 5113c039..fffbf6a0 100644 --- a/src/hooks/user/CommentHooks/usePostComment.ts +++ b/src/hooks/user/CommentHooks/usePostComment.ts @@ -10,7 +10,7 @@ const usePostComment = (id: number) => { onSuccess: () => { queryClient.invalidateQueries({ queryKey: [ProjectCommentList.projectComment, id], - exact: true, + exact: false, }); }, onError: (error) => { diff --git a/src/pages/user/apply/Apply.tsx b/src/pages/user/apply/Apply.tsx index 043074c4..98db5326 100644 --- a/src/pages/user/apply/Apply.tsx +++ b/src/pages/user/apply/Apply.tsx @@ -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(); @@ -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, @@ -65,6 +68,12 @@ const Apply = () => { if (isLoading) return ; if (isFetching) return ; + // 모바일 환경이면 ApplyStep 컴포넌트 렌더링 + if (isMobile) { + return ; + } + + // 데스크톱 환경이면 기존 Apply 컴포넌트 렌더링 return ( 프로젝트 지원 diff --git a/src/pages/user/projectDetail/ProjectDetail.tsx b/src/pages/user/projectDetail/ProjectDetail.tsx index d395f152..3e13bc4b 100644 --- a/src/pages/user/projectDetail/ProjectDetail.tsx +++ b/src/pages/user/projectDetail/ProjectDetail.tsx @@ -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 ; if (!data) { @@ -63,7 +86,11 @@ const ProjectDetail = () => { {data.title} - + @@ -71,19 +98,21 @@ const ProjectDetail = () => { {formatDate(data.recruitmentEndDate)} - + {data.views} + -

+
+ {userData && userData.id !== data.user.id && @@ -99,7 +128,9 @@ const ProjectDetail = () => { ) : null} -
+ +
+ { />
+ 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') );