Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 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
12 changes: 12 additions & 0 deletions next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@ const nextConfig: NextConfig = {
// Docker 배포를 위한 standalone 모드 활성화
// 해당 설정은 프로덕션 빌드 시 필요한 파일만 .next/standalone 폴더에 복사됨.
output: 'standalone',

// 외부 이미지 도메인 허용
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'sprint-fe-project.s3.ap-northeast-2.amazonaws.com',
port: '',
pathname: '/globalnomad/**',
},
],
},
};

export default nextConfig;
18 changes: 18 additions & 0 deletions public/assets/svg/my-activities-dashboard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';

const MyActivitiesDashboardIcon = ({ size = 24, ...props }) => (
<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
fill='none'
viewBox='0 0 24 24'
>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

접근성: <title> 또는 aria-label 추가 필요
정적 분석 도구가 지적한 대로 스크린리더가 아이콘 의미를 알 수 있도록 <title> 요소를 추가하거나 role="img" aria-label="대시보드 아이콘" 속성을 부여하세요.

   <svg
     xmlns='http://www.w3.org/2000/svg'
     width={size}
     height={size}
     fill='none'
     viewBox='0 0 24 24'
+    role='img'
+    aria-label='대시보드 아이콘'
   >
+    <title>대시보드</title>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
fill='none'
viewBox='0 0 24 24'
>
<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
fill='none'
viewBox='0 0 24 24'
role='img'
aria-label='대시보드 아이콘'
>
<title>대시보드</title>
🧰 Tools
🪛 Biome (2.1.2)

[error] 4-10: Alternative text title element cannot be empty

For accessibility purposes, SVGs should have an alternative text, provided via title element. If the svg element has role="img", you should add the aria-label or aria-labelledby attribute.

(lint/a11y/noSvgWithoutTitle)

🤖 Prompt for AI Agents
In public/assets/svg/my-activities-dashboard.tsx around lines 4 to 10, the SVG
element lacks accessibility features for screen readers. Add a <title> element
inside the SVG with a descriptive text or add role="img" and aria-label="대시보드
아이콘" attributes to the SVG tag to provide meaningful context for screen readers.

<path
fill='#000'
d='M19 3h-1V1h-2v2H8V1H6v2H5c-1.1 0-2 .9-2 2v14a2 2 0 0 0 2 2h14c1.11 0 2-.89 2-2V5a2 2 0 0 0-2-2m0 16H5V9h14zM5 7V5h14v2zm5.56 10.46 5.94-5.93-1.07-1.06-4.87 4.87-2.11-2.11-1.06 1.06z'
/>
</svg>
);

export default MyActivitiesDashboardIcon;
18 changes: 18 additions & 0 deletions public/assets/svg/my-activities.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';

const MyActivitiesIcon = ({ size = 24, ...props }) => (
<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
fill='none'
viewBox='0 0 24 24'
>
<path
fill='#000'
d='M12 8a4 4 0 1 1 0 8 4 4 0 0 1 0-8m0 2a2 2 0 1 0 0 4 2 2 0 0 0 0-4m-2 12c-.25 0-.46-.18-.5-.42l-.37-2.65c-.63-.25-1.17-.59-1.69-.99l-2.49 1.01c-.22.08-.49 0-.61-.22l-2-3.46a.493.493 0 0 1 .12-.64l2.11-1.66L4.5 12l.07-1-2.11-1.63a.493.493 0 0 1-.12-.64l2-3.46c.12-.22.39-.31.61-.22l2.49 1c.52-.39 1.06-.73 1.69-.98l.37-2.65c.04-.24.25-.42.5-.42h4c.25 0 .46.18.5.42l.37 2.65c.63.25 1.17.59 1.69.98l2.49-1c.22-.09.49 0 .61.22l2 3.46c.13.22.07.49-.12.64L19.43 11l.07 1-.07 1 2.11 1.63c.19.15.25.42.12.64l-2 3.46c-.12.22-.39.31-.61.22l-2.49-1c-.52.39-1.06.73-1.69.98l-.37 2.65c-.04.24-.25.42-.5.42zm1.25-18-.37 2.61c-1.2.25-2.26.89-3.03 1.78L5.44 7.35l-.75 1.3L6.8 10.2a5.55 5.55 0 0 0 0 3.6l-2.12 1.56.75 1.3 2.43-1.04c.77.88 1.82 1.52 3.01 1.76l.37 2.62h1.52l.37-2.61c1.19-.25 2.24-.89 3.01-1.77l2.43 1.04.75-1.3-2.12-1.55c.4-1.17.4-2.44 0-3.61l2.11-1.55-.75-1.3-2.41 1.04a5.42 5.42 0 0 0-3.03-1.77L12.75 4z'
/>
</svg>
);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

