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

DE-959: Table component visual implementation #70

Merged
merged 1 commit into from
Mar 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"@mui/styled-engine-sc": "^5.12.0",
"@storybook/addon-themes": "^7.6.17",
"@types/react-router-hash-link": "^2.4.9",
"@types/tabulator-tables": "^5.6.0",
"axios": "^1.4.0",
"dom-to-image": "^2.6.0",
"easy-peasy": "^6.0.1",
Expand All @@ -30,6 +31,7 @@
"react-scripts": "5.0.1",
"react-use": "^17.4.0",
"styled-components": "^6.0.3",
"tabulator-tables": "^6.1.0",
"typescript": "^4.4.2",
"web-vitals": "^2.1.0"
},
Expand Down
11 changes: 11 additions & 0 deletions src/app/assets/vectors/TableToolbarColumns.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions src/app/assets/vectors/TableToolbarDownload.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/app/assets/vectors/TableToolbarFilter.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/app/assets/vectors/TableToolbarFullscreen.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions src/app/assets/vectors/TableToolbarSearch.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
69 changes: 69 additions & 0 deletions src/app/components/table-container/TableContainer.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";

import { TableContainer } from "app/components/table-container";
import { withRouter } from "storybook-addon-react-router-v6";
import {
TABLE_VARIATION_1_DATA,
TABLE_VARIATION_1_COLUMNS,
TABLE_VARIATION_2_DATA,
TABLE_VARIATION_2_COLUMNS,
TABLE_VARIATION_3_DATA,
TABLE_VARIATION_3_COLUMNS,
TABLE_VARIATION_4_DATA,
TABLE_VARIATION_4_COLUMNS,
TABLE_VARIATION_5_DATA,
TABLE_VARIATION_5_COLUMNS,
} from "app/components/table/data";

const Variant2Wrapper = (args: any) => {
const [tab, setTab] = React.useState(args.tabsView?.selectedTab);

return (
<TableContainer
{...args}
tabsView={
args.tabsView && {
...args.tabsView,
selectedTab: tab,
onTabChange: setTab,
}
}
/>
);
};

const meta = {
title: "Components/Table Container",
component: Variant2Wrapper,
decorators: [withRouter],
parameters: {
layout: "fullscreen",
},
tags: ["autodocs"],
argTypes: {},
} satisfies Meta<typeof TableContainer>;

export default meta;
type StoryType = StoryObj<typeof meta>;

export const Variant1: StoryType = {
args: {
dataTree: true,
data: TABLE_VARIATION_1_DATA,
columns: TABLE_VARIATION_1_COLUMNS,
},
};

export const Variant2: StoryType = {
args: {
dataTree: true,
data: TABLE_VARIATION_1_DATA,
columns: TABLE_VARIATION_1_COLUMNS,
tabsView: {
tabs: ["All", "Impact Indicators", "Outcome Indicators"],
selectedTab: "All",
onTabChange: (tab: string) => console.log(tab),
},
},
};
17 changes: 17 additions & 0 deletions src/app/components/table-container/data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { TableProps } from "app/components/table/data";

export interface TableContainerProps extends TableProps {
tabsView?: {
tabs: string[];
selectedTab: string;
onTabChange: (tab: string) => void;
};
}

export const TABLE_CONTAINER_TABS = [
"All",
"Impact Indicators",
"Outcome Indicators",
"Modules & Coverage Indicators",
"Modules & Workplan Tracking Measures",
];
134 changes: 134 additions & 0 deletions src/app/components/table-container/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import React from "react";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import { Table } from "app/components/table";
import IconButton from "@mui/material/IconButton";
import { TabulatorFull as Tabulator } from "tabulator-tables";
import { TableContainerProps } from "app/components/table-container/data";
import { ReactComponent as FilterIcon } from "app/assets/vectors/TableToolbarFilter.svg";
import { ReactComponent as SearchIcon } from "app/assets/vectors/TableToolbarSearch.svg";
import { ReactComponent as ColumnsIcon } from "app/assets/vectors/TableToolbarColumns.svg";
import { ReactComponent as DownloadIcon } from "app/assets/vectors/TableToolbarDownload.svg";
import { ReactComponent as FullscreenIcon } from "app/assets/vectors/TableToolbarFullscreen.svg";

