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

Fixes FileUpload comments #1612

Merged
merged 9 commits into from
Nov 20, 2023
149 changes: 84 additions & 65 deletions src/features/import/components/UploadFile.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,77 @@
import { alpha } from '@mui/material/styles';
import { makeStyles } from '@mui/styles';
import { UploadFileOutlined } from '@mui/icons-material';
import { useDropzone } from 'react-dropzone';
import {
Box,
Button,
CircularProgress,
IconButton,
Link,
Typography,
useTheme,
} from '@mui/material';
import { useCallback, useState } from 'react';
import { CSSProperties, useCallback, useState } from 'react';

import messageIds from '../l10n/messageIds';
import theme from 'theme';
import useImportedFile from '../hooks/useImportedFile';
import { Msg, useMessages } from 'core/i18n';

const sharedProperties: CSSProperties = {
alignItems: 'center',
borderRadius: 4,
borderWidth: 2,
display: 'flex',
flexDirection: 'column',
flexWrap: 'wrap',
margin: 16,
padding: 50,
textAlign: 'center',
};

const useStyles = makeStyles((theme) => ({
errorState: {
backgroundColor: alpha(
theme.palette.statusColors.red,
theme.palette.action.selectedOpacity
),
borderColor: theme.palette.error.dark,
borderStyle: 'solid',
...sharedProperties,
},
initialState: {
backgroundColor: 'transparent',
borderColor: theme.palette.grey[300],
borderStyle: 'dashed',
...sharedProperties,
},
loadingState: {
backgroundColor: alpha(
theme.palette.statusColors.blue,
theme.palette.action.selectedOpacity
),
borderColor: theme.palette.statusColors.blue,
borderStyle: 'dashed',
...sharedProperties,
},
sharedProperties: {
...sharedProperties,
},
}));

