Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions public/assets/images/crew-sample/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import ImgCrewSample01 from './crew-sample-1.jpg';
import ImgCrewSample02 from './crew-sample-2.jpg';
import ImgCrewSample03 from './crew-sample-3.jpg';

const ImgCrewSamples = [
ImgCrewSample01,
ImgCrewSample02,
ImgCrewSample03,
];

export default ImgCrewSamples;
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions public/assets/images/gathering-sample/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import ImgGatheringSample01 from './gathering-sample-1.jpg';
import ImgGatheringSample02 from './gathering-sample-2.jpg';
import ImgGatheringSample03 from './gathering-sample-3.jpg';

const ImgGatheringSamples = [
ImgGatheringSample01,
ImgGatheringSample02,
ImgGatheringSample03,
];

export default ImgGatheringSamples;
25 changes: 25 additions & 0 deletions src/_apis/crew/get-crew-list.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { fetchApi } from '@/src/utils/api';
import { CrewCardInform, CrewCardInformResponse } from '@/src/types/crew-card';

export async function getCrewList(page: number, limit: number): Promise<CrewCardInformResponse> {
try {
const response = await fetchApi<CrewCardInformResponse>(
`/crews?_page=${page + 1}&_limit=${limit}`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
},
);
if (!Array.isArray(response)) {
throw new Error('서버 응답이 올바른 형식이 아닙니다.');
}
const data = response as CrewCardInform[];
const hasNextPage = data.length === limit;

return { data, hasNextPage };
} catch (error) {
throw new Error('크루 리스트를 불러오는데 실패했습니다.');
}
}
4 changes: 2 additions & 2 deletions src/_queries/crew-queries.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getCrewData } from '@/src/app/api/mock-api/crew';
import { CrewCardInform } from '@/src/types/crew-card';
import { getCrewList } from '../_apis/crew/get-crew-list';

