Skip to content
This repository was archived by the owner on May 30, 2023. It is now read-only.

Commit 06d1fc0

Browse files
committed
update: load thumbnail for image list
1 parent bbc87f1 commit 06d1fc0

13 files changed

Lines changed: 357 additions & 252 deletions

File tree

src/reduxes/album/reducer.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,10 @@ const albumReducer = (state = inititalState, action: any): AlbumReducer => {
100100
[payload.filename]: {
101101
...state.images[payload.filename],
102102
blob: payload.blob,
103-
url: payload.url,
103+
thumbnailUrl: payload.thumbnailUrl
104+
? payload.thumbnailUrl
105+
: state.images[payload.filename].thumbnailUrl,
106+
url: payload.url ? payload.url : state.images[payload.filename].url,
104107
size: payload.size,
105108
},
106109
},

src/reduxes/album/type.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,14 @@ export type ImageSourceType =
2929
export interface ImageApiFields {
3030
filename: string;
3131
s3_key: string;
32+
thumbnail: string;
3233
photoKey: string;
3334
typeOfImage: ImageSourceType;
3435
gen_id?: string[] | string;
3536
classtype?: string;
3637
blob?: Blob;
3738
url?: string;
39+
thumbnailUrl?: string;
3840
size?: number;
3941
}
4042

@@ -104,12 +106,13 @@ export interface LoadImageContentPayload {
104106
isFetchToDownload?: boolean;
105107
isSelectedDownload?: boolean;
106108
blob?: Blob;
109+
isThumbnailImage?: boolean;
107110
}
108111

109112
export interface LoadImageContentSucceedPayload {
110113
projectId: string;
111114
filename: string;
112115
blob: Blob;
113-
url: string;
116+
thumbnailUrl: string;
114117
size: number;
115118
}

