Skip to content

Commit

Permalink
Update dependencies and refactor logic to DropzoneInputComponents.hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
GabrielARamosDev committed Jan 30, 2024
1 parent fe6b879 commit db969a7
Show file tree
Hide file tree
Showing 4 changed files with 203 additions and 82 deletions.
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"typescript": "^5.3.3"
},
"peerDependencies": {
"@arandu/laravel-mui-admin": "^0.6.0-alpha.10",
"@arandu/laravel-mui-admin": "^0.6.0-alpha.16",
"@mui/material": "^5.15.3",
"react": "^17.0.2",
"react-dom": "^17.0.2",
Expand Down
224 changes: 147 additions & 77 deletions src/components/DropzoneInputComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import * as React from 'react';
import Dropzone, { Accept } from 'react-dropzone';

import { FormFieldProps, FormState, FormValue } from '@arandu/laravel-mui-admin/lib/types/form';
import { FormFieldProps } from '@arandu/laravel-mui-admin/lib/types/form';
import { dotAccessor } from '@arandu/laravel-mui-admin/lib/support/object';
import { config, Icon, applyFilters, removeFilter, addFilter } from '@arandu/laravel-mui-admin';
import { Icon } from '@arandu/laravel-mui-admin';

import { styled } from '@mui/material/styles';
import Stack from '@mui/material/Stack';
import Grid from '@mui/material/Grid';
import Button from '@mui/material/Button';
import Typography from '@mui/material/Typography';
import FormHelperText from '@mui/material/FormHelperText';

import useTransformSrc from '../hooks/useTransformSrc';

import FileInput from './FileInput';
import useDropzoneInputComponents, { UploadedFile } from './DropzoneInputComponents.hooks';


type DropzoneFieldProps = {
form: FormFieldProps['form'],
Expand All @@ -22,102 +27,167 @@ type DropzoneFieldProps = {
},
};

type Style = { [className: string]: React.CSSProperties };

const styles: Style = {
avatar: {
position: 'relative',
maxWidth: 240,
maxHeight: 240,
},
closeBtn: {
position: 'absolute',
top: -5,
left: -5,
},
};
const FilePreview = styled(Stack)(({ theme }) => ({
position: 'relative',
// maxWidth: 240,
maxHeight: 240,
}));

const RemoveFile = styled(Stack)(({ theme }) => ({
position: 'absolute',
right: 0,
}));

const RemoveImg = styled(Stack)(({ theme }) => ({
position: 'absolute',
top: -5,
left: -5,
}));


export default function DropzoneInputComponent({ form, field }: DropzoneFieldProps) {

const {
handleDownload,
} = useDropzoneInputComponents();

const { state: [ data ], setProp, errors } = form;

const {
name, label,
placeholder = '', uploadId,
multiple = false,
...props
} = field;

const file: string | File | null = dotAccessor(data, name);
const file: string | UploadedFile | null = dotAccessor(data, name);

const transformSrc = useTransformSrc();

const fileSource = typeof file === 'string'
? transformSrc(file, { uploadId })
: (file ? URL.createObjectURL(file) : false);

// React.useEffect(() => {
// const filter = (transfers: FormValue[]) => {
// if (file instanceof DropzoneFile) {
// return [
// ...transfers,
// file,
// ];
// }
// return transfers;
// };

// addFilter('use_form_clone_transfers', filter);

// return () => {
// removeFilter('use_form_clone_transfers', filter);
// };
// }, [name, file]);

const fileSource = !multiple
? (typeof file === 'string'
? transformSrc(file, { uploadId })
: (file ? URL.createObjectURL(file) : false))
: false;

const fieldData = data[name] || [] || null;

const mountFilePreview = (file: string | UploadedFile | null, index: number = 0) => {
const isLocal = typeof file === 'string';
const uploadingNow = file instanceof File;

const useAvatar = uploadId === 'image';

return (
<FilePreview>
{useAvatar && !multiple
? (
<>
<img
alt="avatar"
style={{
width: 163,
height: 163,
backgroundColor: '#e8e8e8',
border: '1px solid #00000033',
borderRadius: '50%',
objectFit: 'cover',
}}
className={`text-center`}
src={fileSource as string}
/>

<RemoveImg onClick={() => setProp(name, null)} >
<Icon name="close" />
</RemoveImg>
</>
)
: (
<Stack flexDirection="row" justifyContent="space-between" >
<Typography>
{`• ${isLocal
? file
: file?.name
}`}
</Typography>

<Grid>
<Stack flexDirection="row" gap={1} >
{!uploadingNow && (
<Button
variant="outlined"
size="small"
onClick={() => handleDownload(file, isLocal)}
sx={{ minWidth: 24, p: 0 }}
>
<Icon name="download" />
</Button>
)}

<Button
variant="outlined"
size="small"
onClick={() => {
const filesToDrop = multiple
? (fieldData as File[]).filter((_, i) => i !== index)
: null;

setProp(name, filesToDrop);
}}
sx={{ minWidth: 24, p: 0 }}
>
<Icon name="close" />
</Button>
</Stack>
</Grid>
</Stack>
)
}
</FilePreview>
);
};

return (
<Stack display="flex">
{fileSource
? (
<Stack sx={styles.avatar}>
<img
alt="avatar"
style={{
width: 163,
height: 163,
backgroundColor: '#e8e8e8',
border: '1px solid #00000033',
borderRadius: '50%',
objectFit: 'cover',
{fileSource && !multiple
? mountFilePreview(file)
: (
<>
<Dropzone
onDrop={(acceptedFiles) => {
const filesToDrop = multiple
? [
...(fieldData as File[]),
...acceptedFiles,
]
: acceptedFiles[0];

setProp(name, filesToDrop);
}}
className={`text-center`}
src={fileSource}
/>

<Typography
sx={styles.closeBtn}
onClick={() => setProp(name, null)}
maxFiles={multiple ? 10 : 1}
{...props}
>
<Icon name="close" />
</Typography>
</Stack>
) : (
<Dropzone
onDrop={(acceptedFiles) => {

const file = acceptedFiles[0];

setProp(name, file);
}}
maxFiles={1}
{...props}
>
{(inputProps) => (
<FileInput
placeholder={placeholder}
{...inputProps}
/>
{(inputProps) => (
<FileInput
placeholder={placeholder}
{...inputProps}
/>
)}
</Dropzone>

{multiple && (
<Stack sx={{ my: 1 }} gap={1} >
{(fieldData as UploadedFile[])
.map((file: UploadedFile | null, index: number) => (
<React.Fragment key={index} >
{mountFilePreview(file, index)}
</React.Fragment>
))
}
</Stack>
)}
</Dropzone>
</>
)
}

Expand Down
51 changes: 51 additions & 0 deletions src/components/DropzoneInputComponents.hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@

import React from 'react';

import axios from 'axios';

import { route, useDownloadBlob } from '@arandu/laravel-mui-admin';


export type UploadedFile = {
filename: string,
download_blob: BlobPart,
[key: string]: any,
} & File;


export default function useDropzoneInputComponents() {

const handleDownload = async (
file: string | UploadedFile | null,
isLocal: boolean,
folder: string = 'files',
) => {
if (isLocal) {
window.open(`/storage/files/${file}` as string);
} else {
const filename = (file as UploadedFile).filename.split('.')[0];

const response = await axios({
url: route('api.file.download', { folder, filename }),
method: 'GET',
responseType: 'blob',
});

const fileBlob = new Blob([response.data]);

console.log({
filename,
fileBlob,
});

// useDownloadBlob(
// fileBlob,
// filename,
// );
}
};

return {
handleDownload,
};
};

0 comments on commit db969a7

Please sign in to comment.