Skip to content
This repository has been archived by the owner on Mar 6, 2023. It is now read-only.

Commit

Permalink
feat(enquete): import individuel #1801
Browse files Browse the repository at this point in the history
  • Loading branch information
Toub committed May 18, 2020
1 parent 41ef9e9 commit 6c915cc
Show file tree
Hide file tree
Showing 13 changed files with 350 additions and 20 deletions.
24 changes: 24 additions & 0 deletions packages/app/pages/mandataires/enquetes/import-[id].js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { BoxWrapper } from "@emjpm/ui";
import React, { useContext } from "react";

import { EnqueteImportPanel } from "../../../src/components/EnqueteImport";
import { LayoutMandataire } from "../../../src/components/Layout";
import { UserContext } from "../../../src/components/UserContext";
import { withAuthSync } from "../../../src/util/auth";

const ImportEnquetePage = () => {
const user = useContext(UserContext);
return (
<LayoutMandataire>
<BoxWrapper mt={6} px="1">
<EnqueteImportPanel mandataireUserId={user.id} />
</BoxWrapper>
</LayoutMandataire>
);
};

ImportEnquetePage.getInitialProps = async ({ query }) => {
return { id: Number(query.id) };
};

export default withAuthSync(ImportEnquetePage);
20 changes: 0 additions & 20 deletions packages/app/pages/mandataires/import-mesures.js

This file was deleted.

25 changes: 25 additions & 0 deletions packages/app/src/components/EnqueteImport/DocumentLink.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from "react";
import { Flex } from "rebass";

const DocumentLink = ({ children, document }) => (
<a href={document}>
<Flex
maxWidth="200px"
flexDirection="column"
justifyContent="center"
alignItem="center"
pt={6}
pb={6}
pr={2}
pl={2}
m={2}
sx={{
border: "1px solid"
}}
>
{children}
</Flex>
</a>
);

export { DocumentLink };
25 changes: 25 additions & 0 deletions packages/app/src/components/EnqueteImport/EnqueteImportErrors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Card, Heading3 } from "@emjpm/ui";
import React from "react";
import { Flex, Text } from "rebass";

import { importErrorsWrapperStyle } from "./style";

const EnqueteImportErrors = props => {
const { errors } = props;

return (
<Card sx={importErrorsWrapperStyle} overflow="hidden">
<Heading3 mb={4}>Détail des erreurs par ligne</Heading3>
{errors.map(({ line = 0, message }) => (
<Flex key={`${line}-${message}`} mb={1}>
<Text color="warning" mr={1}>
LIGNE {line}
</Text>
<Text>{message}</Text>
</Flex>
))}
</Card>
);
};

export { EnqueteImportErrors };
58 changes: 58 additions & 0 deletions packages/app/src/components/EnqueteImport/EnqueteImportPanel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { LoaderCircle } from "@styled-icons/boxicons-regular/LoaderCircle";
import React, { Fragment } from "react";
import { Box } from "rebass";

import { EnqueteImportResult } from "./EnqueteImportResult";
import { SingleImportFilePicker } from "./SingleImportFilePicker";
import { useEnqueteImportManager } from "./useEnqueteImportManager.hook";

export const EnqueteImportPanel = ({
// mandataireUserId & serviceId are mutually exclusive
mandataireUserId,
serviceId
}) => {
const {
importEnqueteFile,
importSummary,
importEnqueteFileWithAntennesMap,
reset,
enquetesImportLoading
} = useEnqueteImportManager({
mandataireUserId,
serviceId
});

if (enquetesImportLoading) {
return (
<Box p={4}>
<LoaderCircle size="16" /> Traitement du fichier en cours, veuillez patienter (cela peut
prendre jusqu&apos;à 2mn pour les gros fichiers)...
</Box>
);
}

if (importSummary && !importSummary.unexpectedError) {
return (
<EnqueteImportResult
reset={() => reset()}
importSummary={importSummary}
serviceId={serviceId}
onSubmitAntennesMap={({ antennesMap }) => importEnqueteFileWithAntennesMap(antennesMap)}
/>
);
}

return (
<Fragment>
{importSummary && importSummary.unexpectedError && (
<Box mt={2} mb={2}>
Erreur innatendue. Veuillez ré-essayer.
</Box>
)}
<SingleImportFilePicker
placeholder="Sélectionner votre fichier excel"
onFileChosen={file => importEnqueteFile(file)}
/>
</Fragment>
);
};
37 changes: 37 additions & 0 deletions packages/app/src/components/EnqueteImport/EnqueteImportResult.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Button, Heading2, Text } from "@emjpm/ui";
import React from "react";
import { Flex } from "rebass";

import { EnqueteImportErrors } from "./EnqueteImportErrors";
import { ServiceEnqueteImportResultStyle } from "./style";

const EnqueteImportResult = ({
reset,
importSummary: { creationNumber, updateNumber, errors }
}) => {
return (
<div p={7} sx={ServiceEnqueteImportResultStyle}>
<Flex alignItems="center">
<Flex flexDirection="column">
<Heading2>{`Résultat de l'import`}</Heading2>
{errors.length ? (
<Text m={2} fontSize={2}>{`Erreur lors de l'import des enquetes (${
errors.length
} erreurs sur ${errors.length +
creationNumber +
updateNumber} enquetes). Aucune enquete n'a été importée.`}</Text>
) : (
<Text m={2} fontSize={2}>{`${creationNumber +
updateNumber} enquetes ont été importées (${creationNumber} nouvelles et ${updateNumber} mises à jour).`}</Text>
)}
</Flex>
<Button variant="outline" onClick={reset}>
Sélectionner un autre fichier
</Button>
</Flex>
{!!errors.length && <EnqueteImportErrors errors={errors} />}
</div>
);
};

