Skip to content

Commit

Permalink
test(fe): 다른 방법으로 마우스 호버로 이미지 확대할 수 있는 기능 테스트 (마지막)
Browse files Browse the repository at this point in the history
  • Loading branch information
devbattery committed Dec 9, 2024
1 parent 4ff1699 commit e1c96f7
Showing 1 changed file with 127 additions and 141 deletions.
268 changes: 127 additions & 141 deletions fe/src/components/common/menuItemEditor/ImageBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,165 +8,151 @@ import { PlusGhostIcon } from '../icon/icons';
import { Spinner } from '../loading/spinner';

type Props = {
menuId: string;
imageUrl?: string;
onEditMenuImage(id: string, image: ImageType): void;
menuId: string;
imageUrl?: string;
onEditMenuImage(id: string, image: ImageType): void;
};

export const ImageBox: React.FC<Props> = ({
menuId,
imageUrl,
onEditMenuImage,
menuId,
imageUrl,
onEditMenuImage,
}) => {
const toast = useToast();
const { mutate: imageMutate, isLoading } = usePostImage('feed');
const toast = useToast();
const { mutate: imageMutate, isLoading } = usePostImage('feed');

const inputRef = useRef<HTMLInputElement>(null);
const imageRef = useRef<HTMLImageElement>(null); // img 태그 ref 추가
const inputRef = useRef<HTMLInputElement>(null);

const [imageData, setImageData] = useState({
id: '',
url: imageUrl,
originalUrl: '', // 원본 이미지 URL 저장
});
const [imageData, setImageData] = useState({
id: '',
url: imageUrl,
});

const handleImageClick = () => {
if (isLoading) return;
const handleImageClick = () => {
if (isLoading) return;

if (inputRef.current) {
inputRef.current.click();
}
};

const handleUploadImage = async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];

if (!file) {
return;
}

const ALLOWED_TYPES = ['image/png', 'image/jpg', 'image/jpeg'];
const MAX_FILE_SIZE_BYTES = 1024 * 1024 * 2.6; // 2MB

if (!ALLOWED_TYPES.includes(file.type) || file.size > MAX_FILE_SIZE_BYTES) {
toast.noti(
'이미지는 2.6MB 이하의 png, jpg, jpeg 파일만 업로드 가능합니z다.'
);
return;
}

const resizedFile = (await resizeImage({
file,
maxWidth: 850,
maxHeight: 850,
})) as File;
console.log('resizedFile', resizedFile);

const formData = new FormData();
formData.append('file', resizedFile);
// formData.append('file', file);

imageMutate(formData, {
onSuccess: (res) => {
console.log(res, ' now res');
setImageData(res);
onEditMenuImage(menuId, res);
},
});

if (inputRef.current) {
inputRef.current.value = '';
}
};

return (
<ImageWrapper $isImageUrl={!!imageUrl} onClick={handleImageClick}>
<input
ref={inputRef}
type="file"
accept=".png, .jpg, .jpeg"
onChange={handleUploadImage}
/>
<ImageContainer>
<img
src={imageData.url || generateDefaultUserImage(menuId)}
alt="menu item image"
/>
</ImageContainer>
{isLoading && (
<SpinnerContainer>
<Spinner isLoading={isLoading} />
</SpinnerContainer>
)}
{!isLoading && <PlusGhostIcon />}
</ImageWrapper>
);
};

if (inputRef.current) {
inputRef.current.click();
const ImageWrapper = styled.div<{ $isImageUrl: boolean }>`
width: 95px;
height: 95px;
position: relative;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
overflow: hidden;
&::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 95px;
height: 95px;
background-color: rgba(0, 0, 0, 0.3);
pointer-events: none;
cursor: pointer;
}
};
const handleUploadImage = async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];

if (!file) {
return;
input[type='file'] {
display: none;
&::file-selector-button {
display: none;
}
}
const ALLOWED_TYPES = ['image/png', 'image/jpg', 'image/jpeg'];
const MAX_FILE_SIZE_BYTES = 1024 * 1024 * 2.6; // 2MB

if (!ALLOWED_TYPES.includes(file.type) || file.size > MAX_FILE_SIZE_BYTES) {
toast.noti(
'이미지는 2.6MB 이하의 png, jpg, jpeg 파일만 업로드 가능합니다.'
);
return;
svg {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 10;
}
`;

const resizedFile = (await resizeImage({
file,
maxWidth: 850,
maxHeight: 850,
})) as File;
console.log('resizedFile', resizedFile);

const formData = new FormData();
formData.append('file', resizedFile);
// formData.append('file', file); // 원본 이미지 업로드 시

imageMutate(formData, {
onSuccess: (res) => {
console.log(res, ' now res');
// originalUrl 저장 (res에 원본 url이 있다고 가정)
// 만약 원본 이미지를 업로드하는 경우, res.url을 resizedFile의 url로 변경
setImageData({ ...res, originalUrl: res.url });
onEditMenuImage(menuId, res);
},
});
const ImageContainer = styled.div`
width: 100%;
height: 100%;
transition: transform 0.2s ease-in-out;
if (inputRef.current) {
inputRef.current.value = '';
&:hover {
transform: scale(1.1);
}
};

return (
<ImageWrapper
$isImageUrl={!!imageUrl}
onClick={handleImageClick}
onMouseEnter={() => {
if (imageRef.current && imageData.originalUrl) {
imageRef.current.src = imageData.originalUrl;
imageRef.current.style.transform = 'scale(1.5)';
}
}}
onMouseLeave={() => {
if (imageRef.current) {
imageRef.current.src =
imageData.url || generateDefaultUserImage(menuId);
imageRef.current.style.transform = 'scale(1)';
}
}}
>
<input
ref={inputRef}
type="file"
accept=".png, .jpg, .jpeg"
onChange={handleUploadImage}
/>
<img
ref={imageRef}
src={imageData.url || generateDefaultUserImage(menuId)}
alt="menu item image"
/>
{isLoading && (
<SpinnerContainer>
<Spinner isLoading={isLoading} />
</SpinnerContainer>
)}
{!isLoading && <PlusGhostIcon />}
</ImageWrapper>
);
};
const ImageWrapper = styled.div<{ $isImageUrl: boolean }>`
width: 95px;
height: 95px;
position: relative;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
&::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 95px;
height: 95px;
background-color: rgba(0, 0, 0, 0.3);
pointer-events: none;
cursor: pointer;
}
input[type='file'] {
display: none;
&::file-selector-button {
display: none;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
img {
width: 95px;
height: 95px;
object-fit: cover;
transition: transform 0.3s ease;
z-index: 1;
}
&:hover img {
z-index: 10;
}
svg {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 10;
}
`;

const SpinnerContainer = styled.div`
Expand Down

0 comments on commit e1c96f7

Please sign in to comment.