Skip to content

Commit

Permalink
fix: fix with Uploading Image logic & type error
Browse files Browse the repository at this point in the history
  • Loading branch information
yihyun-kim1 committed Aug 23, 2024
1 parent b0842eb commit 550ed8a
Show file tree
Hide file tree
Showing 17 changed files with 286 additions and 130 deletions.
9 changes: 8 additions & 1 deletion apis/place/PlaceApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,14 @@ class PlaceApi {

formData.append("addPlaceRequest", JSON.stringify(payload.addPlaceRequest));

formData.append("placeImages", JSON.stringify(payload?.placeImages));
if (
!payload.addPlaceRequest.autoCompletedPlaceImageUrls ||
payload.addPlaceRequest.autoCompletedPlaceImageUrls.length === 0
) {
payload.placeImages?.forEach((image) => {
formData.append("placeImages", image);
});
}

const { data } = await this.axios({
method: "POST",
Expand Down
4 changes: 3 additions & 1 deletion apis/place/types/dto/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,17 @@ export interface AddPlaceRequestDto {
phoneNumber?: string | null;
starGrade?: number | null;
memo?: string;
origin: string;
voteLikeCount?: number | null;
voteDislikeCount?: number | null;
longitude?: number | null;
latitude?: number | null;
autoCompletedPlaceImageUrls?: string[];
}

export interface CreatePlacePayloadDto {
addPlaceRequest: AddPlaceRequestDto;
placeImages?: string[];
placeImages?: File[];
}

export interface ModifyPlaceRequestDto {
Expand Down
25 changes: 20 additions & 5 deletions app/add-course/_components/AddCourse.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,14 @@ const AddCourse = ({ data }: AddCourseProps) => {
const sliderRef = useRef<HTMLDivElement | null>(null);
const isMobile = useIsMobile();
const { clipboardText } = useCopyPasted();

const [placeUrl, setPlaceUrl] = useState("");
const [showInput, setShowInput] = useState(true);
const [showAlternateInput, setShowAlternateInput] = useState(false);
const [isModalOpen, setIsModalOpen] = useState(false);
const [isReadyToVote, setIsReadyToVote] = useState(false);
const searchParams = useSearchParams();

const roomUid = searchParams.get("roomUid") || "";
const {
roomInfo,
Expand All @@ -51,10 +53,10 @@ const AddCourse = ({ data }: AddCourseProps) => {
setAutoData,
} = useCourseContext();
const [selectedChip, setSelectedChip] = useState<number | null | undefined>(
categoryList && categoryList.length > 0 ? categoryList[0].scheduleId : null
null
);

const { data: currentPlacesData } = useGetPlacesQuery({
const { data: currentPlacesData, refetch } = useGetPlacesQuery({
variables: { roomUid },
});

Expand All @@ -68,12 +70,22 @@ const AddCourse = ({ data }: AddCourseProps) => {
const isValidClipboardText = validateClipboardText(clipboardText);
const isValidPlaceUrl = validateClipboardText(placeUrl);

useEffect(() => {
if (categoryList && categoryList.length > 0) {
setSelectedChip(categoryList[0].scheduleId);
}
}, [categoryList]);

useEffect(() => {
if (currentPlacesData) {
setRoomPlacesInfo(currentPlacesData);
}
}, [currentPlacesData, setRoomPlacesInfo]);

useEffect(() => {
refetch();
}, [currentPlacesData, setRoomPlacesInfo]);

const { mutate: createPlaceMutate } = useCreatePlace({
options: {
onSuccess: (res) => {
Expand Down Expand Up @@ -141,15 +153,18 @@ const AddCourse = ({ data }: AddCourseProps) => {

useEffect(() => {
const fetchData = async () => {
if (!isMobile && isValidClipboardText) {
if (!isMobile && clipboardText && isValidClipboardText) {
setShowInput(false);
setIsClipboardText(true);
createPlaceMutate({ url: clipboardText });
} else if (isValidPlaceUrl) {
} else if (placeUrl && isValidPlaceUrl) {
setShowInput(false);
setIsClipboardText(true);
createPlaceMutate({ url: placeUrl });
} else if (!isValidClipboardText || !isValidPlaceUrl) {
} else if (
(clipboardText && !isValidClipboardText) ||
(placeUrl && !isValidPlaceUrl)
) {
setShowInput(false);
setShowAlternateInput(true);
setTimeout(() => {
Expand Down
137 changes: 111 additions & 26 deletions app/add-course/_components/InputWithImage.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,47 @@
"use client";
import * as React from "react";
import { useEffect, useState } from "react";
import { useState, useCallback } from "react";
import Image from "next/image";
import { cn } from "@/lib/utils";

export interface InputProps
extends React.InputHTMLAttributes<HTMLInputElement> {
onFilesChange?: (files: string[]) => void;
onFilesChange?: (formData: FormData) => void;
}

const InputWithImage = React.forwardRef<HTMLInputElement, InputProps>(
({ className, onFilesChange, ...props }, ref) => {
const [uploadedFiles, setUploadedFiles] = useState<string[]>([]);
const [uploadedFiles, setUploadedFiles] = useState<File[]>([]);

useEffect(() => {
if (onFilesChange) {
onFilesChange(uploadedFiles);
}
}, [uploadedFiles, onFilesChange]);

const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const files = e.target.files;
if (files) {
const newFiles = Array.from(files)
.slice(0, 3 - uploadedFiles.length) // 최대 3개의 파일만 업로드
.map(
(file) =>
`${process.env.NEXT_PUBLIC_DNS_URL}/${URL.createObjectURL(file)}`
);

setUploadedFiles((prevFiles) => [...prevFiles, ...newFiles]);
}
};
const handleFileChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
const files = e.target.files;
if (files) {
const newFiles = Array.from(files).slice(0, 3 - uploadedFiles.length); // 최대 3개의 파일
const updatedFiles = [...uploadedFiles, ...newFiles];
setUploadedFiles(updatedFiles);

// FormData 생성 및 파일 추가
const formData = new FormData();
updatedFiles.forEach((file) => formData.append("placeImages", file));

if (onFilesChange) {
onFilesChange(formData);
}
}
},
[uploadedFiles, onFilesChange]
);

const handleDeleteFile = (index: number) => {
setUploadedFiles((prevFiles) => prevFiles.filter((_, i) => i !== index));
const updatedFiles = uploadedFiles.filter((_, i) => i !== index);
setUploadedFiles(updatedFiles);

const formData = new FormData();
updatedFiles.forEach((file) => formData.append("placeImages", file));

if (onFilesChange) {
onFilesChange(formData);
}
};

return (
Expand All @@ -53,8 +60,10 @@ const InputWithImage = React.forwardRef<HTMLInputElement, InputProps>(
{uploadedFiles.map((file, index) => (
<div key={index} className="relative w-[80px] h-[80px]">
<Image
src={file}
alt={`${file}`}
src={URL.createObjectURL(file)}
width={80}
height={80}
alt={`uploaded-image-${index}`}
className="object-cover w-full h-full rounded"
/>
<button
Expand All @@ -75,3 +84,79 @@ const InputWithImage = React.forwardRef<HTMLInputElement, InputProps>(
InputWithImage.displayName = "InputWithImage";

export { InputWithImage };

// "use client";
// import * as React from "react";
// import { useEffect, useState } from "react";
// import Image from "next/image";
// import { cn } from "@/lib/utils";

// export interface InputProps
// extends React.InputHTMLAttributes<HTMLInputElement> {
// onFilesChange?: (files: File[]) => void;
// }

// const InputWithImage = React.forwardRef<HTMLInputElement, InputProps>(
// ({ className, onFilesChange, ...props }, ref) => {
// const [uploadedFiles, setUploadedFiles] = useState<File[]>([]);

// useEffect(() => {
// if (onFilesChange) {
// onFilesChange(uploadedFiles);
// console.log(uploadedFiles, "uploadedFiles");
// }
// }, [uploadedFiles, onFilesChange]);

// const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
// const files = e.target.files;
// if (files) {
// const newFiles = Array.from(files).slice(0, 3 - uploadedFiles.length); // 최대 3개의 파일만 업로드
// console.log(files, "files");
// setUploadedFiles((prevFiles) => [...prevFiles, ...newFiles]);
// }
// };

// const handleDeleteFile = (index: number) => {
// setUploadedFiles((prevFiles) => prevFiles.filter((_, i) => i !== index));
// };

// return (
// <div className="flex flex-row items-center gap-x-[9px] gap-y-2 w-full">
// {uploadedFiles.length < 3 && (
// <input
// type="file"
// className={cn("flex rounded-lg border", className)}
// onChange={handleFileChange}
// ref={ref}
// multiple
// {...props}
// />
// )}
// <div className="flex gap-x-[9px] flex-wrap">
// {uploadedFiles.map((file, index) => (
// <div key={index} className="relative w-[80px] h-[80px]">
// <Image
// src={URL.createObjectURL(file)}
// width={80}
// height={80}
// alt={`uploaded-image-${index}`}
// className="object-cover w-full h-full rounded"
// />
// <button
// type="button"
// onClick={() => handleDeleteFile(index)}
// className="absolute top-0 left-0 text-[#FF601C] rounded-full w-4 h-4 flex items-center justify-center text-sm"
// >
// x
// </button>
// </div>
// ))}
// </div>
// </div>
// );
// }
// );

// InputWithImage.displayName = "InputWithImage";

// export { InputWithImage };
5 changes: 1 addition & 4 deletions app/add-course/_components/InputWithLabel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@ import { cn } from "@/lib/utils";
export interface InputWithLabelProps
extends React.InputHTMLAttributes<HTMLInputElement> {
iconSrc?: string;
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
required?: boolean;
}

const InputWithLabel = React.forwardRef<HTMLInputElement, InputWithLabelProps>(
({ className, iconSrc, value, onChange, required, type, ...props }, ref) => {
({ className, iconSrc, value, required, type, ...props }, ref) => {
return (
<div className="flex flex-col gap-y-2 w-full bg-[#F9FAFB] border rounded-[12px]">
<div className="flex items-center w-full h-[56px] px-[20px]">
Expand All @@ -29,8 +28,6 @@ const InputWithLabel = React.forwardRef<HTMLInputElement, InputWithLabelProps>(
"flex-1 bg-transparent text-[#8B95A1] text-[16px] outline-none",
className
)}
value={value}
onChange={onChange}
ref={ref}
{...props}
/>
Expand Down
2 changes: 1 addition & 1 deletion app/add-course/_components/PlaceContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const PlaceContainer: React.FC<PlacesContainerProps> = ({
origin={place?.origin}
place={place?.name}
link={place?.url}
rating={place?.starGrade?.toString()}
rating={place?.starGrade}
reviewCount={place?.reviewCount}
images={place?.placeImageUrls?.contents}
category={scheduleInfo}
Expand Down
6 changes: 3 additions & 3 deletions app/add-course/_hooks/useAddPlaceDetailForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ export type CommonPlaceDetailFormType = {
url?: string;
reviewCount?: number;
starGrade?: number;
openingHours?: string;
openingHours?: string | null;
phoneNumber?: string;
address?: string;
memo?: string;
pictures: string[];
pictures?: File[];
};

const addPlaceDetailSchema = z.object({
Expand All @@ -28,7 +28,7 @@ const addPlaceDetailSchema = z.object({
phoneNumber: z.string().optional(),
address: z.string().optional(),
memo: z.string().optional(),
pictures: z.array(z.string()),
pictures: z.array(z.any().optional()),
});

export const useAddPlaceDetailForm = (
Expand Down
Loading

0 comments on commit 550ed8a

Please sign in to comment.