export const TableContainer: React.FC<TableContainerProps> = (
props: TableContainerProps
) => {
const [table, setTable] = React.useState<any>(null);
const fullscreenRef = React.useRef<HTMLDivElement>(null);

React.useEffect(() => {
const element = document.getElementById("table");
if (element) {
const tabulatorTables = Tabulator.findTable("#table");
if (tabulatorTables.length > 0 && tabulatorTables[0]) {
setTable(tabulatorTables[0]);
}
}
}, []);

const download = () => {
if (table) {
table.download("csv", "data.csv");
}
};

const fullscreen = () => {
if (!fullscreenRef.current) {
return;
}
if (document.fullscreenElement) {
document.exitFullscreen();
} else {
fullscreenRef.current.requestFullscreen();
}
};

return (
<Box
gap="24px"
display="flex"
bgcolor="#fff"
borderRadius="32px"
ref={fullscreenRef}
flexDirection="column"
>
{!props.tabsView && (
<Box
gap="8px"
display="flex"
justifyContent="flex-end"
sx={{
"& > button": {
padding: "0px",
},
}}
>
<IconButton disableRipple onClick={fullscreen}>
<FullscreenIcon />
</IconButton>
<IconButton disableRipple>
<ColumnsIcon />
</IconButton>
<IconButton disableRipple>
<FilterIcon />
</IconButton>
<IconButton disableRipple onClick={download}>
<DownloadIcon />
</IconButton>
<IconButton disableRipple>
<SearchIcon />
</IconButton>
</Box>
)}
{props.tabsView && (
<Box
width="100%"
display="flex"
flexDirection="row"
alignItems="center"
justifyContent="space-between"
>
<Box
gap="8px"
display="flex"
flexDirection="row"
alignItems="center"
sx={{
"& > button": {
height: "32px",
fontSize: "14px",
fontWeight: "400",
padding: "0px 24px",
borderRadius: "8px",
textTransform: "none",
"&:hover": {
color: "#fff",
background: "#000",
},
},
}}
>
{props.tabsView.tabs.map((tab) => (
<Button
key={tab}
onClick={() => props.tabsView?.onTabChange(tab)}
sx={{
color: props.tabsView?.selectedTab === tab ? "#fff" : "#000",
background:
props.tabsView?.selectedTab === tab ? "#000" : "#F1F3F4",
}}
>
{tab}
</Button>
))}
</Box>
<IconButton disableRipple>
<SearchIcon />
</IconButton>
</Box>
)}
<Table {...props} />
</Box>
);
};
100 changes: 100 additions & 0 deletions src/app/components/table/Table.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import type { Meta, StoryObj } from "@storybook/react";

import { Table } from "app/components/table";
import { withRouter } from "storybook-addon-react-router-v6";
import {
TABLE_VARIATION_1_DATA,
TABLE_VARIATION_1_COLUMNS,
TABLE_VARIATION_2_DATA,
TABLE_VARIATION_2_COLUMNS,
TABLE_VARIATION_3_DATA,
TABLE_VARIATION_3_COLUMNS,
TABLE_VARIATION_4_DATA,
TABLE_VARIATION_4_COLUMNS,
TABLE_VARIATION_5_DATA,
TABLE_VARIATION_5_COLUMNS,
TABLE_VARIATION_6_DATA,
TABLE_VARIATION_6_COLUMNS,
TABLE_VARIATION_7_DATA,
TABLE_VARIATION_7_COLUMNS,
} from "app/components/table/data";

const meta = {
title: "Components/Table",
component: Table,
decorators: [withRouter],
parameters: {
layout: "fullscreen",
},
tags: ["autodocs"],
argTypes: {},
} satisfies Meta<typeof Table>;

export default meta;
type StoryType = StoryObj<typeof meta>;

export const Variant1: StoryType = {
args: {
dataTree: true,
data: TABLE_VARIATION_1_DATA,
columns: TABLE_VARIATION_1_COLUMNS,
},
};

export const Variant2: StoryType = {
args: {
dataTree: true,
dataTreeBranchElement: false,
data: TABLE_VARIATION_2_DATA,
columns: TABLE_VARIATION_2_COLUMNS.slice(0, 7),
extraColumns: TABLE_VARIATION_2_COLUMNS.slice(
7,
TABLE_VARIATION_2_COLUMNS.length - 1
),
},
};

export const Variant3: StoryType = {
args: {
dataTree: true,
dataTreeBranchElement: false,
data: TABLE_VARIATION_3_DATA,
columns: TABLE_VARIATION_3_COLUMNS,
},
};

export const Variant4: StoryType = {
args: {
dataTree: true,
data: TABLE_VARIATION_4_DATA,
columns: TABLE_VARIATION_4_COLUMNS.slice(0, 1),
extraColumns: TABLE_VARIATION_4_COLUMNS.slice(
1,
TABLE_VARIATION_2_COLUMNS.length - 1
),
},
};

export const Variant5: StoryType = {
args: {
dataTree: true,
data: TABLE_VARIATION_5_DATA,
columns: TABLE_VARIATION_5_COLUMNS,
},
};

export const Variant6: StoryType = {
args: {
dataTree: true,
data: TABLE_VARIATION_6_DATA,
columns: TABLE_VARIATION_6_COLUMNS,
},
};

export const Variant7: StoryType = {
args: {
dataTree: true,
data: TABLE_VARIATION_7_DATA,
columns: TABLE_VARIATION_7_COLUMNS,
},
};
Loading
Loading