Skip to content

Commit

Permalink
feature: lazy load images on homepage
Browse files Browse the repository at this point in the history
Also:
- Improve error handling
  • Loading branch information
MDeLuise committed Sep 10, 2023
1 parent 716fb0b commit 0a94233
Show file tree
Hide file tree
Showing 12 changed files with 201 additions and 118 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.github.mdeluise.plantit.image;

import java.util.Base64;
import java.util.Collection;

import com.github.mdeluise.plantit.botanicalinfo.BotanicalInfo;
import com.github.mdeluise.plantit.botanicalinfo.BotanicalInfoService;
import com.github.mdeluise.plantit.image.storage.ImageStorageService;
Expand All @@ -19,9 +22,6 @@
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.util.Base64;
import java.util.Collection;

@RestController
@RequestMapping("/image")
public class ImageController {
Expand Down
16 changes: 14 additions & 2 deletions frontend/src/common.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AxiosInstance } from "axios";
import axios, { AxiosError, AxiosInstance } from "axios";

export const isBigScreen = (): boolean => {
return window.screen.width > 768;
Expand All @@ -13,7 +13,8 @@ const readImage = (requestor: AxiosInstance, imageUrl: string): Promise<string>
requestor.get(`image/content${imageUrl}`)
.then((res) => {
resolve(`data:application/octet-stream;base64,${res.data}`);
});
})
.catch((err) => reject(err));
});
};

Expand All @@ -38,3 +39,14 @@ export const isBackendReachable = (requestor: AxiosInstance): Promise<boolean> =
.catch((_err) => resolve(false));
});
};

export const getErrMessage = (err: any): string => {
console.error(err);
if (err.response != undefined) {
return err.response.data.message;
}
if (axios.isAxiosError(err)) {
return (err as AxiosError).message;
}
return "Some error occurred";
};
33 changes: 10 additions & 23 deletions frontend/src/components/AddPlant.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { Box, Button, Divider, Drawer, Switch, TextField } from "@mui/material";
import { AxiosError, AxiosInstance, AxiosResponse } from "axios";
import { AxiosInstance } from "axios";
import { botanicalInfo, plant } from "../interfaces";
import { useEffect, useState } from "react";
import dayjs, { Dayjs } from "dayjs";
import { LocalizationProvider, DatePicker } from "@mui/x-date-pickers";
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
import AddPhotoAlternateOutlinedIcon from '@mui/icons-material/AddPhotoAlternateOutlined';
import ErrorDialog from "./ErrorDialog";

export default function AddPlant(props: {
requestor: AxiosInstance,
open: boolean,
setOpen: (arg: boolean) => void,
entity?: botanicalInfo,
plants: plant[],
name?: string;
name?: string,
printError: (err: any) => void;
}) {
const [plantName, setPlantName] = useState<string>();
const [plantNameError, setPlantNameError] = useState<string>();
Expand All @@ -26,16 +26,14 @@ export default function AddPlant(props: {
const [selectedImage, setSelectedImage] = useState<File>();
const [downloadedImg, setDownloadedImg] = useState<string>();
const [imageDownloaded, setImageDownloaded] = useState<boolean>(false);
const [errorDialogShown, setErrorDialogShown] = useState<boolean>(false);
const [errorDialogText, setErrorDialogText] = useState<string>();

const readImage = (imageUrl: string): void => {
props.requestor.get(`image/content${imageUrl}`)
.then((res) => {
setDownloadedImg(res.data);
setImageDownloaded(true);
})
.catch((err) => showErrorDialog(err));
.catch((err) => props.printError(err));
};

const setAbsoluteImageUrl = (imageUrl: string | undefined, publicUrl: string): string => {
Expand Down Expand Up @@ -120,7 +118,7 @@ export default function AddPlant(props: {
}
})
.catch((err) => {
showErrorDialog(err);
props.printError(err);
});

};
Expand All @@ -141,7 +139,7 @@ export default function AddPlant(props: {
cleanup();
})
.catch((err) => {
showErrorDialog(err);
props.printError(err);
});
};

Expand Down Expand Up @@ -170,20 +168,21 @@ export default function AddPlant(props: {
props.setOpen(false);
res.botanicalInfo.imageUrl = "/" + imgRes.data.id;
props.plants.push(res);
//props.entity!.id = res.botanicalInfo.id;
setName();
cleanup();
})
.catch((err) => {
props.printError(err);
});
} else {
props.setOpen(false);
props.plants.push(res);
//props.entity!.id = res.botanicalInfo.id;
setName();
cleanup();
}
})
.catch((err) => {
showErrorDialog(err);
props.printError(err);
});
};