접근성을 위한 aria-label 또는 title 요소를 추가하세요.

SVG 아이콘에 접근성을 위한 대체 텍스트가 누락되어 있습니다. 스크린 리더 사용자를 위해 적절한 설명을 추가해주세요.

const MyActivitiesIcon = ({ size = 24, ...props }) => (
  <svg
    xmlns='http://www.w3.org/2000/svg'
    width={size}
    height={size}
    fill='none'
    viewBox='0 0 24 24'
+   aria-label="내 활동"
+   role="img"
  >
    <path
      fill='#000'
      d='M12 8a4 4 0 1 1 0 8 4 4 0 0 1 0-8m0 2a2 2 0 1 0 0 4 2 2 0 0 0 0-4m-2 12c-.25 0-.46-.18-.5-.42l-.37-2.65c-.63-.25-1.17-.59-1.69-.99l-2.49 1.01c-.22.08-.49 0-.61-.22l-2-3.46a.493.493 0 0 1 .12-.64l2.11-1.66L4.5 12l.07-1-2.11-1.63a.493.493 0 0 1-.12-.64l2-3.46c.12-.22.39-.31.61-.22l2.49 1c.52-.39 1.06-.73 1.69-.98l.37-2.65c.04-.24.25-.42.5-.42h4c.25 0 .46.18.5.42l.37 2.65c.63.25 1.17.59 1.69.98l2.49-1c.22-.09.49 0 .61.22l2 3.46c.13.22.07.49-.12.64L19.43 11l.07 1-.07 1 2.11 1.63c.19.15.25.42.12.64l-2 3.46c-.12.22-.39.31-.61.22l-2.49-1c-.52.39-1.06.73-1.69.98l-.37 2.65c-.04.24-.25.42-.5.42zm1.25-18-.37 2.61c-1.2.25-2.26.89-3.03 1.78L5.44 7.35l-.75 1.3L6.8 10.2a5.55 5.55 0 0 0 0 3.6l-2.12 1.56.75 1.3 2.43-1.04c.77.88 1.82 1.52 3.01 1.76l.37 2.62h1.52l.37-2.61c1.19-.25 2.24-.89 3.01-1.77l2.43 1.04.75-1.3-2.12-1.55c.4-1.17.4-2.44 0-3.61l2.11-1.55-.75-1.3-2.41 1.04a5.42 5.42 0 0 0-3.03-1.77L12.75 4z'
    />
  </svg>
);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const MyActivitiesIcon = ({ size = 24, ...props }) => (
<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
fill='none'
viewBox='0 0 24 24'
>
<path
fill='#000'
d='M12 8a4 4 0 1 1 0 8 4 4 0 0 1 0-8m0 2a2 2 0 1 0 0 4 2 2 0 0 0 0-4m-2 12c-.25 0-.46-.18-.5-.42l-.37-2.65c-.63-.25-1.17-.59-1.69-.99l-2.49 1.01c-.22.08-.49 0-.61-.22l-2-3.46a.493.493 0 0 1 .12-.64l2.11-1.66L4.5 12l.07-1-2.11-1.63a.493.493 0 0 1-.12-.64l2-3.46c.12-.22.39-.31.61-.22l2.49 1c.52-.39 1.06-.73 1.69-.98l.37-2.65c.04-.24.25-.42.5-.42h4c.25 0 .46.18.5.42l.37 2.65c.63.25 1.17.59 1.69.98l2.49-1c.22-.09.49 0 .61.22l2 3.46c.13.22.07.49-.12.64L19.43 11l.07 1-.07 1 2.11 1.63c.19.15.25.42.12.64l-2 3.46c-.12.22-.39.31-.61.22l-2.49-1c-.52.39-1.06.73-1.69.98l-.37 2.65c-.04.24-.25.42-.5.42zm1.25-18-.37 2.61c-1.2.25-2.26.89-3.03 1.78L5.44 7.35l-.75 1.3L6.8 10.2a5.55 5.55 0 0 0 0 3.6l-2.12 1.56.75 1.3 2.43-1.04c.77.88 1.82 1.52 3.01 1.76l.37 2.62h1.52l.37-2.61c1.19-.25 2.24-.89 3.01-1.77l2.43 1.04.75-1.3-2.12-1.55c.4-1.17.4-2.44 0-3.61l2.11-1.55-.75-1.3-2.41 1.04a5.42 5.42 0 0 0-3.03-1.77L12.75 4z'
/>
</svg>
);
const MyActivitiesIcon = ({ size = 24, ...props }) => (
<svg
xmlns="http://www.w3.org/2000/svg"
width={size}
height={size}
fill="none"
viewBox="0 0 24 24"
aria-label="내 활동"
role="img"
>
<path
fill="#000"
d="M12 8a4 4 0 1 1 0 8 4 4 0 0 1 0-8m0 2a2 2 0 1 0 0 4 2 2 0 0 0 0-4m-2 12c-.25 0-.46-.18-.5-.42l-.37-2.65c-.63-.25-1.17-.59-1.69-.99l-2.49 1.01c-.22.08-.49 0-.61-.22l-2-3.46a.493.493 0 0 1 .12-.64l2.11-1.66L4.5 12l.07-1-2.11-1.63a.493.493 0 0 1-.12-.64l2-3.46c.12-.22.39-.31.61-.22l2.49 1c.52-.39 1.06-.73 1.69-.98l.37-2.65c.04-.24.25-.42.5-.42h4c.25 0 .46.18.5.42l.37 2.65c.63.25 1.17.59 1.69.98l2.49-1c.22-.09.49 0 .61.22l2 3.46c.13.22.07.49-.12.64L19.43 11l.07 1-.07 1 2.11 1.63c.19.15.25.42.12.64l-2 3.46c-.12.22-.39.31-.61.22l-2.49-1c-.52.39-1.06.73-1.69.98l-.37 2.65c-.04.24-.25.42-.5.42zm1.25-18-.37 2.61c-1.2.25-2.26.89-3.03 1.78L5.44 7.35l-.75 1.3L6.8 10.2a5.55 5.55 0 0 0 0 3.6l-2.12 1.56.75 1.3 2.43-1.04c.77.88 1.82 1.52 3.01 1.76l.37 2.62h1.52l.37-2.61c1.19-.25 2.24-.89 3.01-1.77l2.43 1.04.75-1.3-2.12-1.55c.4-1.17.4-2.44 0-3.61l2.11-1.55-.75-1.3-2.41 1.04a5.42 5.42 0 0 0-3.03-1.77L12.75 4z"
/>
</svg>
);
🧰 Tools
🪛 Biome (2.1.2)

