Skip to content

Commit

Permalink
Merge pull request #97 from Na-o-man/feat/#89
Browse files Browse the repository at this point in the history
Feat/#89
  • Loading branch information
NekoGroove01 authored Aug 22, 2024
2 parents 294340c + f6fabdc commit 8a1dc31
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 101 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const ShareGroupBottomBar: React.FC<BottomBarProps> = ({
// 선택한 이미지들의 URL을 다운로드함
const imageUrls: string[] = srcs;
const handleDownload = async (): Promise<void> => {
await imageZipDownloader({ imageUrls });
await imageZipDownloader(imageUrls);
};
return (
<S.Layout>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,7 @@ const ShareGroupCloudButton: React.FC = () => {
const response = await getDownloadPhotosAll(shareGroupId, profileId);
console.log(response.data.data);
if (response.status === 200) {
await imageZipDownloader({
imageUrls: response.data.data.photoDownloadUrlList,
});
await imageZipDownloader(response.data.data.photoDownloadUrlList);
}
} catch (error) {
console.log(error);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { useRecoilState } from 'recoil';
import ShareGroupBottomBar from '../ShareGroupBottomBar/ShareGroupBottomBar';
import { deletePhoto } from 'apis/deletePhoto';
import { useLocation, useNavigate } from 'react-router-dom';
import { getPhotosAll, getPhotosEtc } from 'apis/getPhotosAll';
import { getPhotos } from 'apis/getPhotos';

export interface itemProp {
createdAt: string;
Expand All @@ -24,14 +26,14 @@ export interface itemProp {
const ShareGroupImageList = ({
items,
maxPage,
getApi,
profileId,
shareGroupId,
loading,
setLoading,
}: {
items: itemProp[];
maxPage: number;
getApi: (page: number) => Promise<void>;
profileId: number;
shareGroupId: number; // Add shareGroupId as a prop
// infinite scroll loading을 위한 state
loading: boolean;
Expand Down Expand Up @@ -76,14 +78,12 @@ const ShareGroupImageList = ({
setIsModal(false);
};

// infinite scroll의 다음 아이템을 가져올지 결정하는 함수

// 사진 삭제
const handleDelete = async () => {
let photoToDelete: number[] = [];
if (selectedImage) {
const id = localItems.find(
(item) => item.w400PhotoUrl === selectedImage,
(item) => item.rawPhotoUrl === selectedImage,
)?.photoId;
if (id) photoToDelete.push(id);
} else if (checkedImg) photoToDelete = checkedImg;
Expand All @@ -109,8 +109,56 @@ const ShareGroupImageList = ({
if (!isChecked) setCheckedImg([]);
}, [isChecked]);

// 사진 불러오기 API 호출 함수
const handleApi = async (
page: number,
profileId: number,
shareGroupId: number,
): Promise<itemProp[]> => {
// page가 있으면 page를 넣어줌
const reqDataWithPage = {
shareGroupId: shareGroupId,
profileId: profileId,
size: 20,
page: page,
};
setLoading(true);

try {
if (profileId === 0) {
const { status, data } = await getPhotosAll(reqDataWithPage);
if (status === 200) {
setLoading(false);
return data.photoInfoList;
}
} else if (profileId === -1) {
const { status, data } = await getPhotosEtc(reqDataWithPage);
if (status === 200) {
setLoading(false);
return data.photoInfoList;
}
} else {
const { status, data } = await getPhotos(reqDataWithPage);
if (status === 200) {
setLoading(false);
return data.photoInfoList;
}
}
return [];
} catch (e) {
alert('앨범 조회 중 오류가 발생하였습니다');
console.error('Failed to fetch more items:', e);
return [];
}
};

// 스크롤 이벤트 핸들러
const handleScroll = useCallback(() => {
console.log('scroll');
if (page >= maxPage) {
setHasMore(false); // 페이지가 최대치에 도달하면 더 이상 로드하지 않도록 설정
return;
}
if (containerRef.current && !loading && hasMore) {
const { scrollTop, scrollHeight, clientHeight } = containerRef.current;
// 스크롤이 하단에 도달했는지 확인
Expand All @@ -123,10 +171,16 @@ const ShareGroupImageList = ({

// 페이지가 변경될 때마다 API 호출
useEffect(() => {
if (page > 0) {
if (page > 0 && hasMore) {
// hasMore가 true일 때만 API 호출
const fetchMoreItems = async () => {
try {
await getApi(page);
const newItems: itemProp[] = await handleApi(
page,
profileId,
shareGroupId,
);
setLocalItems((prevItems) => [...prevItems, ...newItems]); // 새로운 아이템을 기존 아이템에 추가
} catch (error) {
console.error('Failed to fetch more items:', error);
} finally {
Expand All @@ -135,7 +189,7 @@ const ShareGroupImageList = ({
};
fetchMoreItems();
}
}, [page, getApi, setLoading]);
}, [page, handleApi, setLoading, hasMore]);

// 스크롤 이벤트 리스너 등록
useEffect(() => {
Expand All @@ -150,11 +204,6 @@ const ShareGroupImageList = ({
};
}, [handleScroll]);

useEffect(() => {
if (choiceMode) setIsChecked(true);
if (!isChecked) setCheckedImg([]);
}, [isChecked]);

return (
<>
<S.Layout isModal={isModal}>
Expand All @@ -166,7 +215,7 @@ const ShareGroupImageList = ({
selected={false}
isDownload={item.isDownload}
onClick={() =>
handleImageClick(i, item.photoId, item.w200PhotoUrl)
handleImageClick(i, item.photoId, item.rawPhotoUrl)
}
checked={checkedImg.includes(item.photoId)}
/>
Expand Down
1 change: 1 addition & 0 deletions src/pages/ShareGroup/ShareGroupDetailPage/DropDown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const DropDown: React.FC<DropDownProps> = ({ groupId }) => {
setIsClicked(!isClicked);
};


const handleItemClick = (idx: number, profileId: number, name: string) => {
if (name === '모든 사진') {
setPhotoType('all');
Expand Down
16 changes: 13 additions & 3 deletions src/pages/ShareGroup/ShareGroupDetailPage/ShareGroupDetailPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,17 @@ const ShareGroupDetailPage: React.FC = () => {

const handleApi = async (page: number): Promise<void> => {
// page가 있으면 page를 넣어줌
const reqDataWithPage = { ...requestData, page: page };
const reqDataWithPage = profileId
? {
shareGroupId: location.state.shareGroupId,
profileId: profileId,
size: 20,
page: page,
}
: {
...requestData,
page: page,
};
try {
if (requestType === 'all') {
const { status, data } = await getPhotosAll(reqDataWithPage);
Expand Down Expand Up @@ -99,8 +109,8 @@ const ShareGroupDetailPage: React.FC = () => {
<ShareGroupImageList
items={items}
maxPage={maxPage}
getApi={getApi}
shareGroupId={groupId}
profileId={location.state.profileId}
shareGroupId={location.state.shareGroupId}
loading={loading}
setLoading={setLoading}
/>
Expand Down
94 changes: 14 additions & 80 deletions src/utils/ImageZipDownloader.ts
Original file line number Diff line number Diff line change
@@ -1,86 +1,20 @@
import JSZip from 'jszip';

// 모바일 장치인지 확인
const isMobile = (): boolean => {
if (window.matchMedia('(max-width: 767px)').matches) {
return true;
}
// 두 번째 방법
const userAgent = navigator.userAgent;

// iOS, Android, Windows Phone 등의 모바일 장치를 감지
if (/android/i.test(userAgent)) {
return true;
}

if (/iPhone|iPad|iPod/i.test(userAgent)) {
return true;
}

if (/windows phone/i.test(userAgent)) {
return true;
}

// 기타 모바일 장치 감지
if (/mobile/i.test(userAgent)) {
return true;
}

return false;
};

// 이미지들을 jpeg로 변환하여 zip 파일로 다운로드
const imageZipDownloader = async ({
imageUrls,
}: {
imageUrls: string[];
}): Promise<void> => {
if (isMobile()) {
// 모바일일 경우 개별 다운로드
for (const url of imageUrls) {
try {
const response = await fetch(url);
const blob = await response.blob();
const fileName = url.split('/').pop() || 'image';
const downloadUrl = window.URL.createObjectURL(blob);
// 이미지들을 jpeg로 변환하여 다운로드
const imageZipDownloader = async (imageUrls: string[]) => {
imageUrls.forEach((url, index) => {
fetch(url)
.then((response) => response.blob())
.then((blob) => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = downloadUrl;
a.download = fileName;
a.href = url;
a.download = `image-${index + 1}.jpeg`; // 파일 이름 지정
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(downloadUrl);
} catch (error) {
console.error('Error processing image:', error);
throw error;
}
}
} else {
// 모바일이 아니면 ZIP 파일로 압축하여 다운로드
const zip = new JSZip();

for (const url of imageUrls) {
try {
const response = await fetch(url);
const blob = await response.blob();
const fileName = url.split('/').pop() || 'image';
zip.file(fileName, blob);
} catch (error) {
console.error('Error processing image:', error);
throw error;
}
}

const zipBlob = await zip.generateAsync({ type: 'blob' });
const zipUrl = window.URL.createObjectURL(zipBlob);
const a = document.createElement('a');
a.href = zipUrl;
a.download = 'images.zip';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(zipUrl);
}
a.remove();
window.URL.revokeObjectURL(url);
})
.catch((error) => console.error('Image download failed:', error));
});
};

export default imageZipDownloader;

0 comments on commit 8a1dc31

Please sign in to comment.