Skip to content

Commit

Permalink
Merge pull request #70 from globalfund/feat/DE-959
Browse files Browse the repository at this point in the history
DE-959: Table component visual implementation
  • Loading branch information
stephanoshadjipetrou authored Mar 28, 2024
2 parents b0ca01b + dfd1341 commit 1d29bef
Show file tree
Hide file tree
Showing 15 changed files with 1,340 additions and 31 deletions.
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

0 comments on commit 1d29bef

Please sign in to comment.