I need to return the getThumbnail
function so my images get resized. My problem now is that when I tried the code below, all the payload assigned to dispatch returns a promise now. How can I get rid of that and just return a normal payload. Before I had no problem returning it without the getThumbnail
but right now I'm forced since getThumbnail
is a promise. How do I fix this? Do I adjust getThumbnail
function or?
The issue on this code:
const responseImages = response?.data?.map(async (image) => {
return {
productName: image?.uploadResult?.productTitle,
imageFile: await getThumbnail(
images.find((img) => img?.imageFileName === image?.mediaCode)
?.imageFile || null, {
thumbWidth: 100,
thumbHeight: 100,
bgColor: "black",
}
),
imageFileName: image?.mediaCode || "",
};
});
helpers.js
const loadImage = (src) =>
new Promise((resolve, reject) => {
const img = new Image()
img.onload = () => resolve(img)
img.onerror = reject
img.src = src
})
const resize = (imageWidth, imageHeight, thumbWidth, thumbHeight) => {
let w = 0,
h = 0,
x = 0,
y = 0,
widthratio = imageWidth / thumbWidth,
heightratio = imageHeight / thumbHeight,
maxratio = Math.max(widthratio, heightratio)
if (maxratio > 1) {
w = imageWidth / maxratio
h = imageHeight / maxratio
} else {
w = imageWidth
h = imageHeight
}
x = (thumbWidth - w) / 2
y = (thumbHeight - h) / 2
return { w: w, h: h, x: x, y: y }
}
export async function getThumbnail(
photo,
{ thumbWidth, thumbHeight, bgColor }
) {
const img = await loadImage(URL.createObjectURL(photo))
const { naturalWidth, naturalHeight } = img
const canvas = document.createElement('canvas')
const cx = canvas.getContext('2d')
canvas.width = thumbWidth
canvas.height = thumbHeight
const dimensions = resize(
naturalWidth,
naturalHeight,
thumbWidth,
thumbHeight
)
cx.fillStyle = bgColor
cx.fillRect(0, 0, thumbWidth, thumbHeight)
cx.drawImage(img, dimensions.x, dimensions.y, dimensions.w, dimensions.h)
return canvas.toDataURL('image/jpeg')
}
Action.js
export const uploadPhotos =
({
photos,
size,
controller
}) =>
async (dispatch) => {
// Identify the part of the file name that excludes the (optional) sequence number
const keyedphotos = photos.map((photo) => [
photo.imageFileName.replace(/-\w+\.\w+$/, ""),
photo,
]);
// Create a group for each such prefix
const map = new Map(keyedphotos.map(([key]) => [key, []]));
// Populate those groups
for (const [key, photo] of keyedphotos) map.get(key).push(photo);
// And extract those groups into an array (of subarrays)
const photoGroups = [...map.values()];
let index = 0; // Keep the index counter separate
photoGroups.forEach(async (photos) => {
// Iterate the groups that can run in parallel
for (const photo of photos) {
// Iterate the photos that should run sequentially
const id = index++; // Get the next unique id
const formData = new FormData();
formData.append(photo?.imageFileName, photo?.imageFile);
dispatch({
type: constants.UPLOAD_PHOTOS_START,
size
});
try {
const response = await axios.post(
`${API_URL}/photos/upload`,
formData, {
onUploadProgress({
loaded,
total
}) {
dispatch(setUploadProgress({
id,
loaded,
total
})); // Use id
},
signal: controller.signal,
}
);
dispatch({
type: constants.UPLOAD_PHOTOS_SUCCESS,
payload: response.data,
});
const responseImages = response?.data?.map(async (image) => {
return {
productName: image?.uploadResult?.productTitle,
imageFile: await getThumbnail(
images.find((img) => img?.imageFileName === image?.mediaCode)
?.imageFile || null, {
thumbWidth: 100,
thumbHeight: 100,
bgColor: "black",
}
),
imageFileName: image?.mediaCode || "",
};
});
} catch (error) {
dispatch({
type: constants.UPLOAD_PHOTOS_FAILURE,
payload: error,
});
}
}
});
};