[error] 4-10: Alternative text title element cannot be empty

For accessibility purposes, SVGs should have an alternative text, provided via title element. If the svg element has role="img", you should add the aria-label or aria-labelledby attribute.

(lint/a11y/noSvgWithoutTitle)

🤖 Prompt for AI Agents
In public/assets/svg/my-activities.tsx around lines 3 to 16, the SVG icon lacks
accessibility features such as an aria-label or title element. To fix this, add
a descriptive title element inside the SVG tag or include an aria-label
attribute on the SVG element to provide alternative text for screen readers,
ensuring the icon is accessible.


export default MyActivitiesIcon;
18 changes: 18 additions & 0 deletions public/assets/svg/my-reservation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';

const MyReservationIcon = ({ size = 24, ...props }) => (
<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
fill='none'
viewBox='0 0 24 24'
>
<path
fill='#000'
d='m17 21-2.75-3 1.16-1.16L17 18.43l3.59-3.59 1.16 1.41M12.8 21H5c-1.11 0-2-.89-2-2V5c0-1.11.89-2 2-2h14c1.11 0 2 .89 2 2v7.8c-.61-.35-1.28-.6-2-.72V5H5v14h7.08c.12.72.37 1.39.72 2m-.8-4H7v-2h5m2.68-2H7v-2h10v1.08c-.85.14-1.63.46-2.32.92M17 9H7V7h10'
/>
</svg>
);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