const UploadFile = () => {
const [error, setError] = useState<boolean>(false);
const messages = useMessages(messageIds);
const { parseData, loading } = useImportedFile();
const theme = useTheme();
const classes = useStyles(theme);

let boxClass = classes.initialState;
if (error) {
boxClass = classes.errorState;
} else if (loading) {
boxClass = classes.loadingState;
}

const onDrop = useCallback((acceptedFiles: File[]): void => {
acceptedFiles.map((file: File) => {
Expand All @@ -42,60 +96,29 @@ const UploadFile = () => {

return (
<>
<Box
{...getRootProps()}
p={12}
style={
loading
? {
alignItems: 'center',
backgroundColor: '#1976D214',
borderColor: '#1976D2',
borderRadius: 4,
borderStyle: 'dashed',
borderWidth: 2,
display: 'flex',
flexDirection: 'column',
flexWrap: 'wrap',
margin: 16,
textAlign: 'center',
}
: {
alignItems: 'center',
backgroundColor: error ? '#fdf7f7' : 'transparent',
borderColor: error ? theme.palette.error.dark : '#E0E0E0',
borderRadius: 4,
borderStyle: error ? 'solid' : 'dashed',
borderWidth: 2,
display: 'flex',
flexDirection: 'column',
flexWrap: 'wrap',
margin: 16,
textAlign: 'center',
}
}
>
<Box {...getRootProps()} className={boxClass}>
{loading && (
<Box>
<CircularProgress sx={{ color: '#1976D2' }} />
<Typography>{messages.uploadDialog.loading()}</Typography>
<CircularProgress sx={{ color: theme.palette.statusColors.blue }} />
<Typography sx={{ color: theme.palette.text.primary }}>
{messages.uploadDialog.loading()}
</Typography>
</Box>
)}
<input type="file" {...getInputProps()} />
<Box>
{!loading && (
<Box>
<>
<IconButton
onClick={open}
style={{
backgroundColor: '#E0E0E0',
sx={{
backgroundColor: theme.palette.grey[300],
borderRadius: 100,
cursor: 'pointer',
height: 40,
padding: 30,
width: 40,
height: '40px',
padding: '30px',
width: '40px',
}}
type="button"
>
<UploadFileOutlined
sx={{ color: theme.palette.primary.main, fontSize: 40 }}
Expand All @@ -106,28 +129,25 @@ const UploadFile = () => {
) : (
<>
<Box pt={2}>
<Typography
onClick={open}
sx={{
color: theme.palette.primary.main,
cursor: 'pointer',
display: 'inline-block',
padding: 1,
textDecorationLine: 'underline',
}}
>
{messages.uploadDialog.instructions()}
</Typography>
<Typography
sx={{
display: 'inline-block',
}}
>
{messages.uploadDialog.instructionsEnd()}
<Typography component="span">
{messages.uploadDialog.instructions({
link: (
<Link
onClick={open}
sx={{
color: theme.palette.primary.main,
cursor: 'pointer',
textDecorationLine: 'underline',
}}
>
{messages.uploadDialog.selectClick()}
</Link>
),
})}
</Typography>
</Box>

<Box sx={{ gap: 10 }} />
<Box pt={1} />
{error ? (
<Typography sx={{ color: theme.palette.primary.main }}>
{messages.uploadDialog.unsupportedFile()}
Expand All @@ -139,7 +159,7 @@ const UploadFile = () => {
)}
</>
)}
</Box>
</>
)}
</Box>
</Box>
Expand All @@ -150,7 +170,6 @@ const UploadFile = () => {
color="primary"
onClick={(ev) => {
ev.stopPropagation();

setError(false);
}}
>
Expand Down
20 changes: 9 additions & 11 deletions src/features/import/hooks/useImportedFile.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { addFiles } from '../store';
import { addFile } from '../store';
import { parseExcelFile } from '../utils/parseFile';
import { useAppDispatch } from 'core/hooks';
import { useState } from 'react';
Expand All @@ -8,34 +8,32 @@ export default function useFileImport() {
const [loading, setLoading] = useState(false);
const dispatch = useAppDispatch();

function parseData(file: File) {
async function parseData(file: File) {
setLoading(true);
if (
file.type === 'text/comma-separated-values' ||
file.type === 'text/csv' ||
file.type === 'application/csv'
) {
parseCSVFile(file).then((res) => {
saveData(res);
setLoading(false);
});
const res = await parseCSVFile(file);
saveData(res);
setLoading(false);
} else if (
file.type === 'application/vnd.ms-excel' ||
file.type ===
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ||
file.type === 'application/xls'
) {
parseExcelFile(file).then((res) => {
saveData(res);
setLoading(false);
});
const res = await parseExcelFile(file);
saveData(res);
setLoading(false);
} else {
return null;
}
}

function saveData(data: ImportedFile) {
dispatch(addFiles(data));
dispatch(addFile(data));
}

return { loading, parseData };
Expand Down
5 changes: 3 additions & 2 deletions src/features/import/l10n/messageIds.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ReactJSXElement } from '@emotion/react/types/jsx-namespace';
import { m, makeMessages } from 'core/i18n';

export default makeMessages('feat.import', {
Expand All @@ -19,10 +20,10 @@ export default makeMessages('feat.import', {
configure: m('Configure'),
restart: m('Restart'),
},
instructions: m('Click to upload'),
instructionsEnd: m(' or drag and drop'),
instructions: m<{ link: ReactJSXElement }>('{link} or drag and drop'),
loading: m('Loading file...'),
release: m('Release the file here'),
selectClick: m('Click to upload'),
types: m('CSV, XLS or XLSX'),
unsupportedFile: m('Unsupported file.'),
},
Expand Down
4 changes: 2 additions & 2 deletions src/features/import/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ const importSlice = createSlice({
initialState,
name: 'import',
reducers: {
addFiles: (state, action: PayloadAction<ImportedFile>) => {
addFile: (state, action: PayloadAction<ImportedFile>) => {
const file = action.payload;
state.files.push(file);
},
},
});

export default importSlice;
export const { addFiles } = importSlice.actions;
export const { addFile } = importSlice.actions;
1 change: 1 addition & 0 deletions src/features/views/components/PeopleActionButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const PeopleActionButton: FC<PeopleActionButtonProps> = ({
label={messages.actions.create()}
/>
<Dialog
fullWidth
onClose={() => setUploadDialogOpen(false)}
open={uploadDialogOpen}
>
Expand Down
Loading