Skip to content

Commit

Permalink
More work on media
Browse files Browse the repository at this point in the history
  • Loading branch information
CarsonF committed Sep 26, 2023
1 parent a5f47eb commit 8e3f4f4
Show file tree
Hide file tree
Showing 7 changed files with 267 additions and 237 deletions.
31 changes: 17 additions & 14 deletions src/components/form/Dropzone.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Clear as ClearIcon } from '@mui/icons-material';
import {
Box,
IconButton,
List,
ListItem,
Expand All @@ -12,20 +13,19 @@ import { ReactNode } from 'react';
import { useDropzone } from 'react-dropzone';
import { makeStyles } from 'tss-react/mui';
import { Except } from 'type-fest';
import { extendSx, StyleProps } from '../../common';
import { fileIcon } from '../files/fileTypes';
import { FieldConfig, useField } from './useField';

const useStyles = makeStyles()(({ palette, spacing }) => {
const useStyles = makeStyles()(({ palette, spacing, shape }) => {
const dropzoneHoverStyle = {
backgroundColor: palette.grey[200],
// backgroundColor: palette.grey[200],
borderColor: palette.primary.main,
};
return {
root: {
marginBottom: spacing(2),
},
dropzone: {
backgroundColor: palette.grey[300],
borderRadius: shape.borderRadius,
// backgroundColor: palette.grey[300],
border: `2px dashed ${palette.divider}`,
cursor: 'pointer',
padding: spacing(3),
Expand All @@ -42,17 +42,20 @@ const useStyles = makeStyles()(({ palette, spacing }) => {
};
});

export type DropzoneFieldProps = Except<FieldConfig<File, true>, 'multiple'> & {
label?: ReactNode;
multiple?: boolean;
className?: string;
};
export type DropzoneFieldProps = Except<FieldConfig<File, true>, 'multiple'> &
StyleProps & {
label?: ReactNode;
multiple?: boolean;
disableFileList?: boolean;
};

export function DropzoneField({
multiple = false,
label = 'Click or drag files here',
name: nameProp,
className,
sx,
disableFileList,
}: DropzoneFieldProps) {
const { classes, cx } = useStyles();

Expand Down Expand Up @@ -91,7 +94,7 @@ export function DropzoneField({
});

return (
<div className={cx(classes.root, className)}>
<Box sx={[{ mb: 2 }, ...extendSx(sx)]} className={className}>
<div
className={cx(classes.dropzone, {
[classes.active]: isDragActive,
Expand All @@ -103,7 +106,7 @@ export function DropzoneField({
{label}
</Typography>
</div>
{currentFiles.length > 0 && (
{!disableFileList && currentFiles.length > 0 && (
<List dense className={classes.files}>
{currentFiles.map((file, index) => {
const { name, type } = file;
Expand All @@ -129,6 +132,6 @@ export function DropzoneField({
})}
</List>
)}
</div>
</Box>
);
}
106 changes: 97 additions & 9 deletions src/scenes/ProgressReports/EditForm/Steps/Media/MediaInfoForm.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,114 @@
import { AddPhotoAlternate } from '@mui/icons-material';
import { Box, TextField } from '@mui/material';
import { ProgressReportMediaCategory } from '~/api/schema.graphql';
import { useMemo } from 'react';
import {
ProgressReportMediaCategory as Category,
Sensitivity,
} from '~/api/schema.graphql';
import {
ProgressReportMediaCategoryLabels,
ProgressReportMediaCategoryList,
} from '~/api/schema/enumLists';
import { labelFrom } from '~/common';
import { Form, FormProps, SelectField } from '~/components/form';
import { VariantFragment } from '~/common/fragments';
import {
DropzoneField,
Form,
FormProps,
SelectField,
SubmitAction,
} from '~/components/form';
import { SensitivityIcon } from '../../../../../components/Sensitivity';
import { ProgressReportMediaFragment } from './progressReportMedia.graphql';

export interface MediaFormState {
category: ProgressReportMediaCategory | null;
caption: string | null;
interface MediaFormState extends SubmitAction<'delete'> {
variant: VariantFragment;
id?: string;
newFile?: File[];
category?: Category | null;
caption?: string | null;
}
export const MediaInfoForm = ({ ...formValues }: FormProps<MediaFormState>) => {

export type MediaInfoFormProps = Omit<
FormProps<MediaFormState>,
'initialValues'
> & {
sensitivity: Sensitivity;
variant: VariantFragment;
existingMedia?: ProgressReportMediaFragment;
};

export const MediaInfoForm = ({
existingMedia,
sensitivity,
variant,
...props
}: MediaInfoFormProps) => {
const initialValues = useMemo(
() => ({
variant,
id: existingMedia?.id,
category: existingMedia?.category,
caption: existingMedia?.media.caption,
}),
[variant, existingMedia]
);

return (
<Form<MediaFormState> {...formValues}>
<Form<MediaFormState> autoSubmit {...props} initialValues={initialValues}>
{({ handleSubmit, values }) => (
<Box
sx={{ p: 1, m: 1, flexGrow: 2 }}
onSubmit={handleSubmit}
component="form"
onSubmit={handleSubmit}
sx={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 2 }}
>
{/* TODO Maybe only use for first upload */}
<DropzoneField
name="newFile"
disableFileList
sx={{
gridRow: '1 / 3',
mt: 1,
mb: 0,
display: 'flex',
flexDirection: 'column',
'> *': {
flex: 1,

display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
position: 'relative',
}}
label={
<>
{existingMedia ? (
<Box
component="img"
src={existingMedia.media.file.url}
crossOrigin="use-credentials"
sx={{ width: 1 }}
/>
) : (
<>
<AddPhotoAlternate sx={{ height: 48, width: 48 }} />
<div>Click or drop to add photo</div>
</>
)}
<SensitivityIcon
value={sensitivity}
sx={{
position: 'absolute',
top: '2px',
left: '2px',
bgcolor: 'background.paper',
borderRadius: 1,
}}
/>
</>
}
/>
<SelectField
label="Photo Category"
name="category"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ mutation DeleteMedia($deleteProgressReportMediaId: ID!) {

fragment mediaStep on ProgressReport {
id
media {
sensitivity
media(input: { sort: "variant", order: DESC }) {
items {
...progressReportMedia
}
Expand Down
126 changes: 60 additions & 66 deletions src/scenes/ProgressReports/EditForm/Steps/Media/MediaStep.tsx
Original file line number Diff line number Diff line change
@@ -1,84 +1,78 @@
import { useMutation } from '@apollo/client';
import { Box, Typography } from '@mui/material';
import { Fragment } from 'react';
import { useDropzone } from 'react-dropzone';
import { useUploadFileAsync } from '~/components/files/hooks';
import { DropOverlay } from '~/components/Upload/DropOverlay';
import { StepComponent } from '../step.types';
import { VariantAccordion } from '../VariantAccordion';
import { MediaInfoForm, MediaInfoFormProps } from './MediaInfoForm';
import { CreateMediaDocument, DeleteMediaDocument } from './MediaStep.graphql';
import { VariantMediaAccordion } from './VariantMediaAccordion';
import { FormProps } from "~/components/form";
import { MediaFormState } from "~/scenes/ProgressReports/EditForm/Steps/Media/MediaInfoForm";

// TODO find types for actual uploadVariant here
export interface MediaVariantResponse {
item: any[];
uploadVariant: any;
}
export const MediaStep: StepComponent = ({ report }) => {
const [createMedia] = useMutation(CreateMediaDocument);
const [deleteMedia] = useMutation(DeleteMediaDocument);
const uploadFile = useUploadFileAsync();

const handleSubmit: FormProps<MediaFormState>["onSubmit"] = async (values) => {
// use values.id to determine if we want to create, update, delete
// delete = values.id + submitAction
const [uploadedImageInfo, finalizeUpload] = await uploadFile(values);
if (!uploadedImageInfo) {
finalizeUpload.tap;
return;
const handleSubmit: MediaInfoFormProps['onSubmit'] = async (values) => {
if (values.submitAction === 'delete') {
if (!values.id) {
return;
}
await deleteMedia({
variables: {
deleteProgressReportMediaId: values.id,
},
});
}
await createMedia({
variables: {
input: {
file: uploadedImageInfo,
reportId: report.id,
variant: 'published',

if (!values.id) {
if (!values.newFile || values.newFile.length === 0) {
return;
}
const [uploadedImageInfo, finalizeUpload] = await uploadFile(
values.newFile[0]
);
await createMedia({
variables: {
input: {
reportId: report.id,
file: uploadedImageInfo!,
variant: values.variant.key,
},
},
},
}).then(...finalizeUpload.tap);
}).then(...finalizeUpload.tap);
}
};

const {
getRootProps,
getInputProps,
isDragActive,
open: openFileBrowser,
} = useDropzone({
onDrop: handleFileUpload,
noClick: true,
noKeyboard: true,
disabled: false,
});

return (
<div {...getRootProps()}>
<Box sx={{ maxWidth: 'md' }}>
<Typography variant="h3" gutterBottom>
Upload an image to go with your Report
</Typography>
{report.media.uploadableVariants
.slice()
.reverse()
.map((variant) => {
return (
<Fragment key={variant.key}>
<VariantMediaAccordion
deleteMedia={deleteMedia}
openFileBrowser={openFileBrowser}
response={{
item: report.media.items.filter(
(item) => item.variant.key === variant.key
),
uploadVariant: variant,
}}
sensitivity={report.parent.sensitivity}
initiallyOpen={false}
/>
</Fragment>
);
})}
</Box>
</div>
<Box sx={{ maxWidth: 'md' }}>
<Typography variant="h3" paragraph>
Upload an image to go with your Report
</Typography>
{/* TODO merge lists */}
{report.media.items.map((media) => (
<VariantAccordion variant={media.variant} key={media.id}>
<MediaInfoForm
variant={media.variant}
sensitivity={report.sensitivity}
existingMedia={media}
onSubmit={handleSubmit}
/>
</VariantAccordion>
))}
{report.media.uploadableVariants
.slice()
.reverse()
.map((variant) => {
return (
<VariantAccordion variant={variant} key={variant.key}>
<MediaInfoForm
variant={variant}
sensitivity={report.sensitivity}
existingMedia={undefined}
onSubmit={handleSubmit}
/>
</VariantAccordion>
);
})}
</Box>
);
};
Loading

0 comments on commit 8e3f4f4

Please sign in to comment.