Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[온보딩] step02 썸네일 등록 시 아이폰 이미지 확장자(heic) 업로드 안되는 현상 수정 #497

Merged
merged 7 commits into from
Mar 14, 2024
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"date-fns": "^3.2.0",
"dayjs": "^1.11.10",
"file-saver": "^2.0.5",
"heic2any": "^0.0.4",
"html2canvas": "^1.4.1",
"lottie-web": "^5.12.2",
"open-graph": "^0.2.6",
Expand Down
2 changes: 1 addition & 1 deletion src/components/OnBoardingSteps/Step02/Step02.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const ThumbnailInput = React.memo((props: ThumbnailInputProps) => {
<S.IcEmptyThumbnailWrapper>
<input
type='file'
accept='image/jpeg, image/png, image/gif, image/heic '
accept='image/jpeg, image/png, image/gif, image/heic, image/webp, image/HEIC'
Copy link
Contributor

Choose a reason for hiding this comment

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

앗 이거 저도 수정해야 하는데, MIME type은 대소문자 구분을 하지 않고 주로 소문자로 쓰인다고 해서 image/heic만 유지해도 될 것 같아요!

MIME 타입

style={{ display: 'none' }}
id='imgInput'
onChange={handleImageUpload}
Expand Down
147 changes: 90 additions & 57 deletions src/hooks/common/usePreviewImage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,72 +2,105 @@ import { toast } from 'react-toastify';
import { usePreviewImageContext } from '../../context/Onboarding/PreviewImageContext';
import { IMAGE_HEIGHT, MESSAGE } from '../../core/toast-messages';
import Resizer from 'react-image-file-resizer';
import heic2any from 'heic2any';

const usePreviewImage = () => {
const { previewImageInfo, updatePreviewImageInfo } = usePreviewImageContext();

const handleImageUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
const { files } = event.target;
const uploadFalse = () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

이 부분을 함수 분리하셨군요! 가독성이 더 좋아졌네요👍

updatePreviewImageInfo({
isImageUploaded: false,
file: null,
previewImage: null,
imageName: '',
});
};

const uploadFalse = () => {
updatePreviewImageInfo({
isImageUploaded: false,
file: null,
previewImage: null,
imageName: '',
});
};
const resizedFile = (file: File, previewImage: string) => {
new Promise((resolve) => {
Resizer.imageFileResizer(
file,
480,
480,
'WEBP',
75,
0,
(uri) => {
updatePreviewImageInfo({
isImageUploaded: true,
imageName: (uri as File).name,
file: uri as File,
previewImage: previewImage,
});
resolve(uri);
console.log('됐다?');
},
'file',
);
});
};

const resizedFile = (file: File, previewImage: string) => {
new Promise((resolve) => {
Resizer.imageFileResizer(
file,
480,
480,
'WEBP',
75,
0,
(uri) => {
updatePreviewImageInfo({
isImageUploaded: true,
imageName: (uri as File).name,
file: uri as File,
previewImage: previewImage,
});
resolve(uri);
console.log('됐다?');
},
'file',
);
});
const isFailUploadImageToast = (selectedFile: Blob | MediaSource) => {
const img = new Image();

img.onload = function () {
if (img.height <= IMAGE_HEIGHT.MIN) {
// 이미지 너비가 어느 수준 이하일 때 업로드 x
toast(MESSAGE.HEIGHT_SMALL);
uploadFalse();
} else if (img.height > IMAGE_HEIGHT.MAX) {
toast(MESSAGE.HEIGHT_BIG);
uploadFalse();
}
};

if (files && files.length > 0) {
const selectedFiles = files as FileList;
/**@see 추후 유니크한 이미지 네임 필요할 수 있으니 일단 주석처리 */
// const imageName = files[0].name.trim();

/**@todo 파싱 유틸 함수 공용으로 따로 작성 */
// const uploadTime = new Date().toISOString();

// const uniqueName = `${uploadTime}${imageName}`;
// const finalImageName = uniqueName
// .replace(/\//g, '') // 폴더링 방지를 위해 '/' 제거
// .replace(/\s/g, ''); // 공백 제거
resizedFile(selectedFiles[0], URL.createObjectURL(selectedFiles[0]));

const img = new Image();
img.onload = function () {
if (img.height <= IMAGE_HEIGHT.MIN) {
// 이미지 너비가 어느 수준 이하일 때 업로드 x
toast(MESSAGE.HEIGHT_SMALL);
uploadFalse();
} else if (img.height > IMAGE_HEIGHT.MAX) {
toast(MESSAGE.HEIGHT_BIG);
uploadFalse();
img.src = URL.createObjectURL(selectedFile);
};

const handleImageUpload = async (event: React.ChangeEvent<HTMLInputElement>) => {
const { files } = event.target;

try {
if (files && files.length > 0) {
const selectedFiles = files as FileList;

let convertedFile = selectedFiles[0];
console.log('convertedFile', convertedFile);

if (selectedFiles[0].type === 'image/heic' || selectedFiles[0].type === 'image/HEIC') {
let blob = selectedFiles[0];
console.log('blob', blob);
const resultBlob = await heic2any({ blob, toType: 'image/webp' });
convertedFile = new File(
[resultBlob as Blob],
selectedFiles[0].name.split('.')[0] + '.webp',
{ type: 'image/webp', lastModified: new Date().getTime() },
);
updatePreviewImageInfo({
isImageUploaded: true,
imageName: convertedFile.name,
file: convertedFile,
previewImage: URL.createObjectURL(selectedFiles[0]),
});
}
};
img.src = URL.createObjectURL(selectedFiles[0]);

/**@see 추후 유니크한 이미지 네임 필요할 수 있으니 일단 주석처리 */
// const imageName = files[0].name.trim();

/**@todo 파싱 유틸 함수 공용으로 따로 작성 */
// const uploadTime = new Date().toISOString();

// const uniqueName = `${uploadTime}${imageName}`;
// const finalImageName = uniqueName
// .replace(/\//g, '') // 폴더링 방지를 위해 '/' 제거
// .replace(/\s/g, ''); // 공백 제거

isFailUploadImageToast(selectedFiles[0]);

resizedFile(selectedFiles[0], URL.createObjectURL(selectedFiles[0]));
}
} catch (err) {
console.log('error:', err);
}
};

Expand Down
7 changes: 5 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3510,6 +3510,11 @@ hasown@^2.0.0:
dependencies:
function-bind "^1.1.2"

heic2any@^0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/heic2any/-/heic2any-0.0.4.tgz#eddb8e6fec53c8583a6e18b65069bb5e8d19028a"
integrity sha512-3lLnZiDELfabVH87htnRolZ2iehX9zwpRyGNz22GKXIu0fznlblf0/ftppXKNqS26dqFSeqfIBhAmAj/uSp0cA==

hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1:
version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
Expand Down Expand Up @@ -4495,13 +4500,11 @@ react-is@^16.13.1, react-is@^16.7.0:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==


react-is@^18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==


react-loading-skeleton@^3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/react-loading-skeleton/-/react-loading-skeleton-3.4.0.tgz#c71a3a17259d08e4064974aa0b07f150a09dfd57"
Expand Down