src/reduxes/project/reducer.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -436,10 +436,10 @@ const projectReducer = (
436436
}
437437
case LOAD_PROJECT_THUMBNAIL_IMAGE.SUCCEEDED:
438438
case LOAD_PROJECT_THUMBNAIL_IMAGE.FAILED: {
439-
const { projectId, thumbnailUrl } =
439+
const { projectId, projectThumbnailUrl } =
440440
payload as LoadProjectThumbnailImageSucceedPayload;
441441
const newThumbnails = { ...state.thumbnails };
442-
newThumbnails[projectId] = thumbnailUrl;
442+
newThumbnails[projectId] = projectThumbnailUrl;
443443
return { ...state, thumbnails: newThumbnails };
444444
}
445445
case SET_IS_OPEN_UPDATE_PROJECT_INFO: {

src/reduxes/project/type.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ export interface LoadProjectThumbnailImagePayload {
221221
}
222222

223223
export interface LoadProjectThumbnailImageSucceedPayload {
224-
thumbnailUrl: string;
224+
projectThumbnailUrl: string;
225225
projectId: string;
226226
}
227227
export interface UpdateProjectInfo {
Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
import { useEffect } from "react";
2+
import { useDispatch, useSelector } from "react-redux";
3+
import {
4+
Box,
5+
Card,
6+
CardContent,
7+
CardMedia,
8+
IconButton,
9+
Modal,
10+
Skeleton,
11+
Typography,
12+
} from "@mui/material";
13+
import CancelIcon from "@mui/icons-material/Cancel";
14+
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
15+
import ArrowForwardIcon from "@mui/icons-material/ArrowForward";
16+
17+
import { modalCloseStyle, modalStyle } from "styles/generalStyle";
18+
19+
import lodash from "lodash";
20+
import { AUGMENT_SOURCE, PREPROCESS_SOURCE } from "constants/defaultValues";
21+
import { ImageApiFields } from "reduxes/album/type";
22+
import { ListMethodType, MethodInfoFields } from "reduxes/project/type";
23+
24+
import { formatBytes, objectIndexOf } from "utils/general";
25+
import {
26+
selectorCurrentProjectId,
27+
selectorMethodList,
28+
} from "reduxes/project/selector";
29+
import { loadImageContent } from "reduxes/album/action";
30+
import { S3_BUCKET_NAME } from "constants/s3Values";
31+
32+
import { PreviewImageModalProps } from "./type";
33+
34+
const convertMethodCodeToName = (
35+
image: ImageApiFields | null,
36+
listMethod: ListMethodType | null
37+
) => {
38+
if (image && image.gen_id) {
39+
let usingListMethod: Array<MethodInfoFields> = [];
40+
if (image.typeOfImage === PREPROCESS_SOURCE) {
41+
usingListMethod = listMethod?.preprocessing || [];
42+
} else if (image.typeOfImage === AUGMENT_SOURCE) {
43+
usingListMethod = listMethod?.augmentation || [];
44+
}
45+
46+
if (usingListMethod) {
47+
let genIdArray = [];
48+
49+
if (typeof image.gen_id === "string") {
50+
try {
51+
genIdArray = JSON.parse(image.gen_id.replace(/'/g, '"'));
52+
} catch {
53+
//
54+
}
55+
} else {
56+
genIdArray = image.gen_id || [];
57+
}
58+
59+
return genIdArray.map((methodCode: string) => {
60+
if (usingListMethod) {
61+
const matchMethodIndex = objectIndexOf(
62+
usingListMethod,
63+
methodCode,
64+
"method_id"
65+
);
66+
if (matchMethodIndex > -1) {
67+
if (image.typeOfImage === PREPROCESS_SOURCE) {
68+
return lodash.startCase(
69+
usingListMethod[matchMethodIndex].method_name.replace(/_/g, " ")
70+
);
71+
}
72+
73+
if (image.typeOfImage === AUGMENT_SOURCE) {
74+
return lodash.startCase(
75+
usingListMethod[matchMethodIndex].method_name
76+
.replace(/_/g, " ")
77+
.replace(/random/g, "")
78+
);
79+
}
80+
81+
return "";
82+
}
83+
84+
return "";
85+
}
86+
return "";
87+
});
88+
}
89+
}
90+
91+
return [];
92+
};
93+
94+
function PreviewImageModal({
95+
images,
96+
imagesFileNameArray,
97+
previewImage,
98+
setPreviewImage,
99+
}: PreviewImageModalProps) {
100+
const listMethod = useSelector(selectorMethodList);
101+
const dispatch = useDispatch();
102+
103+
const currentProjectId = useSelector(selectorCurrentProjectId);
104+
105+
const onViewPreviousImages = (currentImageFileName: string) => {
106+
if (currentImageFileName) {
107+
const currentPreviewIamgeIndex =
108+
imagesFileNameArray.indexOf(currentImageFileName);
109+
110+
if (currentPreviewIamgeIndex > -1) {
111+
if (currentPreviewIamgeIndex + 1 > 1) {
112+
setPreviewImage(
113+
images[imagesFileNameArray[currentPreviewIamgeIndex - 1]]
114+
);
115+
}
116+
}
117+
}
118+
};
119+
120+
const onViewNextImages = (currentImageFileName: string) => {
121+
if (currentImageFileName) {
122+
const currentPreviewIamgeIndex =
123+
imagesFileNameArray.indexOf(currentImageFileName);
124+
125+
if (currentPreviewIamgeIndex > -1) {
126+
if (currentPreviewIamgeIndex + 1 < imagesFileNameArray.length) {
127+
setPreviewImage(
128+
images[imagesFileNameArray[currentPreviewIamgeIndex + 1]]
129+
);
130+
}
131+
}
132+
}
133+
};
134+
135+
useEffect(() => {
136+
const handleNavigateWhenPressArrow = (event: KeyboardEvent) => {
137+
if (previewImage) {
138+
if (event.key === "ArrowRight") {
139+
onViewNextImages(previewImage?.filename!);
140+
} else if (event.key === "ArrowLeft") {
141+
onViewPreviousImages(previewImage?.filename!);
142+
}
143+
}
144+
};
145+
146+
document.addEventListener("keydown", handleNavigateWhenPressArrow);
147+
148+
return () => {
149+
document.removeEventListener("keydown", handleNavigateWhenPressArrow);
150+
};
151+
}, [previewImage]);
152+
153+
const methodListString = convertMethodCodeToName(
154+
previewImage,
155+
listMethod
156+
).join(", ");
157+
158+
useEffect(() => {
159+
if (previewImage) {
160+
dispatch(
161+
loadImageContent({
162+
fileName: previewImage.filename,
163+
projectId: currentProjectId,
164+
typeMethod: previewImage.typeOfImage,
165+
photoKey: previewImage.s3_key.replace(`${S3_BUCKET_NAME}/`, ""),
166+
isFetchToDownload: false,
167+
isThumbnailImage: false,
168+
})
169+
);
170+
}
171+
}, [previewImage]);
172+
173+
return (
174+
<Modal open={!!previewImage} onClose={() => setPreviewImage(null)}>
175+
<Box sx={modalStyle} bgcolor="background.paper">
176+
<IconButton sx={modalCloseStyle} onClick={() => setPreviewImage(null)}>
177+
<CancelIcon fontSize="large" />
178+
</IconButton>
179+
<Box>
180+
<Typography sx={{ marginBottom: 1 }} variant="h5" component="p">
181+
Preview Image
182+
</Typography>
183+
184+
<Box
185+
display="flex"
186+
justifyContent="space-between"
187+
alignItems="center"
188+
>
189+
<Box>
190+
<IconButton
191+
sx={{ "&:disabled": { opacity: 0.2 } }}
192+
disabled={
193+
imagesFileNameArray.indexOf(previewImage?.filename!) === 0
194+
}
195+
onClick={() => onViewPreviousImages(previewImage?.filename!)}
196+
>
197+
<ArrowBackIcon fontSize="large" />
198+
</IconButton>
199+
</Box>
200+
<Box>
201+
{previewImage ? (
202+
<Card
203+
sx={{
204+
width: "80vw",
205+
height: "80vh",
206+
maxHeight: "80vh",
207+
maxWidth: "80vw",
208+
display: "flex",
209+
flexDirection: "column",
210+
alignItems: "center",
211+
boxShadow: "none",
212+
}}
213+
>
214+
{images[previewImage.filename].url ? (
215+
<CardMedia
216+
sx={{
217+
objectFit: "contain",
218+
width: "60vw",
219+
height: "60vh",
220+
maxHeight: "60vh",
221+
maxWidth: "60vw",
222+
}}
223+
component="img"
224+
src={images[previewImage.filename].url}
225+
alt="ts"
226+
/>
227+
) : (
228+
<Box sx={{ position: "relative" }}>
229+
<Skeleton
230+
sx={{
231+
position: "absolute",
232+
top: 0,
233+
left: 0,
234+
zIndex: 999,
235+
}}
236+
variant="rectangular"
237+
width="100%"
238+
height="100%"
239+
/>
240+
<Box
241+
sx={{
242+
backgroundImage: `url(${previewImage.thumbnailUrl})`,
243+
backgroundRepeat: "no-repeat",
244+
backgroundPosition: "center",
245+
backgroundSize: "cover",
246+
width: "60vw",
247+
height: "60vh",
248+
maxHeight: "60vh",
249+
maxWidth: "60vw",
250+
opacity: 0.3,
251+
}}
252+
/>
253+
</Box>
254+
)}
255+
256+
<CardContent>
257+
<Typography variant="body2">
258+
Name:{" "}
259+
<Typography
260+
fontWeight="bold"
261+
component="span"
262+
variant="body2"
263+
>
264+
{previewImage.filename}
265+
</Typography>
266+
</Typography>
267+
<Typography variant="body2">
268+
Size:{" "}
269+
{images[previewImage.filename].url
270+
? formatBytes(images[previewImage.filename].size || 0)
271+
: "... bytes"}
272+
</Typography>
273+
{methodListString && (
274+
<Typography variant="body2">
275+
Method: {methodListString}.
276+
</Typography>
277+
)}
278+
</CardContent>
279+
</Card>
280+
) : null}
281+
</Box>
282+
<Box>
283+
<IconButton
284+
sx={{ "&:disabled": { opacity: 0.2 } }}
285+
disabled={
286+
imagesFileNameArray.indexOf(previewImage?.filename!) ===
287+
imagesFileNameArray.length - 1
288+
}
289+
onClick={() => onViewNextImages(previewImage?.filename!)}
290+
>
291+
<ArrowForwardIcon fontSize="large" />
292+
</IconButton>
293+
</Box>
294+
</Box>
295+
</Box>
296+
</Box>
297+
</Modal>
298+
);
299+
}
300+
301+
export default PreviewImageModal;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { AlbumImagesFields, ImageApiFields } from "reduxes/album/type";
2+
3+
export interface PreviewImageModalProps {
4+
previewImage: ImageApiFields | null;
5+
setPreviewImage: (image: ImageApiFields | null) => void;
6+
images: AlbumImagesFields;
7+
imagesFileNameArray: string[];
8+
}

0 commit comments

Comments
 (0)