접근성을 위한 aria-label 또는 title 요소를 추가하세요.

MyActivitiesIcon과 동일하게 SVG 아이콘에 접근성을 위한 대체 텍스트가 누락되어 있습니다. 스크린 리더 사용자를 위해 적절한 설명을 추가해주세요.

const MyReservationIcon = ({ size = 24, ...props }) => (
  <svg
    xmlns='http://www.w3.org/2000/svg'
    width={size}
    height={size}
    fill='none'
    viewBox='0 0 24 24'
+   aria-label="내 예약"  
+   role="img"
  >
    <path
      fill='#000'
      d='m17 21-2.75-3 1.16-1.16L17 18.43l3.59-3.59 1.16 1.41M12.8 21H5c-1.11 0-2-.89-2-2V5c0-1.11.89-2 2-2h14c1.11 0 2 .89 2 2v7.8c-.61-.35-1.28-.6-2-.72V5H5v14h7.08c.12.72.37 1.39.72 2m-.8-4H7v-2h5m2.68-2H7v-2h10v1.08c-.85.14-1.63.46-2.32.92M17 9H7V7h10'
    />
  </svg>
);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const MyReservationIcon = ({ size = 24, ...props }) => (
<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
fill='none'
viewBox='0 0 24 24'
>
<path
fill='#000'
d='m17 21-2.75-3 1.16-1.16L17 18.43l3.59-3.59 1.16 1.41M12.8 21H5c-1.11 0-2-.89-2-2V5c0-1.11.89-2 2-2h14c1.11 0 2 .89 2 2v7.8c-.61-.35-1.28-.6-2-.72V5H5v14h7.08c.12.72.37 1.39.72 2m-.8-4H7v-2h5m2.68-2H7v-2h10v1.08c-.85.14-1.63.46-2.32.92M17 9H7V7h10'
/>
</svg>
);
const MyReservationIcon = ({ size = 24, ...props }) => (
<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
fill='none'
viewBox='0 0 24 24'
aria-label="내 예약"
role="img"
>
<path
fill='#000'
d='m17 21-2.75-3 1.16-1.16L17 18.43l3.59-3.59 1.16 1.41M12.8 21H5c-1.11 0-2-.89-2-2V5c0-1.11.89-2 2-2h14c1.11 0 2 .89 2 2v7.8c-.61-.35-1.28-.6-2-.72V5H5v14h7.08c.12.72.37 1.39.72 2m-.8-4H7v-2h5m2.68-2H7v-2h10v1.08c-.85.14-1.63.46-2.32.92M17 9H7V7h10'
/>
</svg>
);
🧰 Tools
🪛 Biome (2.1.2)

[error] 4-10: Alternative text title element cannot be empty

For accessibility purposes, SVGs should have an alternative text, provided via title element. If the svg element has role="img", you should add the aria-label or aria-labelledby attribute.

(lint/a11y/noSvgWithoutTitle)

🤖 Prompt for AI Agents
In public/assets/svg/my-reservation.tsx around lines 3 to 16, the SVG icon lacks
accessibility features such as an aria-label or title element. To fix this, add
a descriptive title element inside the SVG tag or include an aria-label
attribute with appropriate text to provide alternative text for screen readers,
similar to the approach used in MyActivitiesIcon.


export default MyReservationIcon;
18 changes: 18 additions & 0 deletions public/assets/svg/my-user.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';

