mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-20 23:00:34 +00:00
feat: wip import resource UI
This commit is contained in:
@@ -42,7 +42,7 @@ export class ImportController extends BaseController {
|
|||||||
this.asyncMiddleware(this.mapping.bind(this)),
|
this.asyncMiddleware(this.mapping.bind(this)),
|
||||||
this.catchServiceErrors
|
this.catchServiceErrors
|
||||||
);
|
);
|
||||||
router.post(
|
router.get(
|
||||||
'/:import_id/preview',
|
'/:import_id/preview',
|
||||||
this.asyncMiddleware(this.preview.bind(this)),
|
this.asyncMiddleware(this.preview.bind(this)),
|
||||||
this.catchServiceErrors
|
this.catchServiceErrors
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { Ref, useCallback } from 'react';
|
||||||
import clsx from 'classnames';
|
import clsx from 'classnames';
|
||||||
import {
|
import {
|
||||||
Accept,
|
Accept,
|
||||||
@@ -226,6 +227,7 @@ export const Dropzone = (_props: DropzoneProps) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const isIdle = !isDragAccept && !isDragReject;
|
const isIdle = !isDragAccept && !isDragReject;
|
||||||
|
assignRef(openRef, open);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropzoneProvider
|
<DropzoneProvider
|
||||||
@@ -264,3 +266,26 @@ Dropzone.displayName = '@mantine/dropzone/Dropzone';
|
|||||||
Dropzone.Accept = DropzoneAccept;
|
Dropzone.Accept = DropzoneAccept;
|
||||||
Dropzone.Idle = DropzoneIdle;
|
Dropzone.Idle = DropzoneIdle;
|
||||||
Dropzone.Reject = DropzoneReject;
|
Dropzone.Reject = DropzoneReject;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
type PossibleRef<T> = Ref<T> | undefined;
|
||||||
|
|
||||||
|
export function assignRef<T>(ref: PossibleRef<T>, value: T) {
|
||||||
|
if (typeof ref === 'function') {
|
||||||
|
ref(value);
|
||||||
|
} else if (typeof ref === 'object' && ref !== null && 'current' in ref) {
|
||||||
|
(ref as React.MutableRefObject<T>).current = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mergeRefs<T>(...refs: PossibleRef<T>[]) {
|
||||||
|
return (node: T | null) => {
|
||||||
|
refs.forEach((ref) => assignRef(ref, node));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useMergedRef<T>(...refs: PossibleRef<T>[]) {
|
||||||
|
return useCallback(mergeRefs(...refs), refs);
|
||||||
|
}
|
||||||
@@ -30,7 +30,7 @@ export function Stack(props: StackProps) {
|
|||||||
const StackStyled = styled(Box)`
|
const StackStyled = styled(Box)`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: align;
|
align-items: ${(props: StackProps) => props.align};
|
||||||
justify-content: justify;
|
justify-content: justify;
|
||||||
gap: ${(props: StackProps) => props.spacing}px;
|
gap: ${(props: StackProps) => props.spacing}px;
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -81,8 +81,8 @@ export function Stepper({
|
|||||||
active > _children.length - 1 ? completedContent : stepContent;
|
active > _children.length - 1 ? completedContent : stepContent;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box className={classNames?.root}>
|
||||||
<StepsItems>{items}</StepsItems>
|
<StepsItems className={classNames?.items}>{items}</StepsItems>
|
||||||
<StepsContent className={classNames?.content}>{content} </StepsContent>
|
<StepsContent className={classNames?.content}>{content} </StepsContent>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,42 +1,20 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import { Button } from '@blueprintjs/core';
|
|
||||||
import { Field } from 'formik';
|
import { Field } from 'formik';
|
||||||
import { Box, Group, Icon, Stack } from '@/components';
|
import { Box, Group, Stack } from '@/components';
|
||||||
import { Dropzone } from '@/components/Dropzone';
|
|
||||||
import { MIME_TYPES } from '@/components/Dropzone/mine-types';
|
|
||||||
import styles from './ImportDropzone.module.css';
|
import styles from './ImportDropzone.module.css';
|
||||||
|
import { ImportDropzoneField } from './ImportDropzoneFile';
|
||||||
|
|
||||||
export function ImportDropzone() {
|
export function ImportDropzone() {
|
||||||
return (
|
return (
|
||||||
<Stack spacing={0}>
|
<Stack spacing={0}>
|
||||||
<Field id={'file'} name={'file'} type="file">
|
<Field id={'file'} name={'file'} type="file">
|
||||||
{({ form: { setFieldValue } }) => (
|
{({ form }) => (
|
||||||
<Dropzone
|
<ImportDropzoneField
|
||||||
onDrop={(files) => setFieldValue('file', files[0])}
|
value={form.file}
|
||||||
onReject={(files) => console.log('rejected files', files)}
|
onChange={(file) => {
|
||||||
maxSize={5 * 1024 ** 2}
|
form.setFieldValue('file', file);
|
||||||
accept={[MIME_TYPES.csv, MIME_TYPES.xls, MIME_TYPES.xlsx]}
|
}}
|
||||||
classNames={{ content: styles.dropzoneContent }}
|
/>
|
||||||
>
|
|
||||||
<Stack spacing={10} className={styles.content}>
|
|
||||||
<Box className={styles.iconWrap}>
|
|
||||||
<Icon icon="download" iconSize={26} />
|
|
||||||
</Box>
|
|
||||||
<Stack spacing={4}>
|
|
||||||
<h4 className={styles.title}>
|
|
||||||
Drag images here or click to select files
|
|
||||||
</h4>
|
|
||||||
<span className={styles.subtitle}>
|
|
||||||
Drag and Drop file here or Choose file
|
|
||||||
</span>
|
|
||||||
</Stack>
|
|
||||||
<Box>
|
|
||||||
<Button intent="none" minimal outlined>
|
|
||||||
Upload File
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
</Stack>
|
|
||||||
</Dropzone>
|
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
|
|||||||
80
packages/webapp/src/containers/Import/ImportDropzoneFile.tsx
Normal file
80
packages/webapp/src/containers/Import/ImportDropzoneFile.tsx
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
import { useRef } from 'react';
|
||||||
|
import { Button, Intent } from '@blueprintjs/core';
|
||||||
|
import { Box, Icon, Stack } from '@/components';
|
||||||
|
import { Dropzone, DropzoneProps } from '@/components/Dropzone';
|
||||||
|
import { MIME_TYPES } from '@/components/Dropzone/mine-types';
|
||||||
|
import styles from './ImportDropzone.module.css';
|
||||||
|
import { useUncontrolled } from '@/hooks/useUncontrolled';
|
||||||
|
|
||||||
|
interface ImportDropzoneFieldProps {
|
||||||
|
initialValue?: File;
|
||||||
|
value?: File;
|
||||||
|
onChange?: (file: File) => void;
|
||||||
|
dropzoneProps?: DropzoneProps;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ImportDropzoneField({
|
||||||
|
initialValue,
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
dropzoneProps,
|
||||||
|
}: ImportDropzoneFieldProps) {
|
||||||
|
const [localValue, handleChange] = useUncontrolled({
|
||||||
|
value,
|
||||||
|
initialValue,
|
||||||
|
finalValue: null,
|
||||||
|
onChange,
|
||||||
|
});
|
||||||
|
const openRef = useRef<() => void>(null);
|
||||||
|
|
||||||
|
const handleRemove = () => {
|
||||||
|
handleChange(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dropzone
|
||||||
|
onDrop={(files) => handleChange(files[0])}
|
||||||
|
onReject={(files) => console.log('rejected files', files)}
|
||||||
|
maxSize={5 * 1024 ** 2}
|
||||||
|
accept={[MIME_TYPES.csv, MIME_TYPES.xls, MIME_TYPES.xlsx]}
|
||||||
|
classNames={{ content: styles.dropzoneContent }}
|
||||||
|
activateOnClick={false}
|
||||||
|
openRef={openRef}
|
||||||
|
{...dropzoneProps}
|
||||||
|
>
|
||||||
|
<Stack spacing={12} align="center" className={styles.content}>
|
||||||
|
<Box className={styles.iconWrap}>
|
||||||
|
<Icon icon="download" iconSize={26} />
|
||||||
|
</Box>
|
||||||
|
{localValue ? (
|
||||||
|
<Stack spacing={6} justify="center" align="center">
|
||||||
|
<h4 className={styles.title}>{localValue.name}</h4>
|
||||||
|
<Button small minimal intent={Intent.DANGER} onClick={handleRemove}>
|
||||||
|
Remove
|
||||||
|
</Button>
|
||||||
|
</Stack>
|
||||||
|
) : (
|
||||||
|
<Stack spacing={4} align="center">
|
||||||
|
<h4 className={styles.title}>
|
||||||
|
Drag images here or click to select files
|
||||||
|
</h4>
|
||||||
|
<span className={styles.subtitle}>
|
||||||
|
Drag and Drop file here or Choose file
|
||||||
|
</span>
|
||||||
|
</Stack>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Button
|
||||||
|
intent="none"
|
||||||
|
onClick={() => openRef.current?.()}
|
||||||
|
style={{ pointerEvents: 'all' }}
|
||||||
|
minimal
|
||||||
|
outlined
|
||||||
|
>
|
||||||
|
{localValue ? 'Replace File' : 'Upload File'}
|
||||||
|
</Button>
|
||||||
|
</Stack>
|
||||||
|
</Dropzone>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
|
||||||
|
.root{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import styles from './ImportFileUploadStep.module.scss';
|
||||||
|
|
||||||
|
interface ImportFileContainerProps {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ImportFileContainer({ children }: ImportFileContainerProps) {
|
||||||
|
return <div className={styles.content}>{children}</div>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
import clsx from 'classnames';
|
||||||
|
import { Group } from '@/components';
|
||||||
|
import { CLASSES } from '@/constants';
|
||||||
|
import { Button, Intent } from '@blueprintjs/core';
|
||||||
|
import { useFormikContext } from 'formik';
|
||||||
|
import styles from './ImportFileActions.module.scss';
|
||||||
|
import { useImportFileContext } from './ImportFileProvider';
|
||||||
|
|
||||||
|
export function ImportFileUploadFooterActions() {
|
||||||
|
const { isSubmitting } = useFormikContext();
|
||||||
|
const { setStep } = useImportFileContext();
|
||||||
|
|
||||||
|
const handleCancelBtnClick = () => {};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={clsx(CLASSES.PAGE_FORM_FLOATING_ACTIONS, styles.root)}>
|
||||||
|
<Group spacing={10}>
|
||||||
|
<Button onClick={handleCancelBtnClick}>Cancel</Button>
|
||||||
|
<Button type="submit" intent={Intent.PRIMARY} loading={isSubmitting}>
|
||||||
|
Next
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,6 +1,11 @@
|
|||||||
.table {
|
.table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-top: 1.8rem;
|
margin-top: 1.4rem;
|
||||||
|
|
||||||
|
th.label,
|
||||||
|
td.label{
|
||||||
|
width: 32% !important;
|
||||||
|
}
|
||||||
|
|
||||||
thead{
|
thead{
|
||||||
th{
|
th{
|
||||||
@@ -8,14 +13,19 @@
|
|||||||
padding-top: 8px;
|
padding-top: 8px;
|
||||||
padding-bottom: 8px;
|
padding-bottom: 8px;
|
||||||
color: #738091;
|
color: #738091;
|
||||||
}
|
font-weight: 500;
|
||||||
th.label{
|
|
||||||
width: 32%;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tbody{
|
tbody{
|
||||||
tr td {
|
tr td {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tr td{
|
||||||
|
:global(.bp4-popover-target .bp4-button){
|
||||||
|
max-width: 250px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,32 +1,36 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import clsx from 'classnames';
|
import clsx from 'classnames';
|
||||||
|
import { Button, Intent } from '@blueprintjs/core';
|
||||||
|
import { useFormikContext } from 'formik';
|
||||||
import { FSelect, Group } from '@/components';
|
import { FSelect, Group } from '@/components';
|
||||||
import { ImportFileMappingForm } from './ImportFileMappingForm';
|
import { ImportFileMappingForm } from './ImportFileMappingForm';
|
||||||
import { useImportFileContext } from './ImportFileProvider';
|
import { useImportFileContext } from './ImportFileProvider';
|
||||||
import styles from './ImportFileMapping.module.scss';
|
|
||||||
import { CLASSES } from '@/constants';
|
import { CLASSES } from '@/constants';
|
||||||
import { Button, Intent } from '@blueprintjs/core';
|
import { ImportFileContainer } from './ImportFileContainer';
|
||||||
import { useFormikContext } from 'formik';
|
import styles from './ImportFileMapping.module.scss';
|
||||||
|
import { ImportStepperStep } from './_types';
|
||||||
|
|
||||||
export function ImportFileMapping() {
|
export function ImportFileMapping() {
|
||||||
return (
|
return (
|
||||||
<ImportFileMappingForm>
|
<ImportFileMappingForm>
|
||||||
<p>
|
<ImportFileContainer>
|
||||||
Review and map the column headers in your csv/xlsx file with the
|
<p>
|
||||||
Bigcapital fields.
|
Review and map the column headers in your csv/xlsx file with the
|
||||||
</p>
|
Bigcapital fields.
|
||||||
|
</p>
|
||||||
|
|
||||||
<table className={clsx('bp4-html-table', styles.table)}>
|
<table className={clsx('bp4-html-table', styles.table)}>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th className={'label'}>Bigcapital Fields</th>
|
<th className={styles.label}>Bigcapital Fields</th>
|
||||||
<th className={'field'}>Sheet Column Headers</th>
|
<th className={styles.field}>Sheet Column Headers</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<ImportFileMappingFields />
|
<ImportFileMappingFields />
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
</ImportFileContainer>
|
||||||
|
|
||||||
<ImportFileMappingFloatingActions />
|
<ImportFileMappingFloatingActions />
|
||||||
</ImportFileMappingForm>
|
</ImportFileMappingForm>
|
||||||
@@ -43,14 +47,14 @@ function ImportFileMappingFields() {
|
|||||||
|
|
||||||
const columns = entityColumns.map((column, index) => (
|
const columns = entityColumns.map((column, index) => (
|
||||||
<tr key={index}>
|
<tr key={index}>
|
||||||
<td className={'label'}>{column.name}</td>
|
<td className={styles.label}>{column.name}</td>
|
||||||
<td className={'field'}>
|
<td className={styles.field}>
|
||||||
<FSelect
|
<FSelect
|
||||||
name={column.key}
|
name={column.key}
|
||||||
items={items}
|
items={items}
|
||||||
fill
|
popoverProps={{ minimal: true }}
|
||||||
popoverProps={{ minimal: false }}
|
minimal={true}
|
||||||
minimal={false}
|
fill={true}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -60,14 +64,19 @@ function ImportFileMappingFields() {
|
|||||||
|
|
||||||
function ImportFileMappingFloatingActions() {
|
function ImportFileMappingFloatingActions() {
|
||||||
const { isSubmitting } = useFormikContext();
|
const { isSubmitting } = useFormikContext();
|
||||||
|
const { setStep } = useImportFileContext();
|
||||||
|
|
||||||
|
const handleCancelBtnClick = () => {
|
||||||
|
setStep(ImportStepperStep.Upload);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}>
|
<div className={clsx(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}>
|
||||||
<Group>
|
<Group spacing={10}>
|
||||||
|
<Button onClick={handleCancelBtnClick}>Cancel</Button>
|
||||||
<Button type="submit" intent={Intent.PRIMARY} loading={isSubmitting}>
|
<Button type="submit" intent={Intent.PRIMARY} loading={isSubmitting}>
|
||||||
Next
|
Next
|
||||||
</Button>
|
</Button>
|
||||||
<Button>Cancel</Button>
|
|
||||||
</Group>
|
</Group>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import { Button, Callout, Intent, Text } from '@blueprintjs/core';
|
import { Button, Callout, Intent, Text } from '@blueprintjs/core';
|
||||||
import clsx from 'classnames';
|
import clsx from 'classnames';
|
||||||
|
import { useHistory } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
ImportFilePreviewBootProvider,
|
ImportFilePreviewBootProvider,
|
||||||
useImportFilePreviewBootContext,
|
useImportFilePreviewBootContext,
|
||||||
@@ -9,7 +10,7 @@ import { useImportFileContext } from './ImportFileProvider';
|
|||||||
import { AppToaster, Card, Group } from '@/components';
|
import { AppToaster, Card, Group } from '@/components';
|
||||||
import { useImportFileProcess } from '@/hooks/query/import';
|
import { useImportFileProcess } from '@/hooks/query/import';
|
||||||
import { CLASSES } from '@/constants';
|
import { CLASSES } from '@/constants';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { ImportStepperStep } from './_types';
|
||||||
|
|
||||||
export function ImportFilePreview() {
|
export function ImportFilePreview() {
|
||||||
const { importId } = useImportFileContext();
|
const { importId } = useImportFileContext();
|
||||||
@@ -81,7 +82,7 @@ function ImportFilePreviewContent() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function ImportFilePreviewFloatingActions() {
|
function ImportFilePreviewFloatingActions() {
|
||||||
const { importId } = useImportFileContext();
|
const { importId, setStep } = useImportFileContext();
|
||||||
const { importPreview } = useImportFilePreviewBootContext();
|
const { importPreview } = useImportFilePreviewBootContext();
|
||||||
const { mutateAsync: importFile, isLoading: isImportFileLoading } =
|
const { mutateAsync: importFile, isLoading: isImportFileLoading } =
|
||||||
useImportFileProcess();
|
useImportFileProcess();
|
||||||
@@ -102,9 +103,14 @@ function ImportFilePreviewFloatingActions() {
|
|||||||
})
|
})
|
||||||
.catch((error) => {});
|
.catch((error) => {});
|
||||||
};
|
};
|
||||||
|
const handleCancelBtnClick = () => {
|
||||||
|
setStep(ImportStepperStep.Mapping);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}>
|
<div className={clsx(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}>
|
||||||
<Group>
|
<Group spacing={10}>
|
||||||
|
<Button onClick={handleCancelBtnClick}>Cancel</Button>
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
intent={Intent.PRIMARY}
|
intent={Intent.PRIMARY}
|
||||||
@@ -114,7 +120,6 @@ function ImportFilePreviewFloatingActions() {
|
|||||||
>
|
>
|
||||||
Import
|
Import
|
||||||
</Button>
|
</Button>
|
||||||
<Button>Cancel</Button>
|
|
||||||
</Group>
|
</Group>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Intent } from '@blueprintjs/core';
|
|||||||
import { Formik, Form, FormikHelpers } from 'formik';
|
import { Formik, Form, FormikHelpers } from 'formik';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
import { useImportFileContext } from './ImportFileProvider';
|
import { useImportFileContext } from './ImportFileProvider';
|
||||||
|
import { ImportStepperStep } from './_types';
|
||||||
|
|
||||||
const initialValues = {
|
const initialValues = {
|
||||||
file: null,
|
file: null,
|
||||||
@@ -22,9 +23,14 @@ interface ImportFileUploadValues {
|
|||||||
file: File | null;
|
file: File | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ImportFileUploadForm({ children }: ImportFileUploadFormProps) {
|
export function ImportFileUploadForm({
|
||||||
|
children,
|
||||||
|
formikProps,
|
||||||
|
formProps,
|
||||||
|
}: ImportFileUploadFormProps) {
|
||||||
const { mutateAsync: uploadImportFile } = useImportFileUpload();
|
const { mutateAsync: uploadImportFile } = useImportFileUpload();
|
||||||
const { setStep, setSheetColumns, setEntityColumns, setImportId } = useImportFileContext();
|
const { setStep, setSheetColumns, setEntityColumns, setImportId } =
|
||||||
|
useImportFileContext();
|
||||||
|
|
||||||
const handleSubmit = (
|
const handleSubmit = (
|
||||||
values: ImportFileUploadValues,
|
values: ImportFileUploadValues,
|
||||||
@@ -42,7 +48,7 @@ export function ImportFileUploadForm({ children }: ImportFileUploadFormProps) {
|
|||||||
setImportId(data.import.import_id);
|
setImportId(data.import.import_id);
|
||||||
setSheetColumns(data.sheet_columns);
|
setSheetColumns(data.sheet_columns);
|
||||||
setEntityColumns(data.resource_columns);
|
setEntityColumns(data.resource_columns);
|
||||||
setStep(1);
|
setStep(ImportStepperStep.Mapping);
|
||||||
setSubmitting(false);
|
setSubmitting(false);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@@ -55,8 +61,9 @@ export function ImportFileUploadForm({ children }: ImportFileUploadFormProps) {
|
|||||||
initialValues={initialValues}
|
initialValues={initialValues}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
validationSchema={validationSchema}
|
validationSchema={validationSchema}
|
||||||
|
{...formikProps}
|
||||||
>
|
>
|
||||||
<Form>{children}</Form>
|
<Form {...formProps}>{children}</Form>
|
||||||
</Formik>
|
</Formik>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
.root {
|
||||||
|
margin-top: 2.2rem
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
flex: 1;
|
||||||
|
padding: 32px 20px;
|
||||||
|
min-width: 660px;
|
||||||
|
max-width: 760px;
|
||||||
|
width: 75%;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form {
|
||||||
|
}
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
.root {
|
|
||||||
margin-top: 2.2rem
|
|
||||||
}
|
|
||||||
@@ -1,40 +1,26 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import clsx from 'classnames';
|
import { Stack } from '@/components';
|
||||||
import { Group, Stack } from '@/components';
|
|
||||||
import { ImportDropzone } from './ImportDropzone';
|
import { ImportDropzone } from './ImportDropzone';
|
||||||
import { ImportSampleDownload } from './ImportSampleDownload';
|
import { ImportSampleDownload } from './ImportSampleDownload';
|
||||||
import { CLASSES } from '@/constants';
|
|
||||||
import { Button, Intent } from '@blueprintjs/core';
|
|
||||||
import { ImportFileUploadForm } from './ImportFileUploadForm';
|
import { ImportFileUploadForm } from './ImportFileUploadForm';
|
||||||
import { useFormikContext } from 'formik';
|
import { ImportFileUploadFooterActions } from './ImportFileFooterActions';
|
||||||
|
import { ImportFileContainer } from './ImportFileContainer';
|
||||||
|
|
||||||
export function ImportFileUploadStep() {
|
export function ImportFileUploadStep() {
|
||||||
return (
|
return (
|
||||||
<ImportFileUploadForm>
|
<ImportFileUploadForm>
|
||||||
<p style={{ marginBottom: 18 }}>
|
<ImportFileContainer>
|
||||||
Download a sample file and compare it to your import file to ensure you
|
<p style={{ marginBottom: 18 }}>
|
||||||
have the file perfect for the import.
|
Download a sample file and compare it to your import file to ensure
|
||||||
</p>
|
you have the file perfect for the import.
|
||||||
|
</p>
|
||||||
|
<Stack spacing={40}>
|
||||||
|
<ImportDropzone />
|
||||||
|
<ImportSampleDownload />
|
||||||
|
</Stack>
|
||||||
|
</ImportFileContainer>
|
||||||
|
|
||||||
<Stack spacing={40}>
|
|
||||||
<ImportDropzone />
|
|
||||||
<ImportSampleDownload />
|
|
||||||
</Stack>
|
|
||||||
<ImportFileUploadFooterActions />
|
<ImportFileUploadFooterActions />
|
||||||
</ImportFileUploadForm>
|
</ImportFileUploadForm>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ImportFileUploadFooterActions() {
|
|
||||||
const { isSubmitting } = useFormikContext();
|
|
||||||
return (
|
|
||||||
<div className={clsx(CLASSES.PAGE_FORM_FLOATING_ACTIONS)}>
|
|
||||||
<Group spacing={10}>
|
|
||||||
<Button type="submit" intent={Intent.PRIMARY} loading={isSubmitting}>
|
|
||||||
Next
|
|
||||||
</Button>
|
|
||||||
<Button>Cancel</Button>
|
|
||||||
</Group>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
.root{
|
.root{
|
||||||
padding: 32px 40px;
|
|
||||||
min-width: 700px;
|
|
||||||
max-width: 800px;
|
|
||||||
width: 75%;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
}
|
||||||
.rootWrap {
|
.rootWrap {
|
||||||
max-width: 1800px;
|
max-width: 1800px;
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import { ImportStepper } from './ImportStepper';
|
import { ImportStepper } from './ImportStepper';
|
||||||
import { Box, DashboardInsider } from '@/components';
|
import { Box, DashboardInsider } from '@/components';
|
||||||
import styles from './ImportPage.module.scss';
|
|
||||||
import { ImportFileProvider } from './ImportFileProvider';
|
import { ImportFileProvider } from './ImportFileProvider';
|
||||||
|
import styles from './ImportPage.module.scss';
|
||||||
|
|
||||||
|
|
||||||
export default function ImportPage() {
|
export default function ImportPage() {
|
||||||
return (
|
return (
|
||||||
<DashboardInsider>
|
<DashboardInsider>
|
||||||
<Box className={styles.rootWrap}>
|
<Box className={styles.root}>
|
||||||
<Box className={styles.root}>
|
<ImportFileProvider resource="account">
|
||||||
<ImportFileProvider resource="account">
|
<ImportStepper />
|
||||||
<ImportStepper />
|
</ImportFileProvider>
|
||||||
</ImportFileProvider>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
</Box>
|
||||||
</DashboardInsider>
|
</DashboardInsider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,3 +1,18 @@
|
|||||||
.content {
|
.content {
|
||||||
margin-top: 2.4rem;
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
border-top: 1px solid #DCE0E5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.root {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.items {
|
||||||
|
padding: 32px 20px;
|
||||||
|
min-width: 660px;
|
||||||
|
max-width: 760px;
|
||||||
|
width: 75%;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
}
|
}
|
||||||
@@ -2,16 +2,22 @@
|
|||||||
|
|
||||||
import { Stepper } from '@/components/Stepper';
|
import { Stepper } from '@/components/Stepper';
|
||||||
import { ImportFileUploadStep } from './ImportFileUploadStep';
|
import { ImportFileUploadStep } from './ImportFileUploadStep';
|
||||||
import styles from './ImportStepper.module.scss';
|
|
||||||
import { useImportFileContext } from './ImportFileProvider';
|
import { useImportFileContext } from './ImportFileProvider';
|
||||||
import { ImportFileMapping } from './ImportFileMapping';
|
import { ImportFileMapping } from './ImportFileMapping';
|
||||||
import { ImportFilePreview } from './ImportFilePreview';
|
import { ImportFilePreview } from './ImportFilePreview';
|
||||||
|
import styles from './ImportStepper.module.scss';
|
||||||
|
|
||||||
export function ImportStepper() {
|
export function ImportStepper() {
|
||||||
const { step } = useImportFileContext();
|
const { step } = useImportFileContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stepper active={step} classNames={{ content: styles.content }}>
|
<Stepper
|
||||||
|
active={step}
|
||||||
|
classNames={{
|
||||||
|
content: styles.content,
|
||||||
|
items: styles.items,
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Stepper.Step label={'File Upload'}>
|
<Stepper.Step label={'File Upload'}>
|
||||||
<ImportFileUploadStep />
|
<ImportFileUploadStep />
|
||||||
</Stepper.Step>
|
</Stepper.Step>
|
||||||
|
|||||||
5
packages/webapp/src/containers/Import/_types.ts
Normal file
5
packages/webapp/src/containers/Import/_types.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export enum ImportStepperStep {
|
||||||
|
Upload = 0,
|
||||||
|
Mapping = 1,
|
||||||
|
Preview = 2,
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user