// Crew data 변환 로직을 간소화한 helper 함수
const mapCrewData = (crew: CrewCardInform) => ({
Expand Down Expand Up @@ -31,7 +31,7 @@ export function useGetCrewQuery() {

return {
queryKey: ['crew'],
queryFn: ({ pageParam = 0 }: QueryParams) => getCrewData(pageParam, 3),
queryFn: ({ pageParam = 0 }: QueryParams) => getCrewList(pageParam, 3),
getNextPageParam: (lastPage: Page, allPages: Page[]) =>
lastPage.hasNextPage ? allPages.length + 1 : undefined,
select: (data: CrewCardInform[]) => data.map(mapCrewData),
Expand Down
7 changes: 6 additions & 1 deletion src/app/(crew)/crew/_components/create-crew-form/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import DropDown from '@/src/components/common/input/drop-down';
import FileInputWrap from '@/src/components/common/input/file-input-wrap';
import TextInput from '@/src/components/common/input/text-input';
import { CreateCrewRequestTypes } from '@/src/types/create-crew';
import ImgCrewSamples from '@/public/assets/images/crew-sample';

export interface CreateCrewFormTypes {
data: CreateCrewRequestTypes;
Expand Down Expand Up @@ -154,7 +155,11 @@ export default function CreateCrewForm({
control={control}
rules={{ required: '이미지를 선택해주세요.' }}
render={({ field }) => (
<FileInputWrap {...field} onChange={(newValue) => field.onChange(newValue)} />
<FileInputWrap
{...field}
sample={ImgCrewSamples}
onChange={(newValue) => field.onChange(newValue)}
/>
)}
/>
{errors.imageUrl && <p className="text-red-500">{errors.imageUrl.message}</p>}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import FileInputWrap from '@/src/components/common/input/file-input-wrap';
import TextInput from '@/src/components/common/input/text-input';
import Textarea from '@/src/components/common/input/textarea';
import { CreateGatheringRequestType } from '@/src/types/gathering-data';
import ImgGatheringSamples from '@/public/assets/images/gathering-sample';

export interface CreateGatheringFormTypes {
data: CreateGatheringRequestType;
Expand Down Expand Up @@ -89,6 +90,7 @@ export default function CreateGatheringForm({
</label>
<div className="flex">
<FileInputWrap
sample={ImgGatheringSamples}
value={values.imageUrl}
onChange={(newValue) =>
setValues((prevValues) => ({ ...prevValues, imageUrl: newValue }))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,18 @@ export default function CreateGatheringModalPresenter({
title="약속 잡기"
styles={{
root: { '--modal-size': '520px' },
content: { boxShadow: '0 25px 50px -12px rgba(0,0,0,0.1)', borderRadius: '12px' },
content: {
boxShadow: '0 25px 50px -12px rgba(0,0,0,0.1)',
borderRadius: '12px',
},
}}
classNames={{
body: 'p-0',
title: 'text-xl font-semibold text-gray-900',
}}
>
<div>
<ScrollArea h={640}>
<ScrollArea h={760}>
<div className="flex flex-col gap-8 p-6">
<CreateGatheringForm
data={data}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export default function GatheringDetailModalPresenter({
}}
>
<div>
<ScrollArea h={640}>
<ScrollArea h={760}>
<figure className="relative aspect-video w-full overflow-hidden">
<Image
src={data?.imageUrl}
Expand Down
13 changes: 4 additions & 9 deletions src/app/(crew)/my-crew/page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
'use client';

import { useState } from 'react';
import { useGetCrewQuery } from '@/src/_queries/crew-queries';
import { useInfiniteScroll } from '@/src/hooks/useInfiniteScroll';
import { fetchCrewData } from '@/src/app/api/mock-api/crew';
import CrewCardList from '@/src/components/common/crew-list/crew-card-list';
import Tabs from '@/src/components/common/tab';
import { CrewCardInformResponse } from '@/src/types/crew-card';
Expand All @@ -15,14 +15,9 @@ export default function MyCrewPage() {
const [currentTab, setCurrentTab] = useState(myPageTabs[0].id);

// TODO: fetchCrewData 함수를 사용하여 데이터를 불러오기 : 파라미터 수정 필요
const { data, ref, isFetchingNextPage } = useInfiniteScroll<CrewCardInformResponse>({
queryKey: ['crew'],
queryFn: ({ pageParam = 0 }) => {
return fetchCrewData(pageParam, 3);
},
getNextPageParam: (lastPage, allPages) =>
lastPage.hasNextPage ? allPages.length + 1 : undefined,
});
const { data, ref, isFetchingNextPage } =
useInfiniteScroll<CrewCardInformResponse>(useGetCrewQuery());

return (
<div className="py-8 md:py-12.5">
<div className="px-3 md:px-8 lg:px-11.5">
Expand Down
42 changes: 0 additions & 42 deletions src/app/api/mock-api/crew.ts

This file was deleted.

14 changes: 4 additions & 10 deletions src/components/common/crew-list/crew-card-list.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { Meta, StoryObj } from '@storybook/react';
import { useGetCrewQuery } from '@/src/_queries/crew-queries';
import { useInfiniteScroll } from '@/src/hooks/useInfiniteScroll';
import { fetchCrewData } from '@/src/app/api/mock-api/crew';
import ClientProvider from '@/src/components/client-provider';
import { CrewCardInformResponse } from '@/src/types/crew-card';
import ClientProvider from '../../client-provider';
import CrewCardList from './crew-card-list';

const meta: Meta = {
Expand All @@ -28,14 +28,8 @@ export default meta;
type Story = StoryObj<typeof meta>;

function RenderCrewCardList() {
const { data, ref, isFetchingNextPage } = useInfiniteScroll<CrewCardInformResponse>({
queryKey: ['crew'],
queryFn: ({ pageParam = 0 }) => {
return fetchCrewData(pageParam, 3);
},
getNextPageParam: (lastPage, allPages) =>
lastPage.hasNextPage ? allPages.length + 1 : undefined,
});
const { data, ref, isFetchingNextPage } =
useInfiniteScroll<CrewCardInformResponse>(useGetCrewQuery());

return <CrewCardList data={data} ref={ref} isFetchingNextPage={isFetchingNextPage} />;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { ChangeEvent, useEffect, useRef, useState } from 'react';
import Image from 'next/image';
import Image, { StaticImageData } from 'next/image';
import IcoPlus from '@/public/assets/icons/ic-plus.svg';
import IcoX from '@/public/assets/icons/ic-x.svg';

export interface FileInputProps {
value: File | null;
value: File | StaticImageData | null;
onChange: (value: File | null) => void;
isBlur: boolean;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

타입 불일치 문제가 있습니다!

value prop이 StaticImageData를 받을 수 있지만, onChange 콜백은 StaticImageData를 처리할 수 없습니다. 이는 런타임 오류를 발생시킬 수 있습니다.

다음과 같이 수정하는 것을 제안합니다:

export interface FileInputProps {
-  value: File | StaticImageData | null;
-  onChange: (value: File | null) => void;
+  value: File | StaticImageData | null;
+  onChange: (value: File | StaticImageData | null) => void;
  isBlur: boolean;
}
📝 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
value: File | StaticImageData | null;
onChange: (value: File | null) => void;
isBlur: boolean;
value: File | StaticImageData | null;
onChange: (value: File | StaticImageData | null) => void;
isBlur: boolean;

}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { useEffect, useRef } from 'react';
import Image from 'next/image';
import Image, { StaticImageData } from 'next/image';

export interface FileSampleProps {
imgUrl: string;
image: StaticImageData;
isBlur: boolean;
onChange: (inputValue: File | null) => void;
onChange: (inputValue: StaticImageData) => void;
}

export default function FileSample({ imgUrl, isBlur, onChange }: FileSampleProps) {
export default function FileSample({ image, isBlur, onChange }: FileSampleProps) {
const radioInput = useRef<HTMLInputElement>(null);

const convertUrlToFile = async (
Expand All @@ -21,8 +21,7 @@ export default function FileSample({ imgUrl, isBlur, onChange }: FileSampleProps
};

const handleClick = async () => {
const file = await convertUrlToFile(imgUrl, 'crew-01.webp', 'image/webp');
onChange(file);
onChange(image);
};

useEffect(() => {
Expand All @@ -41,7 +40,7 @@ export default function FileSample({ imgUrl, isBlur, onChange }: FileSampleProps
className="absolute inset-0 hidden"
/>
<Image
src={imgUrl}
src={image}
width={282}
height={282}
alt="샘플 이미지 1"
Expand Down
28 changes: 9 additions & 19 deletions src/components/common/input/file-input-wrap/index.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
'use client';

import { useState } from 'react';
import { StaticImageData } from 'next/image';
import FileInput from './file-input';
import FileSample from './file-sample';

export interface FileInputProps {
value: File | null;
onChange: (newValue: File | null) => void;
sample: StaticImageData[];
onChange: (newValue: File | StaticImageData | null) => void;
}

export default function FileInputWrap({ value, onChange }: FileInputProps) {
const [fileValue, setFileValue] = useState<File | null>(value);
export default function FileInputWrap({ value, sample, onChange }: FileInputProps) {
const [fileValue, setFileValue] = useState<File | StaticImageData | null>(value);
const [isOtherSelected, setIsOtherSelected] = useState(false);
const [isSampleSelected, setIsSampleSelected] = useState(false);

const handleChange = (inputValue: File | null) => {
const handleChange = (inputValue: StaticImageData) => {
setIsOtherSelected(false);
setIsSampleSelected(true);
setFileValue(inputValue);
Expand All @@ -30,21 +32,9 @@ export default function FileInputWrap({ value, onChange }: FileInputProps) {

return (
<div className="container flex max-w-[1200px] gap-4">
<FileSample
imgUrl="https://images.stockcake.com/public/a/7/6/a768d87b-1f99-4b50-9286-f1583af33522_large/team-huddle-celebration-stockcake.jpg"
onChange={handleChange}
isBlur={isOtherSelected}
/>
<FileSample
imgUrl="https://images.stockcake.com/public/a/a/0/aa0e5e46-987b-43ab-9e14-0012148d4d47_large/joyful-sports-gathering-stockcake.jpg"
onChange={handleChange}
isBlur={isOtherSelected}
/>
<FileSample
imgUrl="https://images.stockcake.com/public/2/4/0/240c891a-9e35-4490-8714-a1c135b0c645_large/team-celebration-time-stockcake.jpg"
onChange={handleChange}
isBlur={isOtherSelected}
/>
<FileSample image={sample[0]} onChange={handleChange} isBlur={isOtherSelected} />
<FileSample image={sample[1]} onChange={handleChange} isBlur={isOtherSelected} />
<FileSample image={sample[2]} onChange={handleChange} isBlur={isOtherSelected} />
Comment on lines +35 to +37
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

배열 접근에 대한 안전성 검증이 필요합니다.

현재 구현은 sample 배열이 항상 3개의 항목을 가진다고 가정하고 있습니다. 배열의 길이가 부족할 경우 런타임 오류가 발생할 수 있습니다.

다음과 같이 안전한 배열 접근을 구현하는 것을 추천드립니다:

-      <FileSample image={sample[0]} onChange={handleChange} isBlur={isOtherSelected} />
-      <FileSample image={sample[1]} onChange={handleChange} isBlur={isOtherSelected} />
-      <FileSample image={sample[2]} onChange={handleChange} isBlur={isOtherSelected} />
+      {sample.map((image, index) => (
+        <FileSample
+          key={index}
+          image={image}
+          onChange={handleChange}
+          isBlur={isOtherSelected}
+        />
+      ))}
📝 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
<FileSample image={sample[0]} onChange={handleChange} isBlur={isOtherSelected} />
<FileSample image={sample[1]} onChange={handleChange} isBlur={isOtherSelected} />
<FileSample image={sample[2]} onChange={handleChange} isBlur={isOtherSelected} />
{sample.map((image, index) => (
<FileSample
key={index}
image={image}
onChange={handleChange}
isBlur={isOtherSelected}
/>
))}

<FileInput value={fileValue} onChange={handleFileInput} isBlur={isSampleSelected} />
</div>
);
Expand Down
2 changes: 1 addition & 1 deletion src/types/create-crew.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ export interface CreateCrewRequestTypes {
title: string;
mainCategory: string | null;
subCategory: string | null;
imageUrl: File | null;
imageUrl: File | StaticImageData | null;
mainLocation: string | null;
subLocation: string | null;
totalCount: number;
Expand Down
2 changes: 1 addition & 1 deletion src/types/gathering-data.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export interface CreateGatheringRequestType {
dateTime: string;
location: string;
totalCount: number;
imageUrl: File | null; // NOTE : 임시로 File로 설정
imageUrl: File | StaticImageData | null; // NOTE : 임시로 File로 설정
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

StaticImageData 타입을 가져오도록 수정이 필요합니다.

StaticImageData 타입을 사용하기 위해서는 next/image에서 해당 타입을 가져와야 합니다.

다음과 같이 수정해주세요:

+import { StaticImageData } from 'next/image';

Committable suggestion skipped: line range outside the PR's diff.

}

export interface GatheringCardProps {
Expand Down