Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[EPICSYSTEM-243]: image cropping before upload #83

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { If, Then, Else } from 'react-if';
import { EngagementTabsContext } from './EngagementTabsContext';
import { EngagementStatus, SUBMISSION_STATUS } from 'constants/engagementStatus';
import DayCalculatorModal from '../DayCalculator';
import { ENGAGEMENT_CROPPER_ASPECT_RATIO, ENGAGEMENT_UPLOADER_HEIGHT } from './constants';
import { ENGAGEMENT_CROPPER_ASPECT_RATIO, ENGAGEMENT_CROPPER_TEXT, ENGAGEMENT_UPLOADER_HEIGHT } from './constants';
import RichTextEditor from 'components/common/RichTextEditor';
import { getTextFromDraftJsContentState } from 'components/common/RichTextEditor/utils';

Expand Down Expand Up @@ -304,6 +304,7 @@ const EngagementForm = () => {
savedImageName={savedEngagement.banner_filename}
height={ENGAGEMENT_UPLOADER_HEIGHT}
cropAspectRatio={ENGAGEMENT_CROPPER_ASPECT_RATIO}
cropText={ENGAGEMENT_CROPPER_TEXT}
/>
</Grid>
<Grid item xs={12}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ export const ENGAGEMENT_FORM_TABS: { [x: string]: EngagementFormTabValues } = {

export const ENGAGEMENT_UPLOADER_HEIGHT = '360px';
export const ENGAGEMENT_CROPPER_ASPECT_RATIO = 1920 / 700;
export const ENGAGEMENT_CROPPER_TEXT =
'The image will be cropped at the correct ratio to display as a banner on MET. You can zoom in or out and move the image around. Please note that part of the image could be hidden depending on the display size.';
66 changes: 44 additions & 22 deletions met-web/src/components/image/listing/ImageContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import { useAppDispatch } from 'hooks';

export interface ImageListingContext {
images: ImageInfo[];
handleUploadImage: (_files: File[]) => void;
handleTempUpload: (_files: File[]) => void;
handleUploadImage: () => void;
searchText: string;
setSearchText: (value: string) => void;
paginationOptions: PaginationOptions<ImageInfo>;
Expand All @@ -19,11 +20,15 @@ export interface ImageListingContext {
setPageInfo: (value: PageInfo) => void;
tableLoading: boolean;
imageToDisplay: ImageInfo | undefined;
imageToUpload: File | null;
}

export const ImageContext = createContext<ImageListingContext>({
images: [],
handleUploadImage: (_files: File[]) => {
handleTempUpload: (_files: File[]) => {
/* empty default method */
},
handleUploadImage: () => {
/* empty default method */
},
searchText: '',
Expand All @@ -45,6 +50,7 @@ export const ImageContext = createContext<ImageListingContext>({
},
tableLoading: false,
imageToDisplay: undefined,
imageToUpload: null,
});

export const ImageProvider = ({ children }: { children: JSX.Element | JSX.Element[] }) => {
Expand All @@ -64,17 +70,31 @@ export const ImageProvider = ({ children }: { children: JSX.Element | JSX.Elemen
const [tableLoading, setTableLoading] = useState(true);
const [pageInfo, setPageInfo] = useState<PageInfo>(createDefaultPageInfo());
const [images, setImages] = useState<Array<ImageInfo>>([]);
const [imageToUpload, setImageToUpload] = useState<File | null>(null);
const dispatch = useAppDispatch();
const { page, size, sort_key, sort_order } = paginationOptions;

const handleUploadImage = async (files: File[]) => {
const handleTempUpload = async (files: File[]) => {
if (files.length > 0) {
const [uniquefilename, fileName]: string[] = (await handleSaveImage(files[0])) || [];
setImageToDisplay(undefined);
setImageToUpload(files[0]);
return;
}
setImageToUpload(null);
};

const handleUploadImage = async () => {
if (!imageToUpload) return;
try {
const [uniquefilename, fileName]: string[] = (await handleSaveImageToS3(imageToUpload)) || [];
createImage(uniquefilename, fileName);
setImageToUpload(null);
} catch (error) {
console.log(error);
}
};

const handleSaveImage = async (file: File) => {
const handleSaveImageToS3 = async (file: File) => {
if (!file) {
return;
}
Expand All @@ -87,6 +107,22 @@ export const ImageProvider = ({ children }: { children: JSX.Element | JSX.Elemen
}
};

const createImage = async (unqiueFilename: string, fileName: string) => {
setImageToDisplay(undefined);
const date_uploaded = new Date();
try {
const image: ImageInfo = await postImage({
unique_name: unqiueFilename,
display_name: fileName,
date_uploaded,
});
setPaginationOptions({ page: 1, size: 10 });
setImageToDisplay(image);
} catch (err) {
dispatch(openNotification({ severity: 'error', text: 'Error occurred while creating image' }));
}
};

const fetchImages = async () => {
try {
setTableLoading(true);
Expand All @@ -108,22 +144,6 @@ export const ImageProvider = ({ children }: { children: JSX.Element | JSX.Elemen
}
};

const createImage = async (unqiueFilename: string, fileName: string) => {
setImageToDisplay(undefined);
const date_uploaded = new Date();
try {
const image: ImageInfo = await postImage({
unique_name: unqiueFilename,
display_name: fileName,
date_uploaded,
});
setPaginationOptions({ page: 1, size: 10 });
setImageToDisplay(image);
} catch (err) {
dispatch(openNotification({ severity: 'error', text: 'Error occurred while creating image' }));
}
};

useEffect(() => {
updateURLWithPagination(paginationOptions);
fetchImages();
Expand All @@ -133,7 +153,7 @@ export const ImageProvider = ({ children }: { children: JSX.Element | JSX.Elemen
<ImageContext.Provider
value={{
images,
handleUploadImage,
handleTempUpload,
searchText,
setSearchText,
paginationOptions,
Expand All @@ -142,6 +162,8 @@ export const ImageProvider = ({ children }: { children: JSX.Element | JSX.Elemen
pageInfo,
setPageInfo,
imageToDisplay,
imageToUpload,
handleUploadImage,
}}
>
{children}
Expand Down
43 changes: 30 additions & 13 deletions met-web/src/components/image/listing/ImageListing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,21 @@ import ContentCopyIcon from '@mui/icons-material/ContentCopy';
import { Else, If, Then } from 'react-if';
import { openNotification } from 'services/notificationService/notificationSlice';
import { useAppDispatch } from 'hooks';
import { formatDate } from 'components/common/dateHelper';

const ImageListing = () => {
const {
images,
handleUploadImage,
handleTempUpload,
paginationOptions,
searchText,
setSearchText,
tableLoading,
pageInfo,
setPaginationOptions,
imageToDisplay,
handleUploadImage,
imageToUpload,
} = useContext(ImageContext);

const dispatch = useAppDispatch();
Expand All @@ -36,7 +39,7 @@ const ImageListing = () => {

const headCells: HeadCell<ImageInfo>[] = [
{
key: 'display_name',
key: 'url',
label: '',
disablePadding: true,
allowSort: true,
Expand Down Expand Up @@ -69,13 +72,9 @@ const ImageListing = () => {
allowSort: true,
numeric: false,
renderCell: (row: ImageInfo) => {
const date = new Date(row.date_uploaded);
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, '0'); // Months are 0-indexed, pad with leading zero
const day = date.getDate().toString().padStart(2, '0'); // Pad with leading zero
return (
<Grid container item>
{`${year}-${month}-${day}`}
{formatDate(row.date_uploaded)}
</Grid>
);
},
Expand Down Expand Up @@ -115,15 +114,31 @@ const ImageListing = () => {
<ImageUpload
margin={4}
data-testid="image-listing/image-upload"
handleAddFile={handleUploadImage}
handleAddFile={handleTempUpload}
height={'240px'}
canCrop={false}
cropText="You can zoom in or out and move the image around."
/>
</Grid>
<If condition={imageToDisplay != undefined}>
<If condition={imageToUpload != null}>
<Then>
<Grid item xs={12}>
<Stack direction={'row'} justifyContent={'flex-end'} alignItems={'center'}>
<PrimaryButton
onClick={() => {
handleUploadImage();
}}
size="small"
>
Upload
</PrimaryButton>
</Stack>
</Grid>
</Then>
</If>
<If condition={imageToDisplay?.url}>
<Then>
<Grid item xs={6}>
<Stack direction="row" spacing={2} alignItems="center" justifyContent="left">
<Stack direction="row" spacing={2} alignItems="center" justifyContent="space-between">
<img
src={imageToDisplay?.url}
style={{
Expand Down Expand Up @@ -156,7 +171,6 @@ const ImageListing = () => {
<Grid item sx={{ height: '100px' }} />
</Else>
</If>

<Grid item xs={12}>
<HeaderTitle>Uploaded Files</HeaderTitle>
</Grid>
Expand All @@ -171,7 +185,10 @@ const ImageListing = () => {
onChange={(e) => setSearchText(e.target.value)}
size="small"
/>
<PrimaryButton onClick={() => setPaginationOptions({ page: 1, size: 10 })}>
<PrimaryButton
data-testid="image/listing/searchButton"
onClick={() => setPaginationOptions({ page: 1, size: 10 })}
>
<SearchIcon />
</PrimaryButton>
</Stack>
Expand Down
20 changes: 8 additions & 12 deletions met-web/src/components/imageUpload/Uploader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { Grid, Stack, Typography } from '@mui/material';
import Dropzone, { Accept } from 'react-dropzone';
import { PrimaryButton, SecondaryButton } from 'components/common';
import { ImageUploadContext } from './imageUploadContext';
import { When } from 'react-if';

interface UploaderProps {
margin?: number;
Expand All @@ -17,7 +16,6 @@ const Uploader = ({
helpText = 'Drag and drop some files here, or click to select files',
height = '10em',
accept = {},
canCrop = true,
}: UploaderProps) => {
const {
handleAddFile,
Expand Down Expand Up @@ -89,16 +87,14 @@ const Uploader = ({
>
Remove
</SecondaryButton>
<When condition={canCrop}>
<PrimaryButton
onClick={() => {
setCropModalOpen(true);
}}
size="small"
>
Crop
</PrimaryButton>
</When>
<PrimaryButton
onClick={() => {
setCropModalOpen(true);
}}
size="small"
>
Crop
</PrimaryButton>
</Stack>
</Grid>
</Grid>
Expand Down
12 changes: 6 additions & 6 deletions met-web/src/components/imageUpload/cropModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ import { Box } from '@mui/system';
import getCroppedImg from './cropImage';
import { blobToFile } from 'utils';

export const CropModal = () => {
interface CropModalProps {
cropText?: string;
}

export const CropModal = ({ cropText }: CropModalProps) => {
const {
existingImageUrl,
addedImageFileUrl,
Expand Down Expand Up @@ -92,11 +96,7 @@ export const CropModal = () => {
>
<Grid container direction="row" alignItems="flex-start" justifyContent="flex-start" spacing={2}>
<Grid item xs={12}>
<MetDescription>
The image will be cropped at the correct ratio to display as a banner on MET. You
can zoom in or out and move the image around. Please note that part of the image
could be hidden depending on the display size.
</MetDescription>
<MetDescription>{cropText}</MetDescription>
</Grid>
<Grid item xs={12} container justifyContent="flex-end">
<PrimaryButton
Expand Down
7 changes: 4 additions & 3 deletions met-web/src/components/imageUpload/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ interface UploaderProps {
cropAspectRatio?: number;
accept?: Accept;
canCrop?: boolean;
cropText?: string;
}
export const ImageUpload = ({
margin = 2,
Expand All @@ -23,12 +24,12 @@ export const ImageUpload = ({
helpText = 'Drag and drop an image here, or click to select an image from your device. Formats accepted are: jpg, png, webp.',
height = '10em',
cropAspectRatio = 1,
cropText = '',
accept = {
'image/jpeg': [],
'image/png': [],
'image/webp': [],
},
canCrop = true,
}: UploaderProps) => {
return (
<ImageUploadContextProvider
Expand All @@ -37,8 +38,8 @@ export const ImageUpload = ({
savedImageName={savedImageName}
cropAspectRatio={cropAspectRatio}
>
<Uploader margin={margin} helpText={helpText} height={height} accept={accept} canCrop={canCrop} />
<CropModal />
<Uploader margin={margin} helpText={helpText} height={height} accept={accept} />
<CropModal cropText={cropText} />
</ImageUploadContextProvider>
);
};
Expand Down
Loading
Loading