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')
);