Container.tsx 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. import { makeStyles, Theme } from '@material-ui/core';
  2. import { FC, useContext, useMemo, useState } from 'react';
  3. import { useTranslation } from 'react-i18next';
  4. import DialogTemplate from '../customDialog/DialogTemplate';
  5. import icons from '../icons/Icons';
  6. import { rootContext } from '../../context/Root';
  7. import InsertImport from './Import';
  8. import InsertPreview from './Preview';
  9. import InsertStatus from './Status';
  10. import {
  11. InsertContentProps,
  12. InsertStatusEnum,
  13. InsertStepperEnum,
  14. } from './Types';
  15. import { Option } from '../customSelector/Types';
  16. import { parse } from 'papaparse';
  17. const getStyles = makeStyles((theme: Theme) => ({
  18. icon: {
  19. fontSize: '16px',
  20. },
  21. }));
  22. /**
  23. * this component contains processes during insert
  24. * all datas and methods passed in as props, no interactions with server done in it
  25. */
  26. const InsertContainer: FC<InsertContentProps> = ({
  27. collections,
  28. selectedCollection,
  29. partitions,
  30. selectedPartition,
  31. schema,
  32. handleInsert,
  33. }) => {
  34. const classes = getStyles();
  35. // props children component needed:
  36. const collectionOptions: Option[] = collections.map(c => ({
  37. label: c._name,
  38. value: c._name,
  39. }));
  40. const partitionOptions: Option[] = partitions.map(p => ({
  41. label: p._name,
  42. value: p._name,
  43. }));
  44. const schemaOptions: Option[] = schema.map(s => ({
  45. label: s._fieldName,
  46. value: s._fieldId,
  47. }));
  48. const { t: insertTrans } = useTranslation('insert');
  49. const { t: btnTrans } = useTranslation('btn');
  50. const { handleCloseDialog, openSnackBar } = useContext(rootContext);
  51. const [activeStep, setActiveStep] = useState<InsertStepperEnum>(
  52. InsertStepperEnum.import
  53. );
  54. const [insertStatus, setInsertStauts] = useState<InsertStatusEnum>(
  55. InsertStatusEnum.init
  56. );
  57. // const [nextDisabled, setNextDisabled] = useState<boolean>(false);
  58. const [collectionValue, setCollectionValue] =
  59. useState<string>(selectedCollection);
  60. const [partitionValue, setPartitionValue] =
  61. useState<string>(selectedPartition);
  62. // use contain field names yes as default
  63. const [isContainFieldNames, setIsContainFieldNames] = useState<number>(1);
  64. const [fileName, setFileName] = useState<string>('');
  65. const BackIcon = icons.back;
  66. const { confirm, cancel } = useMemo(() => {
  67. /**
  68. * activeStep type is InsertStepperEnum
  69. * so index 0 represents import,
  70. * index 1 represents preview,
  71. * index 2 represents status
  72. */
  73. const labelList = [
  74. {
  75. confirm: btnTrans('next'),
  76. cancel: btnTrans('cancel'),
  77. },
  78. {
  79. confirm: btnTrans('insert'),
  80. cancel: (
  81. <>
  82. <BackIcon classes={{ root: classes.icon }} />
  83. {btnTrans('previous')}
  84. </>
  85. ),
  86. },
  87. {
  88. confirm: btnTrans('done'),
  89. cancel: '',
  90. },
  91. ];
  92. return labelList[activeStep];
  93. }, [activeStep, btnTrans, BackIcon, classes.icon]);
  94. const { showActions, showCancel } = useMemo(() => {
  95. return {
  96. showActions: insertStatus !== InsertStatusEnum.loading,
  97. showCancel: insertStatus === InsertStatusEnum.init,
  98. };
  99. }, [insertStatus]);
  100. const checkUploadFileValidation = (fieldNamesLength: number): boolean => {
  101. // return schemaOptions.length === fieldNamesLength;
  102. return true;
  103. };
  104. const handleUploadedData = (csv: string) => {
  105. // use !! to convert number(0 or 1) to boolean
  106. const { data } = parse(csv, { header: !!isContainFieldNames });
  107. const uploadFieldNamesLength = !!isContainFieldNames
  108. ? data.length
  109. : (data as string[])[0].length;
  110. const validation = checkUploadFileValidation(uploadFieldNamesLength);
  111. if (!validation) {
  112. // open snackbar
  113. openSnackBar(insertTrans('uploadFieldNamesLenWarning'), 'error');
  114. // reset filename
  115. setFileName('');
  116. return;
  117. }
  118. };
  119. const handleInsertData = () => {
  120. // mock status change
  121. setInsertStauts(InsertStatusEnum.loading);
  122. handleInsert();
  123. setTimeout(() => {
  124. setInsertStauts(InsertStatusEnum.success);
  125. }, 500);
  126. };
  127. const handleNext = () => {
  128. switch (activeStep) {
  129. case InsertStepperEnum.import:
  130. setActiveStep(activeStep => activeStep + 1);
  131. break;
  132. case InsertStepperEnum.preview:
  133. setActiveStep(activeStep => activeStep + 1);
  134. handleInsertData();
  135. break;
  136. // default represent InsertStepperEnum.status
  137. default:
  138. handleCloseDialog();
  139. break;
  140. }
  141. };
  142. const handleBack = () => {
  143. switch (activeStep) {
  144. case InsertStepperEnum.import:
  145. handleCloseDialog();
  146. break;
  147. case InsertStepperEnum.preview:
  148. setActiveStep(activeStep => activeStep - 1);
  149. break;
  150. // default represent InsertStepperEnum.status
  151. // status don't have cancel button
  152. default:
  153. break;
  154. }
  155. };
  156. const generateContent = (activeStep: InsertStepperEnum) => {
  157. switch (activeStep) {
  158. case InsertStepperEnum.import:
  159. return (
  160. <InsertImport
  161. collectionOptions={collectionOptions}
  162. partitionOptions={partitionOptions}
  163. selectedCollection={collectionValue}
  164. selectedPartition={partitionValue}
  165. isContainFieldNames={isContainFieldNames}
  166. handleCollectionChange={setCollectionValue}
  167. handlePartitionChange={setPartitionValue}
  168. handleIsContainedChange={setIsContainFieldNames}
  169. handleUploadedData={handleUploadedData}
  170. fileName={fileName}
  171. setFileName={setFileName}
  172. />
  173. );
  174. case InsertStepperEnum.preview:
  175. return <InsertPreview schemaOptions={schemaOptions} />;
  176. // default represents InsertStepperEnum.status
  177. default:
  178. return <InsertStatus status={insertStatus} />;
  179. }
  180. };
  181. return (
  182. <DialogTemplate
  183. title={insertTrans('import')}
  184. handleClose={handleCloseDialog}
  185. confirmLabel={confirm}
  186. cancelLabel={cancel}
  187. handleCancel={handleBack}
  188. handleConfirm={handleNext}
  189. confirmDisabled={false}
  190. showActions={showActions}
  191. showCancel={showCancel}
  192. >
  193. {generateContent(activeStep)}
  194. </DialogTemplate>
  195. );
  196. };
  197. export default InsertContainer;