export { EnqueteImportResult };
34 changes: 34 additions & 0 deletions packages/app/src/components/EnqueteImport/EnqueteImportResults.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Button, Heading2, Text } from "@emjpm/ui";
import React, { Fragment } from "react";
import { Flex } from "rebass";

import { EnqueteImportErrors } from "./EnqueteImportErrors";
import { ServiceEnqueteImportResultStyle } from "./style";

const EnqueteImportResults = props => {
const { errors, enquetes, reset } = props;

return (
<Fragment>
<Flex alignItems="center" p={7} sx={ServiceEnqueteImportResultStyle}>
<Flex flexDirection="column">
<Heading2>{`Résultat de l'import`}</Heading2>
<Text
m={2}
fontSize={2}
>{`${enquetes.length} enquetes vont être importées ou mises à jour. Vous allez recevoir un email dans quelques instants.`}</Text>
<Text
m={2}
fontSize={2}
>{`${errors.length} enquetes ne seront pas importées ou mises à jour. Les erreurs sont indiquées ci-dessous.`}</Text>
</Flex>
<Button variant="outline" onClick={reset}>
Sélectionner un autre fichier
</Button>
</Flex>
{errors.length > 0 && <EnqueteImportErrors errors={errors} />}
</Fragment>
);
};

export { EnqueteImportResults };
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Input } from "@emjpm/ui";
import React from "react";
import { Box } from "rebass";

const SingleImportFilePicker = ({ onFileChosen, placeholder }) => {
return (
<Box mb="2">
<Input
id="file"
type="file"
name="file"
value=""
onChange={event => {
const file = event.currentTarget.files[0];
onFileChosen(file);
}}
placeholder={placeholder}
/>
</Box>
);
};

export { SingleImportFilePicker };
29 changes: 29 additions & 0 deletions packages/app/src/components/EnqueteImport/fileReader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
function readFileAsBinaryString(file, cb, err) {
if (file) {
const reader = new FileReader();

const isExcel = file.name.endsWith(".xls") || file.name.endsWith(".xlsx");

if (isExcel) {
reader.readAsBinaryString(file);
} else {
reader.readAsText(file);
}
reader.onload = () => {
const base64str = btoa(reader.result);
if (cb) {
cb({ base64str, file });
}
};
reader.onerror = () => {
console.error("unable to parse file");
if (err) {
err(new Error("Unable to parse file"));
}
};
}
}

export const fileReader = {
readFileAsBinaryString
};
1 change: 1 addition & 0 deletions packages/app/src/components/EnqueteImport/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { EnqueteImportPanel } from "./EnqueteImportPanel";
23 changes: 23 additions & 0 deletions packages/app/src/components/EnqueteImport/mutations.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import gql from "graphql-tag";

export const UPLOAD_ENQUETES_EXCEL_FILE = gql`
mutation upload_enquetes_file(
$name: String!
$type: String!
$base64str: String!
$antennesMap: String
$serviceId: Int
$mandataireUserId: Int
) {
upload_enquetes_file(
name: $name
type: $type
base64str: $base64str
antennesMap: $antennesMap
serviceId: $serviceId
mandataireUserId: $mandataireUserId
) {
data
}
}
`;
17 changes: 17 additions & 0 deletions packages/app/src/components/EnqueteImport/style.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const ServiceEnqueteImportStyle = {};

const ServiceEnqueteImportResultStyle = {
border: "1px solid",
borderRadius: "3px"
};

const importErrorsWrapperStyle = {
bg: "cardSecondary",
borderRadius: "5px 0 0 5px",
m: "2",
p: "5",
maxHeight: "500px",
overflow: "auto"
};

export { ServiceEnqueteImportStyle, ServiceEnqueteImportResultStyle, importErrorsWrapperStyle };
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { useMutation } from "@apollo/react-hooks";
import { useState } from "react";

import { UPLOAD_ENQUETES_EXCEL_FILE } from "../EnqueteImport/mutations";
import { fileReader } from "./fileReader";

function useEnqueteImportManager({ mandataireUserId, serviceId }) {
const [importSummary, setImportSummary] = useState();
const [uploadFile, { loading: enquetesImportLoading }] = useMutation(UPLOAD_ENQUETES_EXCEL_FILE);

function importEnqueteFile({ file, antennesMap }) {
fileReader.readFileAsBinaryString(file, ({ file, base64str }) => {
const { name, type } = file;
uploadFile({
variables: {
base64str,
name,
serviceId,
antennesMap: antennesMap ? JSON.stringify(antennesMap) : undefined,
type,
mandataireUserId
}
})
.then(
({
data: {
upload_enquetes_file: { data }
}
}) => {
const importSummary = JSON.parse(data);
setImportSummary(importSummary);
}
)
.catch(() => {
setImportSummary({
unexpectedError: true
});
});
});
}

function reset() {
setImportSummary(undefined);
}

return {
importEnqueteFile,
importSummary,
enquetesImportLoading,
reset
};
}

export { useEnqueteImportManager };

0 comments on commit 6c915cc

Please sign in to comment.