import csv step 1

This commit is contained in:
Sidney Alcantara
2020-10-26 10:33:30 +11:00
parent d5a0fbda2c
commit 554dc3ff3a
14 changed files with 341 additions and 28 deletions

View File

@@ -15,7 +15,7 @@ import { APP_BAR_HEIGHT } from "components/Navigation";
import { useFiretableContext } from "contexts/firetableContext";
import ColumnMenu from "./ColumnMenu";
import ImportWizard from "components/Wizards/ImportWizard";
import ImportCSV from "./TableHeader/ImportCSV";
import ImportCSV from "./TableHeader/ImportCsv";
const useStyles = makeStyles((theme) =>
createStyles({

View File

@@ -7,7 +7,7 @@ import VisibilityOffIcon from "@material-ui/icons/VisibilityOff";
import MultiSelect from "@antlerengineering/multiselect";
import ButtonWithStatus from "components/ButtonWithStatus";
import Column from "components/Wizards/ImportWizard/Column";
import Column from "components/Wizards/Column";
import { useFiretableContext } from "contexts/firetableContext";
import { useAppContext } from "contexts/appContext";

View File

@@ -96,7 +96,7 @@ const selectedColumnsReducer = (doc: any) => (
}
};
export default function ExportCSV() {
export default function ExportCsv() {
const classes = useStyles();
const [open, setOpen] = useState(false);

View File

@@ -24,9 +24,13 @@ import TabPanel from "@material-ui/lab/TabPanel";
import ImportIcon from "assets/icons/Import";
import FileUploadIcon from "assets/icons/FileUpload";
import AttachmentIcon from "@material-ui/icons/AttachFile";
import CheckIcon from "@material-ui/icons/CheckCircle";
import GoIcon from "assets/icons/Go";
import ImportCsvWizard, {
IImportCsvWizardProps,
} from "components/Wizards/ImportCsvWizard";
const useStyles = makeStyles((theme) =>
createStyles({
button: {
@@ -76,22 +80,23 @@ const useStyles = makeStyles((theme) =>
})
);
export interface IImportCSVProps {
export interface IImportCsvProps {
render?: (
onClick: (event: React.MouseEvent<HTMLButtonElement>) => void
) => React.ReactNode;
}
export default function ImportCSV({ render }: IImportCSVProps) {
export default function ImportCsv({ render }: IImportCsvProps) {
const classes = useStyles();
const [open, setOpen] = useState<HTMLButtonElement | null>(null);
const [tab, setTab] = useState("upload");
const [csvData, setCsvData] = useState<{
columns: string[];
rows: string[][];
} | null>(null);
const [csvData, setCsvData] = useState<IImportCsvWizardProps["csvData"]>(
null
);
const [error, setError] = useState("");
const validCsv =
csvData !== null && csvData?.columns.length > 0 && csvData?.rows.length > 0;
const handleOpen = (event: React.MouseEvent<HTMLButtonElement>) =>
setOpen(event.currentTarget);
@@ -152,6 +157,8 @@ export default function ImportCSV({ render }: IImportCSVProps) {
});
}, 1000);
const [openWizard, setOpenWizard] = useState(false);
return (
<>
{render ? (
@@ -218,11 +225,17 @@ export default function ImportCSV({ render }: IImportCSVProps) {
) : (
<>
<Grid item>
<FileUploadIcon color="inherit" />
{validCsv ? (
<CheckIcon color="inherit" />
) : (
<FileUploadIcon color="inherit" />
)}
</Grid>
<Grid item>
<Typography variant="overline" color="inherit">
Click to upload or drop CSV file here
{validCsv
? "Valid CSV"
: "Click to upload or drop CSV file here"}
</Typography>
</Grid>
</>
@@ -277,16 +290,49 @@ export default function ImportCSV({ render }: IImportCSVProps) {
<Button
endIcon={<GoIcon />}
disabled={
csvData === null ||
csvData?.columns.length === 0 ||
csvData?.rows.length === 0
}
disabled={!validCsv}
className={classes.continueButton}
onClick={() => setOpenWizard(true)}
>
Continue
</Button>
</Popover>
<ImportCsvWizard
// open={openWizard}
setOpen={setOpenWizard}
// csvData={csvData}
open
csvData={{
columns: [
"Title",
"Show On Fusion",
"Datastudio Link",
"Fusion Section",
],
rows: [
["Events Data", "NO", "", "/events/global"],
[
"Antler Global Key Statistics",
"NO",
"https://datastudio.google.com/embed/reporting/14x4t3K_8pwhsdPN27gQlgykMBOJtsm16/page/sq7VB",
"/employees",
],
[
"Program Resource Usage Stats",
"YES",
"https://datastudio.google.com/embed/reporting/709aea8c-db5a-451f-88c5-51485b8ece63/page/p6veB",
"/resources/program",
],
[
"Founder Stats",
"YES",
"https://datastudio.google.com/embed/reporting/1Ka1xm1OhrZU6BtfMQB0hGtLdgfZeH-nQ/page/oXEBB",
"/cohort/founders",
],
],
}}
/>
</>
);
}

View File

@@ -14,8 +14,8 @@ import { isCollectionGroup } from "util/fns";
import AddRowIcon from "assets/icons/AddRow";
import Filters from "../Filters";
import ImportCSV from "./ImportCSV";
import ExportCSV from "./ExportCSV";
import ImportCSV from "./ImportCsv";
import ExportCSV from "./ExportCsv";
import TableSettings from "./TableSettings";
import { DRAWER_COLLAPSED_WIDTH } from "components/SideDrawer";

View File

@@ -0,0 +1,154 @@
import React, { useState, useEffect } from "react";
import MultiSelect from "@antlerengineering/multiselect";
import _find from "lodash/find";
import {
makeStyles,
createStyles,
Grid,
Typography,
Divider,
FormControlLabel,
Checkbox,
} from "@material-ui/core";
import ArrowIcon from "@material-ui/icons/ArrowForward";
import { IStepProps } from ".";
import FadeList from "../FadeList";
import Column from "../Column";
import EmptyState from "components/EmptyState";
import AddColumnIcon from "assets/icons/AddColumn";
import { useFiretableContext } from "contexts/firetableContext";
const useStyles = makeStyles((theme) =>
createStyles({
csvListItem: { display: "flex" },
csvColumn: {},
formControlLabel: {
marginRight: 0,
flex: 1,
},
columnLabel: { flex: 1 },
arrowGridItem: {
width: theme.spacing(7),
display: "flex",
alignItems: "center",
justifyContent: "center",
},
})
);
export default function Step1Columns({
csvData,
config,
updateConfig,
isXs,
}: IStepProps) {
const classes = useStyles();
const { tableState } = useFiretableContext();
const tableColumns = Object.values(
tableState?.columns ?? {}
).map((column) => ({ label: column.name, value: column.key }));
const [selectedFields, setSelectedFields] = useState(
config.pairs.map((pair) => pair.csvKey)
);
const handleSelect = (field: string) => (_, checked: boolean) => {
if (checked) {
setSelectedFields((x) => [...x, field]);
} else {
const newValue = [...selectedFields];
newValue.splice(newValue.indexOf(field), 1);
setSelectedFields(newValue);
}
};
const handleChange = (csvKey: string) => (columnKey: string) =>
updateConfig({ pairs: [{ csvKey, columnKey }] });
return (
<>
<Grid container spacing={7}>
{!isXs && (
<Grid item xs={12} sm={6}>
<Typography variant="overline" gutterBottom component="h2">
Select Columns ({config.pairs.length} of {csvData.columns.length})
</Typography>
</Grid>
)}
<Grid item xs={12} sm={6}>
<Typography variant="overline" gutterBottom component="h2">
Firetable Columns
</Typography>
</Grid>
</Grid>
<Divider />
<FadeList>
{csvData.columns.map((field) => {
const selected = selectedFields.indexOf(field) > -1;
const ftColumnKey =
_find(config.pairs, { csvKey: field })?.columnKey ?? null;
const matchingColumn = ftColumnKey
? tableState?.columns[ftColumnKey]
: null;
return (
<Grid container key={field} component="li" wrap="nowrap">
<Grid item xs>
<FormControlLabel
key={field}
control={
<Checkbox
checked={selected}
aria-label={`Select column ${field}`}
onChange={handleSelect(field)}
color="default"
/>
}
label={<Column label={field} className={classes.csvColumn} />}
classes={{
root: classes.formControlLabel,
label: classes.columnLabel,
}}
/>
</Grid>
<Grid item className={classes.arrowGridItem}>
<ArrowIcon color={selected ? "action" : "disabled"} />
</Grid>
<Grid item xs>
{selected && (
<MultiSelect
multiple={false}
options={tableColumns}
value={ftColumnKey}
onChange={handleChange(field) as any}
TextFieldProps={{
hiddenLabel: true,
SelectProps: {
renderValue: (_) => {
if (!ftColumnKey) return "Select or add column";
else return matchingColumn.name;
},
},
}}
clearable={false}
displayEmpty
/>
)}
</Grid>
</Grid>
);
})}
</FadeList>
</>
);
}

View File

@@ -0,0 +1,113 @@
import React, { useState, useEffect } from "react";
import _merge from "lodash/merge";
import { useTheme, useMediaQuery, Typography } from "@material-ui/core";
import WizardDialog from "../WizardDialog";
import Step1Columns from "./Step1Columns";
import { ColumnConfig } from "hooks/useFiretable/useTableConfig";
import { useFiretableContext } from "contexts/firetableContext";
export type CsvConfig = {
pairs: { csvKey: string; columnKey: string }[];
newColumns: string[];
};
export interface IStepProps {
csvData: NonNullable<IImportCsvWizardProps["csvData"]>;
config: CsvConfig;
setConfig: React.Dispatch<React.SetStateAction<CsvConfig>>;
updateConfig: (value: Partial<ColumnConfig>) => void;
isXs: boolean;
}
export interface IImportCsvWizardProps {
open: boolean;
setOpen: React.Dispatch<React.SetStateAction<boolean>>;
csvData: {
columns: string[];
rows: string[][];
} | null;
}
export default function ImportCsvWizard({
open,
setOpen,
csvData,
}: IImportCsvWizardProps) {
const theme = useTheme();
const isXs = useMediaQuery(theme.breakpoints.down("xs"));
const { tableState, tableActions } = useFiretableContext();
const [config, setConfig] = useState<CsvConfig>({
pairs: [],
newColumns: [],
});
const updateConfig: IStepProps["updateConfig"] = (value) => {
setConfig((prev) => ({ ..._merge(prev, value) }));
};
useEffect(() => {
if (!tableState || !open) return;
if (Array.isArray(tableState.filters) && tableState.filters?.length > 0)
tableActions!.table.filter([]);
if (Array.isArray(tableState.orderBy) && tableState.orderBy?.length > 0)
tableActions!.table.orderBy([]);
}, [open, tableState]);
if (tableState?.rows.length === 0) return null;
const handleFinish = () => {
tableActions?.table.updateConfig("columns", config);
setOpen(false);
};
if (!csvData) return null;
return (
<WizardDialog
open={open}
onClose={() => setOpen(false)}
title="Import CSV"
steps={[
{
title: "choose columns",
description: "Select which columns to import to your table.",
content: (
<Step1Columns
csvData={csvData}
config={config}
setConfig={setConfig}
updateConfig={updateConfig}
isXs={isXs}
/>
),
disableNext: Object.keys(config).length === 0,
},
{
title: "rename columns",
description:
"Rename your Firetable columns with user-friendly names. These changes will not update the field names in your database.",
content: <div>Step2Rename</div>,
},
{
title: "set column types",
description:
"Set the type of each column to display your data correctly. Some column types have been suggested based off your data.",
content: <div>Step3Types</div>,
},
{
title: "preview",
description:
"Preview your data with your configured columns. You can change column types by clicking “Edit Type” from the column menu at any time.",
content: <div>Step4Preview</div>,
},
]}
onFinish={handleFinish}
/>
);
}

View File

@@ -21,8 +21,8 @@ import {
import DragHandleIcon from "@material-ui/icons/DragHandle";
import { IStepProps } from ".";
import FadeList from "./FadeList";
import Column from "./Column";
import FadeList from "../FadeList";
import Column from "../Column";
import EmptyState from "components/EmptyState";
import AddColumnIcon from "assets/icons/AddColumn";

View File

@@ -15,8 +15,8 @@ import EditIcon from "@material-ui/icons/Edit";
import DoneIcon from "@material-ui/icons/Done";
import { IStepProps } from ".";
import FadeList from "./FadeList";
import Column from "./Column";
import FadeList from "../FadeList";
import Column from "../Column";
const useStyles = makeStyles((theme) =>
createStyles({

View File

@@ -11,9 +11,9 @@ import {
import ChevronRightIcon from "@material-ui/icons/ChevronRight";
import { IStepProps } from ".";
import FadeList from "./FadeList";
import Column from "./Column";
import Cell from "./Cell";
import FadeList from "../FadeList";
import Column from "../Column";
import Cell from "../Cell";
import FieldsDropdown from "components/Table/ColumnMenu/FieldsDropdown";
import { useFiretableContext } from "contexts/firetableContext";

View File

@@ -4,8 +4,8 @@ import { ScrollSync, ScrollSyncPane } from "react-scroll-sync";
import { makeStyles, createStyles, Grid } from "@material-ui/core";
import { IStepProps } from ".";
import Column from "./Column";
import Cell from "./Cell";
import Column from "../Column";
import Cell from "../Cell";
import { useFiretableContext } from "contexts/firetableContext";