Skip to content

Commit

Permalink
Merge pull request #226 from BCSDLab/feature/#197-add-image-upload-logic
Browse files Browse the repository at this point in the history
[영양사] 식단 이미지 업로드 presigned-url 적용
  • Loading branch information
MinGu-Jeong authored Apr 10, 2024
2 parents d9f6cc3 + aeefed7 commit b887435
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 39 deletions.
69 changes: 32 additions & 37 deletions src/page/Coop/components/MenuCard/index.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
/* eslint-disable max-len */
import { useGetDining, useUploadDiningImage, useUpdateSoldOut } from 'query/coop';
import {
Dinings, Menus, DINING_TYPES, Corner,
} from 'model/Coop';
import SoldoutToggle from 'page/Coop/components/SoldoutToggle';
import { ReactComponent as Photo } from 'assets/svg/coop/photo.svg';
import { useEffect, useRef, useState } from 'react';
import { useRef, useState } from 'react';
import { getCoopUrl } from 'api/uploadFile/index';
import CustomModal from 'component/common/CustomModal';
import axios from 'axios';
import styles from './MenuCard.module.scss';

interface MenuCardProps {
selectedMenuType: Menus;
}

interface FileInfo {
file: File;
presignedUrl: string;
}

export default function MenuCard({ selectedMenuType }: MenuCardProps) {
const { data } = useGetDining();
const { uploadDiningImageMutation } = useUploadDiningImage();
Expand All @@ -22,26 +27,32 @@ export default function MenuCard({ selectedMenuType }: MenuCardProps) {
const [isSoldoutModalOpen, setIsSoldoutModalOpen] = useState(false);
const [selectedMenu, setSelectedMenu] = useState<Dinings | null>(null);
const [selectedCorner, setSelectedCorner] = useState<Corner | null>(null);
const [selectedImages, setSelectedImages] = useState<{ [key: number]: string }>({});

const uploadImage = async ({ presignedUrl, file }: FileInfo) => {
await axios.put(presignedUrl, file, {
headers: {
'Content-Type': 'image/jpeg, image/png, image/svg+xml, image/webp',
},
});
};

const handleImageChange = (menuId: number) => async (
event: React.ChangeEvent<HTMLInputElement>,
) => {
const file = event.target.files?.[0];
if (file) {
const presignedUrl = await getCoopUrl({
const presigned = await getCoopUrl({
content_length: file.size,
content_type: file.type,
file_name: file.name,
});
await uploadDiningImageMutation({
menu_id: menuId,
image_url: presignedUrl.data.file_url,
});
setSelectedImages((prev) => ({
...prev,
[menuId]: presignedUrl.data.file_url,
}));
if (presigned.data.pre_signed_url) {
uploadImage({ presignedUrl: presigned.data.pre_signed_url, file });
uploadDiningImageMutation({
menu_id: menuId,
image_url: presigned.data.file_url,
});
}
}
};

Expand Down Expand Up @@ -83,28 +94,6 @@ export default function MenuCard({ selectedMenuType }: MenuCardProps) {
}
};

const getImageUrl = (menu: Dinings) => {
if (selectedImages[menu.id]) {
return selectedImages[menu.id];
} if (menu.image_url) {
return menu.image_url;
}
return undefined;
};

useEffect(() => {
if (data) {
data.forEach((menu: Dinings) => {
if (menu.image_url) {
setSelectedImages((prev) => ({
...prev,
[menu.id]: menu.image_url,
}));
}
});
}
}, [data]);

return (
<>
<div className={styles.container}>
Expand All @@ -116,7 +105,13 @@ export default function MenuCard({ selectedMenuType }: MenuCardProps) {
<span className={styles.card__title}>{corner}</span>
<div className={styles['card__soldout-wrapper']}>
{menu && <span className={styles.card__soldout}>품절</span>}
{menu && <SoldoutToggle menuId={menu.id} onClick={() => handleToggleSoldoutModal(menu, corner)} menu={menu} />}
{menu && (
<SoldoutToggle
menuId={menu.id}
onClick={() => handleToggleSoldoutModal(menu, corner)}
menu={menu}
/>
)}
</div>
</div>
<div className={styles.card__wrapper}>
Expand All @@ -131,8 +126,8 @@ export default function MenuCard({ selectedMenuType }: MenuCardProps) {
if (event.key === 'Enter') handleImageClick(menu.id)();
}}
>
{getImageUrl(menu) ? (
<img src={getImageUrl(menu)} alt="" className={styles.card__image} />
{menu.image_url ? (
<img src={menu.image_url} alt="" className={styles.card__image} />
) : (
<Photo />
)}
Expand Down
4 changes: 4 additions & 0 deletions src/query/KeyFactory/coopKeys.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const coopKeys = {
all: ['coop'] as const,
dining: ['coop', 'dining'] as const,
};
5 changes: 3 additions & 2 deletions src/query/coop.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { useMutation, useQueryClient, useSuspenseQuery } from '@tanstack/react-query';
import { getDining, updateSoldOut, uploadDiningImage } from 'api/coop';
import { DiningImages, SoldOut } from 'model/Coop';
import { coopKeys } from './KeyFactory/coopKeys';

export const useGetDining = () => {
const { data } = useSuspenseQuery(
{
queryKey: ['dining'],
queryKey: coopKeys.dining,
queryFn: getDining,
},
);
Expand All @@ -32,7 +33,7 @@ export const useUploadDiningImage = () => {
const { mutate: uploadDiningImageMutation } = useMutation({
mutationFn: (data: DiningImages) => uploadDiningImage(data),
onSuccess: () => {
queryClient.invalidateQueries();
queryClient.invalidateQueries({ queryKey: coopKeys.dining });
},
});
return {
Expand Down

0 comments on commit b887435

Please sign in to comment.