const MyUsersIcon = ({ size = 24, ...props }) => (
<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
fill='none'
viewBox='0 0 24 24'
>
<path
fill='#000'
d='m21.1 12.5 1.4 1.41-6.53 6.59L12.5 17l1.4-1.41 2.07 2.08zM11 4a4 4 0 1 1 0 8 4 4 0 0 1 0-8m0 2a2 2 0 1 0 0 4 2 2 0 0 0 0-4m0 7c.68 0 1.5.09 2.41.26l-1.67 1.67-.74-.03c-2.97 0-6.1 1.46-6.1 2.1v1.1h6.2L13 20H3v-3c0-2.66 5.33-4 8-4'
/>
</svg>
);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

접근성 문제와 TypeScript 타입 정의를 개선해야 합니다.

정적 분석 도구에서 지적한 접근성 문제와 TypeScript 타입 정의가 누락된 문제를 해결해야 합니다.

접근성과 타입 안정성을 위한 수정사항:

+interface MyUsersIconProps {
+  size?: number;
+  className?: string;
+  'aria-label'?: string;
+  title?: string;
+}
+
-const MyUsersIcon = ({ size = 24, ...props }) => (
+const MyUsersIcon: React.FC<MyUsersIconProps> = ({ 
+  size = 24, 
+  'aria-label': ariaLabel = '사용자 아이콘',
+  title = '사용자 아이콘',
+  ...props 
+}) => (
   <svg
     xmlns='http://www.w3.org/2000/svg'
     width={size}
     height={size}
     fill='none'
     viewBox='0 0 24 24'
+    aria-label={ariaLabel}
+    {...props}
   >
+    <title>{title}</title>
     <path
       fill='#000'
       d='m21.1 12.5 1.4 1.41-6.53 6.59L12.5 17l1.4-1.41 2.07 2.08zM11 4a4 4 0 1 1 0 8 4 4 0 0 1 0-8m0 2a2 2 0 1 0 0 4 2 2 0 0 0 0-4m0 7c.68 0 1.5.09 2.41.26l-1.67 1.67-.74-.03c-2.97 0-6.1 1.46-6.1 2.1v1.1h6.2L13 20H3v-3c0-2.66 5.33-4 8-4'
     />
   </svg>
 );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const MyUsersIcon = ({ size = 24, ...props }) => (
<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
fill='none'
viewBox='0 0 24 24'
>
<path
fill='#000'
d='m21.1 12.5 1.4 1.41-6.53 6.59L12.5 17l1.4-1.41 2.07 2.08zM11 4a4 4 0 1 1 0 8 4 4 0 0 1 0-8m0 2a2 2 0 1 0 0 4 2 2 0 0 0 0-4m0 7c.68 0 1.5.09 2.41.26l-1.67 1.67-.74-.03c-2.97 0-6.1 1.46-6.1 2.1v1.1h6.2L13 20H3v-3c0-2.66 5.33-4 8-4'
/>
</svg>
);
interface MyUsersIconProps {
size?: number;
className?: string;
'aria-label'?: string;
title?: string;
}
const MyUsersIcon: React.FC<MyUsersIconProps> = ({
size = 24,
'aria-label': ariaLabel = '사용자 아이콘',
title = '사용자 아이콘',
...props
}) => (
<svg
xmlns="http://www.w3.org/2000/svg"
width={size}
height={size}
fill="none"
viewBox="0 0 24 24"
aria-label={ariaLabel}
{...props}
>
<title>{title}</title>
<path
fill="#000"
d="m21.1 12.5 1.4 1.41-6.53 6.59L12.5 17l1.4-1.41 2.07 2.08zM11 4a4 4 0 1 1 0 8 4 4 0 0 1 0-8m0 2a2 2 0 1 0 0 4 2 2 0 0 0 0-4m0 7c.68 0 1.5.09 2.41.26l-1.67 1.67-.74-.03c-2.97 0-6.1 1.46-6.1 2.1v1.1h6.2L13 20H3v-3c0-2.66 5.33-4 8-4"
/>
</svg>
);
🧰 Tools
🪛 Biome (2.1.2)

[error] 4-10: Alternative text title element cannot be empty

For accessibility purposes, SVGs should have an alternative text, provided via title element. If the svg element has role="img", you should add the aria-label or aria-labelledby attribute.

(lint/a11y/noSvgWithoutTitle)

🤖 Prompt for AI Agents
In public/assets/svg/my-user.tsx around lines 3 to 16, the component lacks
TypeScript type definitions and accessibility attributes. Add explicit
TypeScript types for the component props, including size and any other props.
Also, include appropriate accessibility attributes such as role="img" and
aria-label or title to the SVG element to improve screen reader support.


export default MyUsersIcon;
21 changes: 21 additions & 0 deletions public/assets/svg/pen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react';

const PenIcon = ({ size = 24, ...props }) => (
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Props 타입 선언 누락

파일 확장자가 .tsx인 만큼 TypeScript 타입을 명시하면 컴파일 단계에서 오타·누락을 예방할 수 있습니다.

-const PenIcon = ({ size = 24, ...props }) => (
+interface PenIconProps extends React.SVGProps<SVGSVGElement> {
+  size?: number;
+}
+
+const PenIcon: React.FC<PenIconProps> = ({ size = 24, ...props }) => (
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const PenIcon = ({ size = 24, ...props }) => (
interface PenIconProps extends React.SVGProps<SVGSVGElement> {
size?: number;
}
const PenIcon: React.FC<PenIconProps> = ({ size = 24, ...props }) => (
🤖 Prompt for AI Agents
In public/assets/svg/pen.tsx at line 3, the PenIcon component lacks explicit
TypeScript type declarations for its props. Define a proper interface or type
for the props, including the size property and any other props, and annotate the
PenIcon function parameter with this type to ensure type safety and prevent
typos or omissions during compilation.

<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
fill='none'
viewBox='0 0 25 24'
>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

접근성 태그 부족
앞선 아이콘과 동일하게 <title> 또는 aria-label을 포함해 접근성을 확보하세요.

🧰 Tools
🪛 Biome (2.1.2)

[error] 4-10: Alternative text title element cannot be empty

For accessibility purposes, SVGs should have an alternative text, provided via title element. If the svg element has role="img", you should add the aria-label or aria-labelledby attribute.

(lint/a11y/noSvgWithoutTitle)

🤖 Prompt for AI Agents
In public/assets/svg/pen.tsx around lines 4 to 10, the SVG element lacks
accessibility tags such as <title> or aria-label. To fix this, add a <title>
element inside the SVG with a descriptive name or include an aria-label
attribute on the SVG tag to improve screen reader support and ensure consistent
accessibility with other icons.

<path
stroke='#fff'
strokeLinecap='round'
strokeLinejoin='round'
strokeWidth='2.063'
d='M17.31 6.06 4.554 18.848l-.773 1.87 1.871-.772L18.44 7.19zm2.553-2.552-.553.552 1.13 1.13.552-.553a.774.774 0 0 0 0-1.094l-.035-.035a.774.774 0 0 0-1.094 0'
/>
</svg>
);

export default PenIcon;
18 changes: 18 additions & 0 deletions public/assets/svg/profile-default.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';

const ProfileDefaultIcon = ({ size = 24, ...props }) => (
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Props 타입 선언이 빠져 있습니다

TSX 파일인데 props가 암시적 any 입니다. SVGProps<SVGSVGElement>를 활용해 명시적으로 선언하면 IDE 지원과 타입 안전성이 향상됩니다.

-import React from 'react';
-
-const ProfileDefaultIcon = ({ size = 24, ...props }) => (
+import React, { type SVGProps } from 'react';
+
+interface ProfileDefaultIconProps extends SVGProps<SVGSVGElement> {
+  size?: number;
+}
+
+const ProfileDefaultIcon = ({ size = 24, ...props }: ProfileDefaultIconProps) => (
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const ProfileDefaultIcon = ({ size = 24, ...props }) => (
import React, { type SVGProps } from 'react';
interface ProfileDefaultIconProps extends SVGProps<SVGSVGElement> {
size?: number;
}
const ProfileDefaultIcon = ({ size = 24, ...props }: ProfileDefaultIconProps) => (
🤖 Prompt for AI Agents
In public/assets/svg/profile-default.tsx at line 3, the props parameter lacks an
explicit type declaration, causing it to be implicitly any. To fix this, import
SVGProps from React and declare the component props as ({ size = 24, ...props }:
SVGProps<SVGSVGElement>) to ensure proper type checking and IDE support.

<svg
xmlns='http://www.w3.org/2000/svg'
width={size}
height={size}
fill='none'
viewBox='0 0 160 160'
>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

접근성 개선 필요
role="img"<title> 또는 aria-label을 추가하여 시각적 의미를 제공하세요.

🧰 Tools
🪛 Biome (2.1.2)

[error] 4-10: Alternative text title element cannot be empty

For accessibility purposes, SVGs should have an alternative text, provided via title element. If the svg element has role="img", you should add the aria-label or aria-labelledby attribute.

(lint/a11y/noSvgWithoutTitle)

🤖 Prompt for AI Agents
In public/assets/svg/profile-default.tsx around lines 4 to 10, the SVG element
lacks accessibility attributes. Add role="img" to the SVG tag and include a
<title> element or an aria-label attribute to provide a descriptive label for
screen readers, ensuring the SVG's visual meaning is conveyed to assistive
technologies.

<path
fill='#E3E5E8'
d='M80 0C35.813 0 0 35.813 0 80c0 44.188 35.813 80 80 80 44.188 0 80-35.812 80-80 0-44.187-35.812-80-80-80m0 40c12.428 0 22.5 10.075 22.5 22.5S92.438 85 80 85c-12.425 0-22.5-10.075-22.5-22.5S67.563 40 80 40m0 100c-16.54 0-31.531-6.728-42.406-17.591C42.656 109.344 55.156 100 70 100h20c14.856 0 27.356 9.337 32.406 22.409C111.531 133.281 96.531 140 80 140'
/>
</svg>
);

export default ProfileDefaultIcon;
44 changes: 44 additions & 0 deletions src/apis/mypage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { privateInstance } from './privateInstance';
import { User } from '@/types/user';
import {
ProfileImageResponse,
UpdateProfileRequest,
} from '@/types/mypageTypes';

/**
* 내 정보 조회
* GET /api/users/me
*/
export const getMyProfile = async (): Promise<User> => {
const response = await privateInstance.get('/users/me');
return response.data;
};

/**
* 내 정보 수정
* PATCH /api/users/me
*/
export const updateMyProfile = async (
data: UpdateProfileRequest,
): Promise<User> => {
const response = await privateInstance.patch('/users/me', data);
return response.data;
};

/**
* 프로필 이미지 업로드
* POST /api/users/me/image
*/
export const uploadProfileImage = async (
file: File,
): Promise<ProfileImageResponse> => {
const formData = new FormData();
formData.append('image', file);

const response = await privateInstance.post('/users/me/image', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
return response.data;
};
18 changes: 18 additions & 0 deletions src/app/(with-header)/mypage/activities/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export default function MyActivitiesPage() {
return (
<>
{/* 제목 */}
<div className='mb-48'>
<h1 className='text-nomad text-[32px] leading-[42px] font-bold'>
내 체험 관리
</h1>
</div>

{/* 내 체험 관리 컨텐츠 */}
<div className='mx-auto w-full max-w-[343px] md:max-w-[429px] lg:mx-0 lg:max-w-[792px]'>
<p className='text-lg text-gray-600'>내 체험 관리 페이지입니다.</p>
{/* TODO: 내 체험 관리 컴포넌트 구현 */}
</div>
</>
);
}
Comment on lines +1 to +18
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

컴포넌트 구조가 깔끔하고 반응형 디자인이 잘 구현되었습니다.

기본적인 페이지 구조와 반응형 레이아웃이 올바르게 구현되어 있습니다. 향후 실제 컨텐츠 구현 시 일관성을 위해 몇 가지 제안사항이 있습니다.

향후 구현 시 고려할 개선사항:

+interface MyActivitiesPageProps {
+  // 필요시 props 타입 정의
+}
+
-export default function MyActivitiesPage() {
+export default function MyActivitiesPage({}: MyActivitiesPageProps = {}) {

또한 일관된 스타일링을 위해 스타일 상수나 공통 컴포넌트 사용을 고려해보세요:

const CONTAINER_STYLES = 'mx-auto w-full max-w-[343px] md:max-w-[429px] lg:mx-0 lg:max-w-[792px]';
🤖 Prompt for AI Agents
In src/app/(with-header)/mypage/activities/page.tsx lines 1 to 18, the component
structure and responsive design are well implemented. To improve consistency and
maintainability in future content additions, extract repeated or complex
className strings like container styles into style constants or shared
components. Define a constant for the container styles and replace the inline
className string with this constant to ensure uniform styling and easier
updates.

87 changes: 87 additions & 0 deletions src/app/(with-header)/mypage/components/ProfileImage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
'use client';

import { useState } from 'react';
import Image from 'next/image';
import cn from '@/lib/cn';
import { ProfileImageProps } from '@/types/mypageTypes';
import PenIcon from '@assets/svg/pen';
import ProfileDefaultIcon from '@assets/svg/profile-default';

/**
* @component ProfileImage
* @description
* 마이페이지 전용 프로필 이미지 컴포넌트입니다.
*
* @param {ProfileImageProps} props - ProfileImage 컴포넌트의 props
* @param {string} [props.src] - 프로필 이미지 URL
* @param {string} [props.alt] - 이미지 alt 텍스트
* @param {string} [props.nickname='사용자'] - 사용자 닉네임
* @param {boolean} [props.showEditButton=false] - 편집 버튼 표시 여부
* @param {() => void} [props.onEdit] - 편집 버튼 클릭 핸들러
* @param {string} [props.className] - 추가 CSS 클래스
*/

function isValidUrl(url: string): boolean {
if (!url || url.trim() === '') return false;

try {
new URL(url);
return true;
} catch {
return false;
}
}

export default function ProfileImage({
src,
alt,
nickname = '사용자',
showEditButton = false,
onEdit,
className,
}: ProfileImageProps) {
const [imageError, setImageError] = useState(false);

// 이미지 로딩 에러 핸들러
const handleImageError = () => {
setImageError(true);
};

// URL 유효성 검사
const hasValidImage = src && isValidUrl(src) && !imageError;

return (
<div className={cn('relative inline-block', className)}>
{/* 프로필 이미지 컨테이너 */}
<div className='relative h-160 w-160 overflow-hidden rounded-full bg-gray-200 shadow-lg'>
{hasValidImage ? (
<Image
src={src}
alt={alt || `${nickname}의 프로필 이미지`}
fill
className='object-cover'
onError={handleImageError}
sizes='160px'
/>
) : (
// 기본 프로필 아이콘
<div className='flex h-full w-full items-center justify-center'>
<ProfileDefaultIcon size={160} />
</div>
)}
</div>

{/* 편집 버튼 */}
{showEditButton && (
<button
onClick={onEdit}
className='absolute right-0 bottom-0 flex h-32 w-32 items-center justify-center rounded-full bg-green-300 shadow-lg transition-colors hover:bg-green-200 focus:ring-2 focus:ring-green-300 focus:ring-offset-2 focus:outline-none'
aria-label='프로필 이미지 편집'
type='button'
>
<PenIcon size={20} />
</button>
)}
</div>
);
}
Comment on lines +35 to +87
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

프로필 이미지 컴포넌트가 잘 구현되었습니다!

이미지 에러 처리, URL 유효성 검사, 접근성 고려가 모두 적절합니다. 다만, 고정 크기(160x160)를 사용하고 있어 반응형 디자인을 위해 크기를 props로 받는 것을 고려해보세요.

🤖 Prompt for AI Agents
In src/app/(with-header)/mypage/components/ProfileImage.tsx around lines 35 to
87, the ProfileImage component uses a fixed size of 160x160 for the image and
container. To improve responsiveness, add a size prop to the component to allow
dynamic sizing. Replace all hardcoded 160 values with this size prop, providing
a default value if none is passed, so the component can adapt to different
layouts.

Loading
Loading