Expand Down Expand Up @@ -217,11 +216,6 @@ export default function AddPlant(props: {
setPlantName(name);
};

const showErrorDialog = (res: AxiosError) => {
setErrorDialogText((res.response?.data as any).message);
setErrorDialogShown(true);
};

useEffect(() => {
setImageDownloaded(false);
setImageSrc();
Expand All @@ -240,13 +234,6 @@ export default function AddPlant(props: {
style: { borderRadius: "15px 15px 0 0" }
}}
>

<ErrorDialog
text={errorDialogText}
open={errorDialogShown}
close={() => setErrorDialogShown(false)}
/>

<input
id="upload-image"
type="file"
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/components/AllLogs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ export default function AllLogs(props: {
entries: diaryEntry[],
plants: plant[],
openEditEvent: (arg: diaryEntry) => void,
printError: (err: any) => void;
}) {
const pageSize = 5;
const [entities, setEntities] = useState<diaryEntry[]>([]);
Expand Down Expand Up @@ -230,6 +231,9 @@ export default function AllLogs(props: {
} else {
setCircularProgressVisible(false);
}
})
.catch((err) => {
props.printError(err);
});
};

Expand Down
16 changes: 8 additions & 8 deletions frontend/src/components/Auth.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useEffect, useState } from "react";
import axios, { AxiosError, AxiosInstance } from 'axios';
import { AxiosError, AxiosInstance } from 'axios';
import { NavigateFunction, useNavigate } from "react-router";
import secureLocalStorage from "react-secure-storage";
import Avatar from '@mui/material/Avatar';
Expand All @@ -20,7 +20,7 @@ import VisibilityOff from '@mui/icons-material/VisibilityOff';
import FormControl from '@mui/material/FormControl';
import { FormHelperText } from "@mui/material";
import ErrorDialog from "./ErrorDialog";
import { isBackendReachable } from "../common";
import { getErrMessage, isBackendReachable } from "../common";

export default function (props: { requestor: AxiosInstance; }) {
const navigate: NavigateFunction = useNavigate();
Expand All @@ -45,8 +45,8 @@ export default function (props: { requestor: AxiosInstance; }) {
getOrCreateApiKey(jwt);
secureLocalStorage.setItem("plant-it-username", username);
})
.catch((err: AxiosError) => {
setErrorDialogText((err.response?.data as any).message);
.catch((err) => {
setErrorDialogText(getErrMessage(err));
setErrorDialogShown(true);
});
};
Expand All @@ -73,7 +73,7 @@ export default function (props: { requestor: AxiosInstance; }) {
navigate('/');
})
.catch((err) => {
setErrorDialogText((err.response?.data as any).message);
setErrorDialogText(getErrMessage(err));
setErrorDialogShown(true);
});
});
Expand All @@ -85,11 +85,11 @@ export default function (props: { requestor: AxiosInstance; }) {
username: username,
password: password
})
.then((_response) => {
.then((_res) => {
doLogin(event);
})
.catch((err: AxiosError) => {
setErrorDialogText((err.response?.data as any).message);
.catch((err) => {
setErrorDialogText(getErrMessage(err));
setErrorDialogShown(true);
});
};
Expand Down
20 changes: 4 additions & 16 deletions frontend/src/components/EditEvent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ export default function EditEvent(props: {
toEdit?: diaryEntry,
open: boolean,
setOpen: (arg: boolean) => void,
removeFromLog: (arg: number) => void;
removeFromLog: (arg: number) => void,
printError: (err: any) => void;
}) {
const [date, setDate] = useState<Dayjs>(dayjs());
const [selectedPlantName, setSelectedPlantName] = useState<string>();
Expand All @@ -82,8 +83,6 @@ export default function EditEvent(props: {
const [confirmDialogTitle, setConfirmDialogTitle] = useState<string>("");
const [confirmDialogText, setConfirmDialogText] = useState<string>("");
const [confirmDialogCallback, setConfirmDialogCallback] = useState<() => void>(() => () => { });
const [errorDialogShown, setErrorDialogShown] = useState<boolean>(false);
const [errorDialogText, setErrorDialogText] = useState<string>();

const updateEvent = (): void => {
let newTarget: plant = props.plants.filter((en) => en.personalName === selectedPlantName)[0];
Expand All @@ -100,7 +99,7 @@ export default function EditEvent(props: {
setEdit(false);
})
.catch((err) => {
showErrorDialog(err);
props.printError(err);
});
};

Expand All @@ -113,16 +112,11 @@ export default function EditEvent(props: {
setConfirmDialogOpen(false);
})
.catch((err) => {
showErrorDialog(err);
props.printError(err);
});
};


const showErrorDialog = (res: AxiosError) => {
setErrorDialogText((res.response?.data as any).message);
setErrorDialogShown(true);
};

useEffect(() => {
setSelectedPlantName(props.toEdit?.diaryTargetPersonalName);
setSelectedEventType(props.toEdit?.type);
Expand All @@ -134,12 +128,6 @@ export default function EditEvent(props: {

return (
<>
<ErrorDialog
text={errorDialogText}
open={errorDialogShown}
close={() => setErrorDialogShown(false)}
/>

<ConfirmDialog
open={confirmDialogOpen}
close={() => setConfirmDialogOpen(false)}
Expand Down
10 changes: 6 additions & 4 deletions frontend/src/components/ErrorDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ export default function ErrorDialog(props: {
}) {
return <div>
<BootstrapDialog
onClose={() => props.close()}
onClose={props.close}
open={props.open}
>
<DialogTitle sx={{ m: 0, p: 2 }} >
Error
</DialogTitle>
<IconButton
aria-label="close"
onClick={() => props.close()}
onClick={props.close}
sx={{
position: 'absolute',
right: 8,
Expand All @@ -36,15 +36,17 @@ export default function ErrorDialog(props: {
>
<CloseIcon />
</IconButton>
<DialogContent dividers>
<DialogContent dividers sx={{
overflowWrap: "break-word",
}}>
<Typography gutterBottom>
{props.text}
</Typography>
</DialogContent>
<DialogActions>
<Button
autoFocus
onClick={() => props.close()}
onClick={props.close}
fullWidth
>
Ok
Expand Down
Loading

0 comments on commit 0a94233

Please sign in to comment.