From f4c76a6023c8f317fb0c329937c88c9981a5e09b Mon Sep 17 00:00:00 2001 From: Guk Hum Jaeson Cho Date: Mon, 19 Jun 2023 19:30:33 +0800 Subject: [PATCH 01/10] test --- src/components/NewComponent/NewComponent.jsx | 9 +++++++++ src/components/NewComponent/index.js | 2 ++ src/components/NewComponent/index.stories.js | 14 ++++++++++++++ 3 files changed, 25 insertions(+) create mode 100644 src/components/NewComponent/NewComponent.jsx create mode 100644 src/components/NewComponent/index.js create mode 100644 src/components/NewComponent/index.stories.js diff --git a/src/components/NewComponent/NewComponent.jsx b/src/components/NewComponent/NewComponent.jsx new file mode 100644 index 0000000..17a08a6 --- /dev/null +++ b/src/components/NewComponent/NewComponent.jsx @@ -0,0 +1,9 @@ +import React from 'react' + +function NewComponent({title}) { + return ( +
NewComponent {title}
+ ) +} + +export default NewComponent \ No newline at end of file diff --git a/src/components/NewComponent/index.js b/src/components/NewComponent/index.js new file mode 100644 index 0000000..ecfd277 --- /dev/null +++ b/src/components/NewComponent/index.js @@ -0,0 +1,2 @@ +import {NewComponent} from "./NewComponent" +export {NewComponent}; \ No newline at end of file diff --git a/src/components/NewComponent/index.stories.js b/src/components/NewComponent/index.stories.js new file mode 100644 index 0000000..9e09ff7 --- /dev/null +++ b/src/components/NewComponent/index.stories.js @@ -0,0 +1,14 @@ +import React from 'react' +import {NewComponent} from "." + +const NewComponentStory = { + title: "title", + component: NewComponent +} + +export const DefaultStory =({...args}) => { + +} + +export const Default = DefaultStory.bind({}); +export default NewComponentStory \ No newline at end of file From cc7e8cbfb84d1c0b8ed9d3f6ab217c2b56866030 Mon Sep 17 00:00:00 2001 From: Guk Hum Jaeson Cho Date: Mon, 19 Jun 2023 19:32:34 +0800 Subject: [PATCH 02/10] test --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6ad470b..9b1715b 100644 --- a/package.json +++ b/package.json @@ -166,7 +166,7 @@ "main": "index.js", "repository": { "type": "git", - "url": "git+ssh://git@bitbucket.org/zennya/web-component-library.git" + "url": "git+ssh://git@bitbucket.org/zennya/web-component-library.git?sha=f4c76a6023c8f317fb0c329937c88c9981a5e09b" }, "author": "", "license": "ISC", From 27b73f0c09329887bda96d675af9535898d763dc Mon Sep 17 00:00:00 2001 From: Guk Hum Jaeson Cho Date: Mon, 26 Jun 2023 17:21:05 +0800 Subject: [PATCH 03/10] ZI-14121 adding auto detection of filter based on column parameters --- src/components/NewComponent/GridStyles.scss | 11 + src/components/NewComponent/NewComponent.jsx | 489 ++++++++++++++++++- src/components/NewComponent/index.js | 2 +- src/components/NewComponent/index.stories.js | 38 +- 4 files changed, 533 insertions(+), 7 deletions(-) create mode 100644 src/components/NewComponent/GridStyles.scss diff --git a/src/components/NewComponent/GridStyles.scss b/src/components/NewComponent/GridStyles.scss new file mode 100644 index 0000000..b176773 --- /dev/null +++ b/src/components/NewComponent/GridStyles.scss @@ -0,0 +1,11 @@ +@import "ag-grid-community/src/styles/ag-grid.scss"; +@import "ag-grid-community/src/styles/ag-theme-alpine/sass/ag-theme-alpine-mixin.scss"; + +.ag-theme-alpine { + @include ag-theme-alpine(( + odd-row-background-color: #eceef1, + )); + } +.ag-root-wrapper { + border-radius: 20px +} diff --git a/src/components/NewComponent/NewComponent.jsx b/src/components/NewComponent/NewComponent.jsx index 17a08a6..e5cd8c0 100644 --- a/src/components/NewComponent/NewComponent.jsx +++ b/src/components/NewComponent/NewComponent.jsx @@ -1,8 +1,491 @@ -import React from 'react' +import React, {useState, useEffect, useRef, useCallback, useMemo} from 'react' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faSort , faSortUp, faSortDown, faPlus, faBars, faFilter, faThumbtack,faEyeSlash } from '@fortawesome/free-solid-svg-icons'; +import SearchIcon from '@mui/icons-material/Search'; +import { render } from 'react-dom'; +import { AgGridColumn, AgGridReact } from 'ag-grid-react'; +import {Button, Divider, FormControl, Grid, IconButton, InputLabel, InputAdornment, MenuItem, OutlinedInput, Popover, Select, TextField, Typography, useTheme} from '@mui/material' +import { makeStyles } from 'tss-react/mui'; +import './GridStyles.scss' -function NewComponent({title}) { + +function NewComponent({columns,rows,hasSearch}) { + const [gridApi, setGridApi] = useState(null); + const [gridColumnApi, setGridColumnApi] = useState(null); + const [isColumnsLoaded, setIsColumnsLoaded] = useState(false) + const [headerCustomSortDirection, setHeaderCustomSortDirection] = useState(null) + const [headerCustomSortColumn, setHeaderCustomSortColumn] = useState(null) + const [headerCustomFilters, setHeaderCustomFilters] = useState([]) + const [activeFilters, setActiveFilters] = useState([]) + const [isRowsLoaded, setIsRowsLoaded] = useState(false) + const [anchorElFilter, setAnchorElFilter] = useState(null) + const [selectedFilter, setSelectedFilter] = useState('') + const [searchValue, setSearchValue] = useState('') + // useRefs + const tableRef = useRef(null) + const columnApi = useRef(null) + // Default + // Data + const [rowData,setRowData] = useState([]); + const [columnDefs,setColumnDefs] = useState([]) + + const updateSortColumn = (colId) => { + setHeaderCustomSortColumn(colId) + } + const updateSortDirection = (sortDir) => { + setHeaderCustomSortDirection(sortDir) + } + + const appendCustomFilter = (filter) => { + // insert custom filter here + setHeaderCustomFilters((prevData)=>({ + ...prevData, + filter + })) + } + + const removeCustomFilter = (filter) => { + // Remove custom filter here + let newCustomFilters = [] + headerCustomFilters.map((curr)=> { + if(curr === filter){ + // insert ignore here + }else{ + // add to newCustomFilters + } + }) + } +// Header/Column Actions + const SortColumn = async (col) => { + // await ResetSort(col) + let newColDef = col + if(col.headerCustomSortColumn === col.column.colId){ + if(col.headerCustomSortDirection === 'asc'){ + return col.updateSortDirection('desc') + }else if(col.headerCustomSortDirection === 'desc'){ + col.updateSortDirection(null) + return col.updateSortColumn(null) + }else{ + // set ascending sort logic here + return col.updateSortDirection(('asc')) + } + }else{ + col.updateSortDirection('asc') + return col.updateSortColumn(col.column.colId) + } + + // return true + } + + const CustomizedHeader = (col) => { + console.log("Col: ",col) + const [anchorEl, setAnchorEl] = useState(null) + const [isHovered, setIsHovered] = useState(false) + const [currentSort, setCurrentSort] = useState(false) + useEffect(() => { + if(col.headerCustomSortColumn === col.column.colId){ + setCurrentSort(true) + } + }, [col.headerCustomSortColumn]) + + const handleMouseEnter = () => { + setIsHovered(true); + } + + const handleMouseLeave = () => { + setIsHovered(false); + } + const handleDivClick = async () => { + if(col.enableSorting){ + await SortColumn(col) + } + } + const handlePopoverClick = (event) => { + setAnchorEl(event.currentTarget); + }; + + const handlePopoverClose = () => { + setAnchorEl(null); + }; + // Pinning + const handlePinRight = () => { + col.columnApi.setColumnPinned(col.column.colId,'right') + handlePopoverClose() + } + const handlePinLeft = () => { + col.columnApi.setColumnPinned(col.column.colId,'left') + handlePopoverClose() + } + const handleUnpin = () => { + col.columnApi.setColumnPinned(col.column.colId, false) + handlePopoverClose() + } + const handleHide = () => { + col.columnApi.setColumnVisible(col.column.colId,false) + } + const sampleClick =() => { + handlePopoverClose() + } + + return ( +
+ + + + + + { (col.column.pinned === null || col.column.pinned === 'left') && ( +
+ +
) + } + { (col.column.pinned === null || col.column.pinned === 'right') && ( +
+ +
) + } + { (col.column.pinned === 'right' || col.column.pinned === 'left') && ( +
+ +
) + } + +
+ +
+
+
+
+ {col.displayName} + { col.enableSorting && (isHovered || currentSort) && ( + (!currentSort || col.headerCustomSortDirection === null )? + <> + + + + : col.headerCustomSortDirection === 'desc' ? + <> + + + : + <> + + + )} +
+
+ ) + } + + const defaultColDef = { + resizable: true, + flex: 1, + headerComponent: CustomizedHeader, + headerComponentParams: { + headerCustomSortDirection: headerCustomSortDirection, + updateSortDirection: updateSortDirection, + headerCustomSortColumn: headerCustomSortColumn, + updateSortColumn: updateSortColumn, + } + } + + const onGridReady = (params) => { + columnApi.current = params.columnApi + } + + const isRowsEmpty = () => { + if(rowData.length === 0 && isRowsLoaded){ + return true + }else{ + return false + } + } + + const isDataLoaded =() => { + if(rowData.length >= 0 && isRowsLoaded){ + if(columnDefs.length >= 0 && isColumnsLoaded){ + return true + }else{ + return false + } + }else{ + return false + } + } + const constructFilter = (element) => { + // Sort input type = autocomplete, default, checkbox, nested, ... + let filterObject = { + label:element.field.charAt(0).toUpperCase() + element.field.slice(1), + isActive:false, + type:'default' + } + if(element.filter.label){ + filterObject={ + ...filterObject, + label:element.filter.label + } + } + if(element.filter.type){ + filterObject = { + ...filterObject, + type: element.filter.type + } + } + console.log(filterObject) + return filterObject + } + // update when component mounts + useEffect(() => { + if(columns){ + if(columns.length >= 0){ + let newColumns = [] + let updatedArray = [] + columns.forEach((element,i) => { + console.log("Checking out this column: ",element) + const newElement = { + ...element + } + newColumns[i] = newElement + // Filters + if(element.filter){ + console.log('hit') + let filterObject = constructFilter(element) + // default value + updatedArray = [...updatedArray,filterObject] + } + + }); + setHeaderCustomFilters(updatedArray) + setColumnDefs(newColumns) + setIsColumnsLoaded(true) + } + }else{ + } + + }, [columns]) + useEffect(() => { + console.log("Custom Filters: ",headerCustomFilters) + }, [headerCustomFilters]) + useEffect(() => { + console.log("selectedFilter: ",selectedFilter) + }, [selectedFilter]) + + + useEffect(() => { + if(rows){ + if(rows.length === 0){ + setRowData(rows) + setIsRowsLoaded(true) + }else if(rows.length > 0){ + setRowData(rows) + setIsRowsLoaded(true) + } + }else{ + } + }, [rows]) + + const handleSearchChange = (e) => { + setSearchValue(e.target.value) + // Insert Search + } + const handleSearchSubmit = (e) => { + console.log("Search Value: ",searchValue) + } + + const handlePopoverFilterClick = (e) => { + setAnchorElFilter(e.currentTarget) + } + const handlePopoverFilterClose = () => { + setAnchorElFilter(null) + } + const sampleClick = () => { + console.log('click') + } + // filter + const handleSelectedFilter = (e) => { + setSelectedFilter(e.target.value) + } return ( -
NewComponent {title}
+ + + + + {/* If filter: */} + { headerCustomFilters.length > 0 && ( + + + + Filter by: + + { //only display button if headerCustomFilter.length < activeFilters.length + + } + + +
+
+ + Filters: + + + + + {/* { !selectedFilter === '' ? //insert here filter type + selectedFilter + : + <> + } */} +
+
+
+
+ )} +
+ + {/* If has search */} + + {hasSearch && ( + + + + Search + + + + + + + } + /> + + + )} + +
+
+ +
+ + +
+
+
) } diff --git a/src/components/NewComponent/index.js b/src/components/NewComponent/index.js index ecfd277..4208fe3 100644 --- a/src/components/NewComponent/index.js +++ b/src/components/NewComponent/index.js @@ -1,2 +1,2 @@ -import {NewComponent} from "./NewComponent" +import NewComponent from "./NewComponent" export {NewComponent}; \ No newline at end of file diff --git a/src/components/NewComponent/index.stories.js b/src/components/NewComponent/index.stories.js index 9e09ff7..f2d9056 100644 --- a/src/components/NewComponent/index.stories.js +++ b/src/components/NewComponent/index.stories.js @@ -2,13 +2,45 @@ import React from 'react' import {NewComponent} from "." const NewComponentStory = { - title: "title", + title: "NewComponent", component: NewComponent } +export default NewComponentStory + export const DefaultStory =({...args}) => { - + return } export const Default = DefaultStory.bind({}); -export default NewComponentStory \ No newline at end of file +Default.args = { + hasSearch:true, + columns: [ + {field: 'id',headerName:"ID", sortable:true ,width:120,flex:0,filter:true}, + {field: 'title', sortable:true,filter:true}, + {field: 'reviews',sortable:true,filter:true}, + {field: 'comments',resizable:false,sortable:true}, + {field: 'filler',sortable:true}, + {field: 'enabled',sortable:true + ,filter:{type:"autocomplete",label:"Enabled"} + }, + ], + rows: [ + { id: 0, title: 'Example 4', reviews:10 ,comments: 'rad', filler: false, enabled: true}, + { id: 1, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, + { id: 2, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, + { id: 3, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, + { id: 4, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, + { id: 5, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, + { id: 6, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, + { id: 7, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, + { id: 8, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, + { id: 9, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, + { id: 10, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, + { id: 11, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, + { id: 12, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, + { id: 13, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, + { id: 14, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, + { id: 15, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, + ], +} \ No newline at end of file From 04322226578c6f5576904820ef2cbd240abb248a Mon Sep 17 00:00:00 2001 From: Guk Hum Jaeson Cho Date: Tue, 27 Jun 2023 14:00:11 +0800 Subject: [PATCH 04/10] ZI-14145 Filter inputs and filter management supported. Needs API integration support --- src/components/NewComponent/NewComponent.jsx | 250 +++++++++++++++---- src/components/NewComponent/index.stories.js | 78 +++++- 2 files changed, 271 insertions(+), 57 deletions(-) diff --git a/src/components/NewComponent/NewComponent.jsx b/src/components/NewComponent/NewComponent.jsx index e5cd8c0..367eae7 100644 --- a/src/components/NewComponent/NewComponent.jsx +++ b/src/components/NewComponent/NewComponent.jsx @@ -4,7 +4,7 @@ import { faSort , faSortUp, faSortDown, faPlus, faBars, faFilter, faThumbtack,fa import SearchIcon from '@mui/icons-material/Search'; import { render } from 'react-dom'; import { AgGridColumn, AgGridReact } from 'ag-grid-react'; -import {Button, Divider, FormControl, Grid, IconButton, InputLabel, InputAdornment, MenuItem, OutlinedInput, Popover, Select, TextField, Typography, useTheme} from '@mui/material' +import {Autocomplete, Button, Checkbox, Chip, Divider, FormControl, Grid, IconButton, InputLabel, InputAdornment, ListItemText , MenuItem, MenuList, OutlinedInput, Popover, Select, TextField, Typography, useTheme} from '@mui/material' import { makeStyles } from 'tss-react/mui'; import './GridStyles.scss' @@ -18,8 +18,12 @@ function NewComponent({columns,rows,hasSearch}) { const [headerCustomFilters, setHeaderCustomFilters] = useState([]) const [activeFilters, setActiveFilters] = useState([]) const [isRowsLoaded, setIsRowsLoaded] = useState(false) + // Filters const [anchorElFilter, setAnchorElFilter] = useState(null) const [selectedFilter, setSelectedFilter] = useState('') + const [selectedFilterOption, setSelectedFilterOption] = useState('') + const [selectedFilterOptionMultiple, setSelectedFilterOptionMultiple] = useState([]) + // Search const [searchValue, setSearchValue] = useState('') // useRefs const tableRef = useRef(null) @@ -78,7 +82,7 @@ function NewComponent({columns,rows,hasSearch}) { } const CustomizedHeader = (col) => { - console.log("Col: ",col) + // console.log("Col: ",col) const [anchorEl, setAnchorEl] = useState(null) const [isHovered, setIsHovered] = useState(false) const [currentSort, setCurrentSort] = useState(false) @@ -245,6 +249,7 @@ function NewComponent({columns,rows,hasSearch}) { return false } } + const constructFilter = (element) => { // Sort input type = autocomplete, default, checkbox, nested, ... let filterObject = { @@ -264,10 +269,17 @@ function NewComponent({columns,rows,hasSearch}) { type: element.filter.type } } + if(element.filter.options){ + filterObject={ + ...filterObject, + options: element.filter.options + } + } console.log(filterObject) return filterObject } - // update when component mounts + + // Update when props change useEffect(() => { if(columns){ if(columns.length >= 0){ @@ -281,7 +293,6 @@ function NewComponent({columns,rows,hasSearch}) { newColumns[i] = newElement // Filters if(element.filter){ - console.log('hit') let filterObject = constructFilter(element) // default value updatedArray = [...updatedArray,filterObject] @@ -296,14 +307,7 @@ function NewComponent({columns,rows,hasSearch}) { } }, [columns]) - useEffect(() => { - console.log("Custom Filters: ",headerCustomFilters) - }, [headerCustomFilters]) - useEffect(() => { - console.log("selectedFilter: ",selectedFilter) - }, [selectedFilter]) - useEffect(() => { if(rows){ if(rows.length === 0){ @@ -317,27 +321,98 @@ function NewComponent({columns,rows,hasSearch}) { } }, [rows]) - const handleSearchChange = (e) => { - setSearchValue(e.target.value) - // Insert Search - } - const handleSearchSubmit = (e) => { - console.log("Search Value: ",searchValue) - } - const handlePopoverFilterClick = (e) => { setAnchorElFilter(e.currentTarget) } const handlePopoverFilterClose = () => { + setSelectedFilter('') + setSelectedFilterOption('') + setSelectedFilterOptionMultiple([]) setAnchorElFilter(null) } const sampleClick = () => { console.log('click') + + } + // SEARCH + const handleSearchChange = (e) => { + setSearchValue(e.target.value) + // Insert Search + } + const handleSearchSubmit = (e) => { + console.log("Search Value: ",searchValue) } - // filter + + // FILTERS const handleSelectedFilter = (e) => { + setSelectedFilterOption('') + setSelectedFilterOptionMultiple([]) setSelectedFilter(e.target.value) } + const handleSelectedFilterOption = (e) => { + setSelectedFilterOption(e.target.value) + } + const handleSelectedFilterAutocomplete = (e,v) => { + if(v){ + setSelectedFilterOption(v.value) + }else{ + setSelectedFilterOption('') + } + } + const handleSelectedFilterOptionMultiple = (e) => { + console.log("mult options") + console.log(e.target.value) + const currArray = e.target.value + let newArray = [] + currArray.forEach(element => { + newArray = [...newArray,element.value] + }); + + setSelectedFilterOptionMultiple(e.target.value) + setSelectedFilterOption(newArray) + } + const handleApplyFilter = (e) =>{ + // Find the target filter in the headerCustomFilters array + const targetFilter = headerCustomFilters.find(obj => obj.label === selectedFilter.label); + console.log("Target Filter: ", targetFilter); + + // Update the target filter's isActive property + if (targetFilter) { + targetFilter.isActive = true; + + // Create a new array with the updated filter + const updatedFilters = headerCustomFilters.map(obj => obj.label === selectedFilter.label ? targetFilter : obj); + + // Update the state with the updated filters + setHeaderCustomFilters(updatedFilters); + } + + handlePopoverFilterClose() + + } + const handleChipDelete = (deletedElement) => { + const updatedFilters = headerCustomFilters.map(element => { + if (element === deletedElement) { + return { ...element, isActive: false }; + } + return element; + }); + + setHeaderCustomFilters(updatedFilters); + console.log(headerCustomFilters); + + } + // Debug + useEffect(() => { + console.log("Custom Filters: ",headerCustomFilters) + }, [headerCustomFilters]) + useEffect(() => { + console.log("selectedFilter: ",selectedFilter) + }, [selectedFilter]) + useEffect(() => { + console.log("Selected Filter Option: ",selectedFilterOption) + }, [selectedFilterOption]) + return ( @@ -345,40 +420,50 @@ function NewComponent({columns,rows,hasSearch}) { {/* If filter: */} { headerCustomFilters.length > 0 && ( - + +
- Filter by: - { //only display button if headerCustomFilter.length < activeFilters.length - +
+ { //Display chips here + headerCustomFilters.filter(obj => obj.isActive === true).map(element => ( + handleChipDelete(element)} style={{marginLeft:'0.5rem'}} /> + )) } - + + -
-
- - Filters: +
+
+ + {/* Filters: */} - + + + { selectedFilter === '' ? //insert here filter type + <> + : + selectedFilter.type === 'default' ? + + { //loop for every active filter + selectedFilter?.options &&( + selectedFilter.options.map(element => ( + + {element.label} + + )) + ) + } + + : + selectedFilter.type === 'autocomplete' ? + } + /> + : + selectedFilter.type === 'multiple' ? + + - {/* { !selectedFilter === '' ? //insert here filter type - selectedFilter : - <> - } */} + <> + {/* Apply nested filter here */} + + } + + + + + + + +
+ ) + } )} diff --git a/src/components/NewComponent/index.stories.js b/src/components/NewComponent/index.stories.js index f2d9056..c606bb7 100644 --- a/src/components/NewComponent/index.stories.js +++ b/src/components/NewComponent/index.stories.js @@ -16,13 +16,77 @@ export const Default = DefaultStory.bind({}); Default.args = { hasSearch:true, columns: [ - {field: 'id',headerName:"ID", sortable:true ,width:120,flex:0,filter:true}, - {field: 'title', sortable:true,filter:true}, - {field: 'reviews',sortable:true,filter:true}, - {field: 'comments',resizable:false,sortable:true}, - {field: 'filler',sortable:true}, - {field: 'enabled',sortable:true - ,filter:{type:"autocomplete",label:"Enabled"} + { + field: 'id', headerName:"ID", sortable:true , width:120, flex:0, + }, + { + field: 'title', sortable:true}, + { + field: 'reviews',sortable:true, + filter:{ + type:'autocomplete', + options:[ + { + label:'Low', + value:6 + }, + { + label: 'High', + value: 5 + }, + { + label: 'Mid', + value: 4 + }, + { + label: 'Good', + value: 3 + }, + { + label: 'Bad', + value: 2 + } + ] + } + }, + { + field: 'comments',sortable:true}, + { + field: 'filler',sortable:true, + filter:{ + type:'multiple', + options:[ + { + label: 'True', + value: true + }, + { + label: 'False', + value: false + }, + { + label: 'Null', + value: null + } + ] + } + }, + { + field: 'enabled',sortable:true + ,filter:{ + label:"Enabled", + options:[ + { + label: 'Enabled', + value: 0, + key:'key1' + }, + { + label: 'Disabled', + value: 1, + key:'key2' + } + ]} }, ], rows: [ From 99a832a2b5baafe71eeaf11fab06f2130cd019a6 Mon Sep 17 00:00:00 2001 From: Guk Hum Jaeson Cho Date: Thu, 29 Jun 2023 12:05:02 +0800 Subject: [PATCH 05/10] ZI-14148 Context file created and initial state. Integrating to code --- package.json | 4 +- src/components/NewComponent/GridContext.jsx | 73 ++++++++++++ src/components/NewComponent/NewComponent.jsx | 117 ++++++++++++++----- src/components/NewComponent/index.stories.js | 85 +++++++++++--- 4 files changed, 228 insertions(+), 51 deletions(-) create mode 100644 src/components/NewComponent/GridContext.jsx diff --git a/package.json b/package.json index 9b1715b..a76cc89 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,8 @@ "@testing-library/react": "^12.1.5", "@testing-library/user-event": "^14.4.3", "@wojtekmaj/react-hooks": "^1.17.2", - "ag-grid-community": "^25.1.0", - "ag-grid-react": "^25.1.0", + "ag-grid-community": "^27.0.1", + "ag-grid-react": "^27.0.1", "axios": "^1.2.1", "branch-sdk": "^2.59.0", "clsx": "^1.1.1", diff --git a/src/components/NewComponent/GridContext.jsx b/src/components/NewComponent/GridContext.jsx new file mode 100644 index 0000000..a133fb9 --- /dev/null +++ b/src/components/NewComponent/GridContext.jsx @@ -0,0 +1,73 @@ +import React, {createContext, useReducer} from 'react' + +export const initialState = { + columns: [], + rows:[], + sortColumn: null, + sortDirection: null, + filterColumns: [], + loading: false, +} + +export const GridContext = createContext([initialState,undefined]) + +export const actions ={ + RESET_GRID:'RESET_GRID', + SORT_COLUMN: 'SORT_COLUMN', + FILTER_COLUMN: 'FILTER_COLUMN', + CLEAR_FILTER_COLUMN:'CLEAR_FILTER_COLUMN', + LOAD_COLUMNS: 'LOAD_COLUMNS', + LOAD_ROWS: 'LOAD_ROWS', + SET_LOADING: 'SET_LOADING', + SET_LOADING_DONE: 'SET_LOADING_DONE' +} + +export const gridReducer = (state,action) => { + switch (action.type) { + case actions.SORT_COLUMN: + return { + ...state + } + case actions.FILTER_COLUMN: + return { + ...state + } + case actions.CLEAR_FILTER_COLUMN: + return { + ...state + } + case actions.LOAD_COLUMNS: + return { + ...state, + columns: action.payload.columns + } + case actions.LOAD_ROWS: + return { + ...state, + rows: action.payload.rows + } + case actions.SET_LOADING: + return { + ...state, + loading: true + } + case actions.SET_LOADING_DONE: + return { + ...state, + loading: false + } + default: + break; + } +} + +const GridProvider = ({ children }) => { + const [state, dispatch] = useReducer(gridReducer, initialState) + return ( + + {children} + + ) +} + +export default GridProvider \ No newline at end of file diff --git a/src/components/NewComponent/NewComponent.jsx b/src/components/NewComponent/NewComponent.jsx index 367eae7..0758b30 100644 --- a/src/components/NewComponent/NewComponent.jsx +++ b/src/components/NewComponent/NewComponent.jsx @@ -4,6 +4,7 @@ import { faSort , faSortUp, faSortDown, faPlus, faBars, faFilter, faThumbtack,fa import SearchIcon from '@mui/icons-material/Search'; import { render } from 'react-dom'; import { AgGridColumn, AgGridReact } from 'ag-grid-react'; +import {actions as DataGridContext } from './GridContext' import {Autocomplete, Button, Checkbox, Chip, Divider, FormControl, Grid, IconButton, InputLabel, InputAdornment, ListItemText , MenuItem, MenuList, OutlinedInput, Popover, Select, TextField, Typography, useTheme} from '@mui/material' import { makeStyles } from 'tss-react/mui'; import './GridStyles.scss' @@ -16,13 +17,13 @@ function NewComponent({columns,rows,hasSearch}) { const [headerCustomSortDirection, setHeaderCustomSortDirection] = useState(null) const [headerCustomSortColumn, setHeaderCustomSortColumn] = useState(null) const [headerCustomFilters, setHeaderCustomFilters] = useState([]) - const [activeFilters, setActiveFilters] = useState([]) const [isRowsLoaded, setIsRowsLoaded] = useState(false) // Filters const [anchorElFilter, setAnchorElFilter] = useState(null) const [selectedFilter, setSelectedFilter] = useState('') const [selectedFilterOption, setSelectedFilterOption] = useState('') const [selectedFilterOptionMultiple, setSelectedFilterOptionMultiple] = useState([]) + const [selectedNestedFilter, setSelectedNestedFilter] = useState('') // Search const [searchValue, setSearchValue] = useState('') // useRefs @@ -77,12 +78,9 @@ function NewComponent({columns,rows,hasSearch}) { col.updateSortDirection('asc') return col.updateSortColumn(col.column.colId) } - - // return true } const CustomizedHeader = (col) => { - // console.log("Col: ",col) const [anchorEl, setAnchorEl] = useState(null) const [isHovered, setIsHovered] = useState(false) const [currentSort, setCurrentSort] = useState(false) @@ -252,6 +250,7 @@ function NewComponent({columns,rows,hasSearch}) { const constructFilter = (element) => { // Sort input type = autocomplete, default, checkbox, nested, ... + console.log("Filter: ",element) let filterObject = { label:element.field.charAt(0).toUpperCase() + element.field.slice(1), isActive:false, @@ -327,6 +326,7 @@ function NewComponent({columns,rows,hasSearch}) { const handlePopoverFilterClose = () => { setSelectedFilter('') setSelectedFilterOption('') + setSelectedNestedFilter('') setSelectedFilterOptionMultiple([]) setAnchorElFilter(null) } @@ -346,6 +346,7 @@ function NewComponent({columns,rows,hasSearch}) { // FILTERS const handleSelectedFilter = (e) => { setSelectedFilterOption('') + setSelectedNestedFilter('') setSelectedFilterOptionMultiple([]) setSelectedFilter(e.target.value) } @@ -371,11 +372,24 @@ function NewComponent({columns,rows,hasSearch}) { setSelectedFilterOptionMultiple(e.target.value) setSelectedFilterOption(newArray) } + const handleSelectedNestedFilter = (e) => { + console.log("Selected Nested Filter: ",e.target.value) + if(e.target.value.nestedOptions){ + setSelectedNestedFilter(e.target.value) + }else{ + setSelectedNestedFilter(e.target.value) + setSelectedFilterOption(e.target.vlue) + } + } const handleApplyFilter = (e) =>{ // Find the target filter in the headerCustomFilters array - const targetFilter = headerCustomFilters.find(obj => obj.label === selectedFilter.label); + let targetFilter = headerCustomFilters.find(obj => obj.label === selectedFilter.label); console.log("Target Filter: ", targetFilter); - + // consider nested property + if(targetFilter.type==='nestedAutocomplete'){ + // newFilter = selectedFilterOption + console.log("Nested: ", selectedFilterOption) + } // Update the target filter's isActive property if (targetFilter) { targetFilter.isActive = true; @@ -417,50 +431,56 @@ function NewComponent({columns,rows,hasSearch}) { - + {/* If filter: */} { headerCustomFilters.length > 0 && ( - +
- - Filter by: + Filters: -
{ //Display chips here headerCustomFilters.filter(obj => obj.isActive === true).map(element => ( - handleChipDelete(element)} style={{marginLeft:'0.5rem'}} /> - )) + handleChipDelete(element)} style={{marginLeft:'0.5rem',paddingTop:'2px'}} /> + )) } +
{ //only display add filter button if headerCustomFilter.length < activeFilters.length (headerCustomFilters.filter(obj => obj.isActive === false).length > 0 )&& ( <> @@ -568,8 +588,41 @@ function NewComponent({columns,rows,hasSearch}) { : <> - {/* Apply nested filter here */} - + + + + + { selectedNestedFilter.nestedOptions && ( + <> + } + /> + + ) + } + } diff --git a/src/components/NewComponent/index.stories.js b/src/components/NewComponent/index.stories.js index c606bb7..1a4e01f 100644 --- a/src/components/NewComponent/index.stories.js +++ b/src/components/NewComponent/index.stories.js @@ -20,7 +20,58 @@ Default.args = { field: 'id', headerName:"ID", sortable:true , width:120, flex:0, }, { - field: 'title', sortable:true}, + field: 'title', sortable:true + }, + { + field:'location_scope', headerName:'Scope', sortable: true, + filter: { + type: 'nestedAutocomplete', + label: "Location Scope", + options:[ + { + label: 'Global', + value: 'global' + }, + { + label: 'Country', + value: 'country', + nestedOptions:[ + { + label: 'Philippines', + value: '1' + }, + { + label: 'US', + value: '2' + }, + { + label: 'Canada', + value: '3' + }, + { + label: 'Japan', + value: '4' + } + ] + }, + { + label:'Office', + value:'office', + nestedOptions:[ + { + label: 'Manila - Cebu', + value: '1' + }, + { + label: 'Manila - Makati', + value: '2' + } + ] + }, + ] + } + + }, { field: 'reviews',sortable:true, filter:{ @@ -90,21 +141,21 @@ Default.args = { }, ], rows: [ - { id: 0, title: 'Example 4', reviews:10 ,comments: 'rad', filler: false, enabled: true}, - { id: 1, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, - { id: 2, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, - { id: 3, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, - { id: 4, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, - { id: 5, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, - { id: 6, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, - { id: 7, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, - { id: 8, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, - { id: 9, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, - { id: 10, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, - { id: 11, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, - { id: 12, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, - { id: 13, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, - { id: 14, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, - { id: 15, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false}, + { id: 0, title: 'Example 4', reviews:10,comments: 'rad', filler: false, enabled: true,location_scope:'Global'}, + { id: 1, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Office'}, + { id: 2, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Regional'}, + { id: 3, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Global'}, + { id: 4, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Office'}, + { id: 5, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Global'}, + { id: 6, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Office'}, + { id: 7, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Regional'}, + { id: 8, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Global'}, + { id: 9, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Office'}, + { id: 10, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Regional'}, + { id: 11, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Global'}, + { id: 12, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Regional'}, + { id: 13, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Office'}, + { id: 14, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Global'}, + { id: 15, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Global'}, ], } \ No newline at end of file From cddfc2c2171d822e62eb62d40d603c527ae1fd0e Mon Sep 17 00:00:00 2001 From: Guk Hum Jaeson Cho Date: Thu, 20 Jul 2023 13:22:43 +0800 Subject: [PATCH 06/10] ZI-14098 DataGrid done --- src/components/DataGridRemake2/DataGrid.jsx | 767 ++++++++++++++++++ .../DataGridRemake2/GridContext.jsx | 82 ++ .../DataGridRemake2/GridStyles.scss | 16 + src/components/DataGridRemake2/index.js | 2 + .../DataGridRemake2/index.stories.js | 179 ++++ yarn.lock | 18 +- 6 files changed, 1055 insertions(+), 9 deletions(-) create mode 100644 src/components/DataGridRemake2/DataGrid.jsx create mode 100644 src/components/DataGridRemake2/GridContext.jsx create mode 100644 src/components/DataGridRemake2/GridStyles.scss create mode 100644 src/components/DataGridRemake2/index.js create mode 100644 src/components/DataGridRemake2/index.stories.js diff --git a/src/components/DataGridRemake2/DataGrid.jsx b/src/components/DataGridRemake2/DataGrid.jsx new file mode 100644 index 0000000..1d93bc1 --- /dev/null +++ b/src/components/DataGridRemake2/DataGrid.jsx @@ -0,0 +1,767 @@ +import React, {useState, useEffect, useRef, useCallback, useMemo, useContext} from 'react' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faSort , faSortUp, faSortDown, faPlus, faBars, faFilter, faThumbtack,faEyeSlash } from '@fortawesome/free-solid-svg-icons'; +import SearchIcon from '@mui/icons-material/Search'; +import { render } from 'react-dom'; +import { AgGridColumn, AgGridReact } from 'ag-grid-react'; +import {GridContext, actions} from "./GridContext"; +import {Autocomplete, Button, Checkbox, Chip, Divider, FormControl, Grid, IconButton, InputLabel, InputAdornment, ListItemText , MenuItem, MenuList, OutlinedInput, Popover, Select, TextField, Typography, useTheme} from '@mui/material' +import { makeStyles } from 'tss-react/mui'; +import { debounce } from 'lodash'; +import './GridStyles.scss' + +function DataGrid({columns, rows, hasSearch}) { + const [state,dispatch] = useContext(GridContext) + const [gridApi, setGridApi] = useState(null); + const [gridColumnApi, setGridColumnApi] = useState(null); +// Sort + const [headerCustomSortDirection, setHeaderCustomSortDirection] = useState(null) + const [headerCustomSortColumn, setHeaderCustomSortColumn] = useState(null) +// Filters + const [anchorElFilter, setAnchorElFilter] = useState(null) + const [selectedFilter, setSelectedFilter] = useState('') + const [headerCustomFilters, setHeaderCustomFilters] = useState([]) + const [selectedFilterOption, setSelectedFilterOption] = useState('') + const [selectedFilterOptionMultiple, setSelectedFilterOptionMultiple] = useState([]) + const [selectedNestedFilter, setSelectedNestedFilter] = useState('') +// Search + const [searchValue, setSearchValue] = useState('') +// useRefs + const tableRef = useRef(null) + const columnApi = useRef(null) +// Data + const [rowData,setRowData] = useState([]); + const [columnDefs,setColumnDefs] = useState([]) + + const constructFilter = (element) => { + // Sort input type = autocomplete, default, checkbox, nested, ... + console.log("Filter: ",element) + let filterObject = { + label:element.field.charAt(0).toUpperCase() + element.field.slice(1), + isActive:false, + type:'default', + selectedOption:null, + selectedNestedOption:null + } + if(element.filter.label){ + filterObject={ + ...filterObject, + label:element.filter.label + } + } + if(element.filter.type){ + filterObject = { + ...filterObject, + type: element.filter.type + } + } + if(element.filter.options){ + filterObject={ + ...filterObject, + options: element.filter.options + } + } + console.log(filterObject) + return filterObject + } +// Mounting + + + +// Update Handlers + const updateSortColumn = (colId) => { + // setHeaderCustomSortColumn(colId) + dispatch({ + type: actions.SORT_COLUMN, + payload:{ + sortColumn: colId + } + }) + } + + const updateSortDirection = (sortDir) => { + // setHeaderCustomSortDirection(sortDir) + dispatch({ + type: actions.SORT_DIRECTION, + payload:{ + sortDirection: sortDir + } + }) + } + + const appendCustomFilter = (filter) => { + // insert custom filter here + dispatch({ + type: actions.FILTER_COLUMN, + payload: [...state.filterColumns, filter] + }) + } + + const removeCustomFilter = (filter) => { + // Remove custom filter here + let newCustomFilters = [] + state?.filterColumns?.map((curr)=> { + if(curr === filter){ + // insert ignore here + }else{ + // add to newCustomFilters + } + }) + } + + + // Header Events: + const SortColumn = async (col) => { + // await ResetSort(col) + let newColDef = col + if(state?.sortColumn === col.column.colId){ + if(state?.sortDirection === 'asc'){ + return col.updateSortDirection('desc') + }else if(state?.sortDirection === 'desc'){ + col.updateSortDirection(null) + return col.updateSortColumn(null) + }else{ + // set ascending sort logic here + return col.updateSortDirection(('asc')) + } + }else{ + col.updateSortDirection('asc') + + return col.updateSortColumn(col.column.colId) + } + } + // useEffect Trackers / Memoization + // Debugging + useEffect(() => { + console.log("Sort: ", headerCustomSortColumn , headerCustomSortDirection) + }, [headerCustomSortColumn,headerCustomSortDirection]) + + useEffect(() => { + console.log("gridContext: ",state) + // dispatch({ + // type: actions.TEST_DISPATCH + // }) + }, [state]) + + + // Render: + const CustomizedHeader = (col) => { + const [anchorEl, setAnchorEl] = useState(null) + const [isHovered, setIsHovered] = useState(false) + const [currentSort, setCurrentSort] = useState(false) + useEffect(() => { + if(state?.sortColumn === col.column.colId){ + setCurrentSort(true) + } + }, [ state?.sortColumn]) + + const handleMouseEnter = () => { + setIsHovered(true); + } + + const handleMouseLeave = () => { + setIsHovered(false); + } + + const handleDivClick = async () => { + if(col.enableSorting){ + await SortColumn(col) + } + } + const handlePopoverClick = (event) => { + setAnchorEl(event.currentTarget); + } + + const handlePopoverClose = () => { + setAnchorEl(null); + } + // Pinning + const handlePinRight = () => { + col.columnApi.setColumnPinned(col.column.colId,'right') + handlePopoverClose() + } + const handlePinLeft = () => { + col.columnApi.setColumnPinned(col.column.colId,'left') + handlePopoverClose() + } + const handleUnpin = () => { + col.columnApi.setColumnPinned(col.column.colId, false) + handlePopoverClose() + } + const handleHide = () => { + col.columnApi.setColumnVisible(col.column.colId,false) + } + const sampleClick =() => { + handlePopoverClose() + } + return ( +
+ + + + + + { (col.column.pinned === null || col.column.pinned === 'left') && ( +
+ +
) + } + { (col.column.pinned === null || col.column.pinned === 'right') && ( +
+ +
) + } + { (col.column.pinned === 'right' || col.column.pinned === 'left') && ( +
+ +
) + } + +
+ +
+
+
+
+ {col.displayName} + { col.enableSorting && (isHovered || currentSort) && ( + (!currentSort || col.sortDirection === null )? + <> + + + + : state?.sortDirection === 'desc' ? + <> + + + : + <> + + + )} +
+
+ ) + } + useEffect(() => { + console.log("Columns: ", columns) + if(columns){ + dispatch({ + type: actions.LOAD_COLUMNS, + payload:{ + columns: columns + } + }) + if(columns.length >= 0){ + let newColumns = [] + let updatedArray = [] + columns.forEach((element,i) => { + console.log("Checking out this column: ",element) + const newElement = { + ...element + } + newColumns[i] = newElement + // Filters + if(element.filter){ + let filterObject = constructFilter(element) + // default value + updatedArray = [...updatedArray,filterObject] + } + + }); + console.log("updatedArray: ",updatedArray) + dispatch({ + type: actions.FILTER_COLUMN, + payload: { + filterColumns: updatedArray + } + }) + dispatch({ + type: actions.LOAD_COLUMNS, + payload:{ + columns: columns + } + }) + dispatch({ + type: actions.SET_LOADING_DONE + }) + // setColumnDefs(newColumns) + } + } + }, [columns]); + +// Context listeners + useEffect(() => { + if(state.columns) + setColumnDefs(state.columns) + }, [state.columns]) + + useEffect(() => { + if(rows){ + if(rows.length >= 0){ + // setRowData(rows) + dispatch({ + type:actions.LOAD_ROWS, + payload:{ + rows: rows + } + }) + } + } + }, [rows]) + + // Grid + const defaultColDef = { + resizable: true, + flex: 1, + headerComponent: CustomizedHeader, + headerComponentParams: { + headerCustomSortDirection: headerCustomSortDirection, + updateSortDirection: updateSortDirection, + headerCustomSortColumn: headerCustomSortColumn, + updateSortColumn: updateSortColumn, + } + } + const onGridReady = (params) => { + columnApi.current = params.columnApi + } +// + const handlePopoverFilterClick = (e) => { + setAnchorElFilter(e.currentTarget) + } + const handlePopoverFilterClose = () => { + setSelectedFilter('') + setSelectedFilterOption('') + setSelectedNestedFilter('') + setSelectedFilterOptionMultiple([]) + setAnchorElFilter(null) + } + const sampleClick = () => { + console.log('click') + } + + const handleSearchChange =(e) => { + setSearchValue(e.target.value) + // Insert Search + debounce(()=>{ + dispatch({ + type: actions.SET_SEARCH, + payload: { + ...state, + search: e.target.value + } + }) + },500)() + + } + const handleSearchSubmit = (e) => { + dispatch({ + type: actions.SET_SEARCH, + payload: { + ...state, + search: searchValue + } + }) + } + +// FILTERS + const handleSelectedFilter = (e) => { + setSelectedFilterOption('') + setSelectedNestedFilter('') + setSelectedFilterOptionMultiple([]) + setSelectedFilter(e.target.value) + } + const handleSelectedFilterOption = (e) => { + setSelectedFilterOption(e.target.value) + } + const handleSelectedFilterAutocomplete = (e,v) => { + if(v){ + setSelectedFilterOption(v.value) + }else{ + setSelectedFilterOption('') + } + } + + const handleSelectedFilterOptionMultiple = (e) => { + console.log("mult options") + console.log(e.target.value) + const currArray = e.target.value + let newArray = [] + currArray.forEach(element => { + newArray = [...newArray,element.value] + }); + + setSelectedFilterOptionMultiple(e.target.value) + setSelectedFilterOption(newArray) + } + + const handleSelectedNestedFilter = (e) => { + console.log("Selected Nested Filter: ",e.target.value) + if(e.target.value.nestedOptions){ + setSelectedNestedFilter(e.target.value) + }else{ + setSelectedNestedFilter(e.target.value) + setSelectedFilterOption(e.target.vlue) + } + } + + + const handleApplyFilter = (e) =>{ + // Find the target filter in the headerCustomFilters array + let targetFilter = state?.filterColumns.find(obj => obj.label === selectedFilter.label); + const targetFilterIndex = state?.filterColumns.findIndex(obj => obj.label === selectedFilter.label); + let updatedFilterColumns = [...state.filterColumns]; + console.log("Target Filter: ", targetFilter, targetFilterIndex, e); + // consider nested property + if (targetFilterIndex !== -1){ + console.log("isActive") + // Update the target filter's isActive property + if (targetFilter) { + updatedFilterColumns[targetFilterIndex] = { + ...updatedFilterColumns[targetFilterIndex], + isActive: true, + selectedOption: selectedFilterOption, + }; + if(targetFilter.type==='nestedAutocomplete'){ + updatedFilterColumns[targetFilterIndex] = { + ...updatedFilterColumns[targetFilterIndex], + selectedNestedOption: selectedNestedFilter + }; + } + // Create a new array with the updated filter + // Update the state with the updated filters + // setHeaderCustomFilters(updatedFilters); + dispatch({ + type:actions.FILTER_COLUMN, + payload:{ + filterColumns:updatedFilterColumns + } + }) + } + } + console.log("Close") + handlePopoverFilterClose() + } + + const handleChipDelete = (deletedElement) => { + const updatedFilters = state?.filterColumns.map(element => { + if (element === deletedElement) { + console.log("Element: ",element," deleted Element: ",deletedElement) + return { ...element, + isActive: false, + selectedOption: null, + selectedNestedOption: null + }; + } + return element; + }); + + // setHeaderCustomFilters(updatedFilters); + dispatch({ + type:actions.FILTER_COLUMN, + payload:{ + filterColumns:updatedFilters + } + }) + console.log(state?.filterColumns); + } + + + return ( + + + + + {/* If filter: */} + { state?.filterColumns.length > 0 && ( + +
+ + + Filters: + + + { //Display chips here + state?.filterColumns.filter(obj => obj.isActive === true).map(element => ( + handleChipDelete(element)} style={{marginLeft:'0.5rem',paddingTop:'2px',padding:'0 8px 0px 9px'}} /> + )) + } + +
+ { //only display add filter button if headerCustomFilter.length < activeFilters.length + (state?.filterColumns.filter(obj => obj.isActive === false).length > 0 )&& ( + <> + + + + +
+
+ + {/* Filters: */} + + + + + { selectedFilter === '' ? //insert here filter type + <> + : + selectedFilter.type === 'default' ? + + { //loop for every active filter + selectedFilter?.options &&( + selectedFilter.options.map(element => ( + + {element.label} + + )) + ) + } + + : + selectedFilter.type === 'autocomplete' ? + } + /> + : + selectedFilter.type === 'multiple' ? + + + + : + <> + + + + + { selectedNestedFilter.nestedOptions && ( + <> + } + /> + + ) + } + + } + + + + + + + + +
+
+
+ ) + } +
+ )} +
+ + {/* If has search */} + + {hasSearch && ( + + + + Search + + + + + + + } + /> + + + )} + +
+
+ +
+ + +
+
+
+ ) +} + +export default DataGrid \ No newline at end of file diff --git a/src/components/DataGridRemake2/GridContext.jsx b/src/components/DataGridRemake2/GridContext.jsx new file mode 100644 index 0000000..e39497c --- /dev/null +++ b/src/components/DataGridRemake2/GridContext.jsx @@ -0,0 +1,82 @@ +import {createContext, useReducer} from 'react' + +export const initialState = { + columns: [], + rows:[], + loading: false, + sortColumn: null, + sortDirection: null, + filterColumns: [], + search: null +} + +export const actions ={ + RESET_GRID:'RESET_GRID', + SORT_COLUMN: 'SORT_COLUMN', + FILTER_COLUMN: 'FILTER_COLUMN', + CLEAR_FILTER_COLUMN:'CLEAR_FILTER_COLUMN', + LOAD_COLUMNS: 'LOAD_COLUMNS', + LOAD_ROWS: 'LOAD_ROWS', + SET_LOADING: 'SET_LOADING', + SET_LOADING_DONE: 'SET_LOADING_DONE', + SET_SEARCH: 'SET_SEARCH', + TEST_DISPATCH: 'TEST_DISPATCH' +} + +export const GridContext = createContext() + +export function gridReducer(state,action){ + switch (action.type) { + case actions.TEST_DISPATCH: + return {...state} + case actions.SET_SEARCH: + return { + ...state, + search: action.payload.search + } + case actions.SORT_COLUMN: + return { + ...state, + sortColumn: action.payload.sortColumn + } + case actions.SORT_DIRECTION: + return { + ...state, + sortDirection: action.payload.sortDirection + } + case actions.FILTER_COLUMN: + return { + ...state, + filterColumns: action.payload.filterColumns ?? [] + } + case actions.CLEAR_FILTER_COLUMN: + return { + ...state + } + case actions.LOAD_COLUMNS: + return { + ...state, + columns: action.payload.columns + } + case actions.LOAD_ROWS: + return { + ...state, + rows: action.payload.rows + } + case actions.SET_LOADING: + return { + ...state, + loading: true + } + case actions.SET_LOADING_DONE: + return { + ...state, + loading: false + } + default: { + throw new Error(`Unhandled action type: ${action.type}`); + } + } +} + + diff --git a/src/components/DataGridRemake2/GridStyles.scss b/src/components/DataGridRemake2/GridStyles.scss new file mode 100644 index 0000000..c59bb17 --- /dev/null +++ b/src/components/DataGridRemake2/GridStyles.scss @@ -0,0 +1,16 @@ +@import "ag-grid-community/src/styles/ag-grid.scss"; +@import "ag-grid-community/src/styles/ag-theme-alpine/sass/ag-theme-alpine-mixin.scss"; + + +.grid-wrapper{ + .ag-theme-alpine{ + @include ag-theme-alpine(( + theme: alpine, + // header-background-color:#86cac7, + // header-foreground-color:red + )); + } +} +.ag-root-wrapper { + border-radius: 20px +} diff --git a/src/components/DataGridRemake2/index.js b/src/components/DataGridRemake2/index.js new file mode 100644 index 0000000..8b8c3b0 --- /dev/null +++ b/src/components/DataGridRemake2/index.js @@ -0,0 +1,2 @@ +import DataGrid from "./DataGrid" +export {DataGrid}; \ No newline at end of file diff --git a/src/components/DataGridRemake2/index.stories.js b/src/components/DataGridRemake2/index.stories.js new file mode 100644 index 0000000..9618a46 --- /dev/null +++ b/src/components/DataGridRemake2/index.stories.js @@ -0,0 +1,179 @@ +import React, { useEffect, useContext, useReducer} from 'react' +import DataGrid from './DataGrid' +import { GridContext, actions, initialState, gridReducer + //, GridProvider +} from './GridContext' + +const DataGridRemakeStory = { + title: "DataGridRemake2", + component: DataGrid +} + +export default DataGridRemakeStory + +export const DefaultStory = ({...args}) => { + const [state,dispatch] = useReducer(gridReducer,initialState) + + return + + +} +function DGWrapper({...args}){ + const [state,dispatch] = useContext(GridContext) + useEffect(() => { + console.log("State Shallow:",state.sortColumn) + }, [state.sortColumn]) + + return( + + ) +} + +export const Default = DefaultStory.bind({}); +Default.args = { + hasSearch:true, + // onSort:, + columns: [ + { + field: 'id', headerName:"ID", sortable:true , width:120, flex:0, + }, + { + field: 'title', sortable:true + }, + { + field:'location_scope', headerName:'Scope', sortable: true, + filter: { + type: 'nestedAutocomplete', + label: "Location Scope", + options:[ + { + label: 'Global', + value: 'global' + }, + { + label: 'Country', + value: 'country', + nestedOptions:[ + { + label: 'Philippines', + value: '1' + }, + { + label: 'US', + value: '2' + }, + { + label: 'Canada', + value: '3' + }, + { + label: 'Japan', + value: '4' + } + ] + }, + { + label:'Office', + value:'office', + nestedOptions:[ + { + label: 'Manila - Cebu', + value: '1' + }, + { + label: 'Manila - Makati', + value: '2' + } + ] + }, + ] + } + + }, + { + field: 'reviews',sortable:true, + filter:{ + type:'autocomplete', + options:[ + { + label:'Low', + value:6 + }, + { + label: 'High', + value: 5 + }, + { + label: 'Mid', + value: 4 + }, + { + label: 'Good', + value: 3 + }, + { + label: 'Bad', + value: 2 + } + ] + } + }, + { + field: 'comments',sortable:true}, + { + field: 'filler',sortable:true, + filter:{ + type:'multiple', + options:[ + { + label: 'True', + value: true + }, + { + label: 'False', + value: false + }, + { + label: 'Null', + value: null + } + ] + } + }, + { + field: 'enabled',sortable:true + ,filter:{ + label:"Enabled", + options:[ + { + label: 'Enabled', + value: 0, + key:'key1' + }, + { + label: 'Disabled', + value: 1, + key:'key2' + } + ]} + }, + ], + rows: [ + { id: 0, title: 'Example 4', reviews:10,comments: 'rad', filler: false, enabled: true,location_scope:'Global'}, + { id: 1, title: 'Example 5' ,reviews:7.5,comments: 'Normal', filler: true, enabled: false,location_scope:'Office'}, + { id: 2, title: 'Life of Pi' ,reviews:7.5,comments: '...', filler: true, enabled: false,location_scope:'Regional'}, + { id: 3, title: 'South Park' ,reviews:7.5,comments: 'Random Comment here', filler: true, enabled: false,location_scope:'Global'}, + { id: 4, title: 'Cabinet of Curioisities' ,reviews:7.5,comments: 'wow 10/10 changed my life', filler: true, enabled: false,location_scope:'Office'}, + { id: 5, title: 'Babadook' ,reviews:7.5,comments: 'Member a comments', filler: true, enabled: false,location_scope:'Global'}, + { id: 6, title: 'Missing' ,reviews:7.5,comments: 'Nice movie', filler: true, enabled: false,location_scope:'Office'}, + { id: 7, title: 'Example 6' ,reviews:7.5,comments: 'Typical', filler: true, enabled: false,location_scope:'Regional'}, + { id: 8, title: 'Home Alone' ,reviews:7.5,comments: '', filler: true, enabled: false,location_scope:'Global'}, + { id: 9, title: 'Insert Title Here' ,reviews:7.5,comments: 'Some Comment insert here', filler: true, enabled: false,location_scope:'Office'}, + { id: 10, title: 'School of Rock' ,reviews:7.5,comments: '', filler: true, enabled: false,location_scope:'Regional'}, + { id: 11, title: 'Witcher' ,reviews:7.5,comments: 'Wow', filler: true, enabled: false,location_scope:'Global'}, + { id: 12, title: 'Pacific Rim' ,reviews:7.5,comments: '8/10', filler: true, enabled: false,location_scope:'Regional'}, + { id: 13, title: 'Journey to the center of the earth' ,reviews:7.5,comments: 'would recommend', filler: true, enabled: false,location_scope:'Office'}, + { id: 14, title: '2012' ,reviews:7.5,comments: 'Some other comment here', filler: true, enabled: false,location_scope:'Global'}, + { id: 15, title: 'Edge of Tomorrow' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Global'}, + ], +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index d0b636a..fd4d44e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5610,17 +5610,17 @@ adjust-sourcemap-loader@^4.0.0: loader-utils "^2.0.0" regex-parser "^2.2.11" -ag-grid-community@^25.1.0: - version "25.3.0" - resolved "https://registry.yarnpkg.com/ag-grid-community/-/ag-grid-community-25.3.0.tgz#9a0acce6d35f0c23313aa559dbd8acd737d5ef19" - integrity sha512-Xe4NZG0PP9kvhila1uHU4BeVfLDCWBmcuBYLBZ+49jvK+jYpuwdAjV3AwIlxpZGRR3WTdBUvUkSz9rmi2DRE3Q== +ag-grid-community@^27.0.1: + version "27.3.0" + resolved "https://registry.yarnpkg.com/ag-grid-community/-/ag-grid-community-27.3.0.tgz#b1e94a58026aaf2f0cd7920e35833325b5e762c7" + integrity sha512-R5oZMXEHXnOLrmhn91J8lR0bv6IAnRcU6maO+wKLMJxffRWaAYFAuw1jt7bdmcKCv8c65F6LEBx4ykSOALa9vA== -ag-grid-react@^25.1.0: - version "25.3.0" - resolved "https://registry.yarnpkg.com/ag-grid-react/-/ag-grid-react-25.3.0.tgz#7dce91fc7ef1821765357517562ba49299d4fddb" - integrity sha512-sRu4Mgxe26GkCKZL9XNMf/jbxLrYOuJo0pumD+LgA3e1x0mKeG8fqMbDLBKfKthIZbTaopIiwn4basThPnVdTg== +ag-grid-react@^27.0.1: + version "27.3.0" + resolved "https://registry.yarnpkg.com/ag-grid-react/-/ag-grid-react-27.3.0.tgz#fe06647653f8b0b349b8e613aab8ea2e07915562" + integrity sha512-2bs9YfJ/shvBZQLLjny4NFvht+ic6VtpTPO0r3bHHOhlL3Fjx2rGvS6AHSwfvu+kJacHCta30PjaEbX8T3UDyw== dependencies: - prop-types "^15.6.2" + prop-types "^15.8.1" agent-base@5: version "5.1.1" From 2b0e6060c7e7205a5d47dc8d63089911b88c05c2 Mon Sep 17 00:00:00 2001 From: Guk Hum Jaeson Cho Date: Thu, 20 Jul 2023 13:25:54 +0800 Subject: [PATCH 07/10] ZI-14098 cleaning up files --- src/components/NewComponent/GridContext.jsx | 73 -- src/components/NewComponent/GridStyles.scss | 11 - src/components/NewComponent/NewComponent.jsx | 695 ------------------- src/components/NewComponent/index.js | 2 - src/components/NewComponent/index.stories.js | 161 ----- 5 files changed, 942 deletions(-) delete mode 100644 src/components/NewComponent/GridContext.jsx delete mode 100644 src/components/NewComponent/GridStyles.scss delete mode 100644 src/components/NewComponent/NewComponent.jsx delete mode 100644 src/components/NewComponent/index.js delete mode 100644 src/components/NewComponent/index.stories.js diff --git a/src/components/NewComponent/GridContext.jsx b/src/components/NewComponent/GridContext.jsx deleted file mode 100644 index a133fb9..0000000 --- a/src/components/NewComponent/GridContext.jsx +++ /dev/null @@ -1,73 +0,0 @@ -import React, {createContext, useReducer} from 'react' - -export const initialState = { - columns: [], - rows:[], - sortColumn: null, - sortDirection: null, - filterColumns: [], - loading: false, -} - -export const GridContext = createContext([initialState,undefined]) - -export const actions ={ - RESET_GRID:'RESET_GRID', - SORT_COLUMN: 'SORT_COLUMN', - FILTER_COLUMN: 'FILTER_COLUMN', - CLEAR_FILTER_COLUMN:'CLEAR_FILTER_COLUMN', - LOAD_COLUMNS: 'LOAD_COLUMNS', - LOAD_ROWS: 'LOAD_ROWS', - SET_LOADING: 'SET_LOADING', - SET_LOADING_DONE: 'SET_LOADING_DONE' -} - -export const gridReducer = (state,action) => { - switch (action.type) { - case actions.SORT_COLUMN: - return { - ...state - } - case actions.FILTER_COLUMN: - return { - ...state - } - case actions.CLEAR_FILTER_COLUMN: - return { - ...state - } - case actions.LOAD_COLUMNS: - return { - ...state, - columns: action.payload.columns - } - case actions.LOAD_ROWS: - return { - ...state, - rows: action.payload.rows - } - case actions.SET_LOADING: - return { - ...state, - loading: true - } - case actions.SET_LOADING_DONE: - return { - ...state, - loading: false - } - default: - break; - } -} - -const GridProvider = ({ children }) => { - const [state, dispatch] = useReducer(gridReducer, initialState) - return ( - - {children} - - ) -} - -export default GridProvider \ No newline at end of file diff --git a/src/components/NewComponent/GridStyles.scss b/src/components/NewComponent/GridStyles.scss deleted file mode 100644 index b176773..0000000 --- a/src/components/NewComponent/GridStyles.scss +++ /dev/null @@ -1,11 +0,0 @@ -@import "ag-grid-community/src/styles/ag-grid.scss"; -@import "ag-grid-community/src/styles/ag-theme-alpine/sass/ag-theme-alpine-mixin.scss"; - -.ag-theme-alpine { - @include ag-theme-alpine(( - odd-row-background-color: #eceef1, - )); - } -.ag-root-wrapper { - border-radius: 20px -} diff --git a/src/components/NewComponent/NewComponent.jsx b/src/components/NewComponent/NewComponent.jsx deleted file mode 100644 index 0758b30..0000000 --- a/src/components/NewComponent/NewComponent.jsx +++ /dev/null @@ -1,695 +0,0 @@ -import React, {useState, useEffect, useRef, useCallback, useMemo} from 'react' -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faSort , faSortUp, faSortDown, faPlus, faBars, faFilter, faThumbtack,faEyeSlash } from '@fortawesome/free-solid-svg-icons'; -import SearchIcon from '@mui/icons-material/Search'; -import { render } from 'react-dom'; -import { AgGridColumn, AgGridReact } from 'ag-grid-react'; -import {actions as DataGridContext } from './GridContext' -import {Autocomplete, Button, Checkbox, Chip, Divider, FormControl, Grid, IconButton, InputLabel, InputAdornment, ListItemText , MenuItem, MenuList, OutlinedInput, Popover, Select, TextField, Typography, useTheme} from '@mui/material' -import { makeStyles } from 'tss-react/mui'; -import './GridStyles.scss' - - -function NewComponent({columns,rows,hasSearch}) { - const [gridApi, setGridApi] = useState(null); - const [gridColumnApi, setGridColumnApi] = useState(null); - const [isColumnsLoaded, setIsColumnsLoaded] = useState(false) - const [headerCustomSortDirection, setHeaderCustomSortDirection] = useState(null) - const [headerCustomSortColumn, setHeaderCustomSortColumn] = useState(null) - const [headerCustomFilters, setHeaderCustomFilters] = useState([]) - const [isRowsLoaded, setIsRowsLoaded] = useState(false) - // Filters - const [anchorElFilter, setAnchorElFilter] = useState(null) - const [selectedFilter, setSelectedFilter] = useState('') - const [selectedFilterOption, setSelectedFilterOption] = useState('') - const [selectedFilterOptionMultiple, setSelectedFilterOptionMultiple] = useState([]) - const [selectedNestedFilter, setSelectedNestedFilter] = useState('') - // Search - const [searchValue, setSearchValue] = useState('') - // useRefs - const tableRef = useRef(null) - const columnApi = useRef(null) - // Default - // Data - const [rowData,setRowData] = useState([]); - const [columnDefs,setColumnDefs] = useState([]) - - const updateSortColumn = (colId) => { - setHeaderCustomSortColumn(colId) - } - const updateSortDirection = (sortDir) => { - setHeaderCustomSortDirection(sortDir) - } - - const appendCustomFilter = (filter) => { - // insert custom filter here - setHeaderCustomFilters((prevData)=>({ - ...prevData, - filter - })) - } - - const removeCustomFilter = (filter) => { - // Remove custom filter here - let newCustomFilters = [] - headerCustomFilters.map((curr)=> { - if(curr === filter){ - // insert ignore here - }else{ - // add to newCustomFilters - } - }) - } -// Header/Column Actions - const SortColumn = async (col) => { - // await ResetSort(col) - let newColDef = col - if(col.headerCustomSortColumn === col.column.colId){ - if(col.headerCustomSortDirection === 'asc'){ - return col.updateSortDirection('desc') - }else if(col.headerCustomSortDirection === 'desc'){ - col.updateSortDirection(null) - return col.updateSortColumn(null) - }else{ - // set ascending sort logic here - return col.updateSortDirection(('asc')) - } - }else{ - col.updateSortDirection('asc') - return col.updateSortColumn(col.column.colId) - } - } - - const CustomizedHeader = (col) => { - const [anchorEl, setAnchorEl] = useState(null) - const [isHovered, setIsHovered] = useState(false) - const [currentSort, setCurrentSort] = useState(false) - useEffect(() => { - if(col.headerCustomSortColumn === col.column.colId){ - setCurrentSort(true) - } - }, [col.headerCustomSortColumn]) - - const handleMouseEnter = () => { - setIsHovered(true); - } - - const handleMouseLeave = () => { - setIsHovered(false); - } - const handleDivClick = async () => { - if(col.enableSorting){ - await SortColumn(col) - } - } - const handlePopoverClick = (event) => { - setAnchorEl(event.currentTarget); - }; - - const handlePopoverClose = () => { - setAnchorEl(null); - }; - // Pinning - const handlePinRight = () => { - col.columnApi.setColumnPinned(col.column.colId,'right') - handlePopoverClose() - } - const handlePinLeft = () => { - col.columnApi.setColumnPinned(col.column.colId,'left') - handlePopoverClose() - } - const handleUnpin = () => { - col.columnApi.setColumnPinned(col.column.colId, false) - handlePopoverClose() - } - const handleHide = () => { - col.columnApi.setColumnVisible(col.column.colId,false) - } - const sampleClick =() => { - handlePopoverClose() - } - - return ( -
- - - - - - { (col.column.pinned === null || col.column.pinned === 'left') && ( -
- -
) - } - { (col.column.pinned === null || col.column.pinned === 'right') && ( -
- -
) - } - { (col.column.pinned === 'right' || col.column.pinned === 'left') && ( -
- -
) - } - -
- -
-
-
-
- {col.displayName} - { col.enableSorting && (isHovered || currentSort) && ( - (!currentSort || col.headerCustomSortDirection === null )? - <> - - - - : col.headerCustomSortDirection === 'desc' ? - <> - - - : - <> - - - )} -
-
- ) - } - - const defaultColDef = { - resizable: true, - flex: 1, - headerComponent: CustomizedHeader, - headerComponentParams: { - headerCustomSortDirection: headerCustomSortDirection, - updateSortDirection: updateSortDirection, - headerCustomSortColumn: headerCustomSortColumn, - updateSortColumn: updateSortColumn, - } - } - - const onGridReady = (params) => { - columnApi.current = params.columnApi - } - - const isRowsEmpty = () => { - if(rowData.length === 0 && isRowsLoaded){ - return true - }else{ - return false - } - } - - const isDataLoaded =() => { - if(rowData.length >= 0 && isRowsLoaded){ - if(columnDefs.length >= 0 && isColumnsLoaded){ - return true - }else{ - return false - } - }else{ - return false - } - } - - const constructFilter = (element) => { - // Sort input type = autocomplete, default, checkbox, nested, ... - console.log("Filter: ",element) - let filterObject = { - label:element.field.charAt(0).toUpperCase() + element.field.slice(1), - isActive:false, - type:'default' - } - if(element.filter.label){ - filterObject={ - ...filterObject, - label:element.filter.label - } - } - if(element.filter.type){ - filterObject = { - ...filterObject, - type: element.filter.type - } - } - if(element.filter.options){ - filterObject={ - ...filterObject, - options: element.filter.options - } - } - console.log(filterObject) - return filterObject - } - - // Update when props change - useEffect(() => { - if(columns){ - if(columns.length >= 0){ - let newColumns = [] - let updatedArray = [] - columns.forEach((element,i) => { - console.log("Checking out this column: ",element) - const newElement = { - ...element - } - newColumns[i] = newElement - // Filters - if(element.filter){ - let filterObject = constructFilter(element) - // default value - updatedArray = [...updatedArray,filterObject] - } - - }); - setHeaderCustomFilters(updatedArray) - setColumnDefs(newColumns) - setIsColumnsLoaded(true) - } - }else{ - } - - }, [columns]) - - useEffect(() => { - if(rows){ - if(rows.length === 0){ - setRowData(rows) - setIsRowsLoaded(true) - }else if(rows.length > 0){ - setRowData(rows) - setIsRowsLoaded(true) - } - }else{ - } - }, [rows]) - - const handlePopoverFilterClick = (e) => { - setAnchorElFilter(e.currentTarget) - } - const handlePopoverFilterClose = () => { - setSelectedFilter('') - setSelectedFilterOption('') - setSelectedNestedFilter('') - setSelectedFilterOptionMultiple([]) - setAnchorElFilter(null) - } - const sampleClick = () => { - console.log('click') - - } - // SEARCH - const handleSearchChange = (e) => { - setSearchValue(e.target.value) - // Insert Search - } - const handleSearchSubmit = (e) => { - console.log("Search Value: ",searchValue) - } - - // FILTERS - const handleSelectedFilter = (e) => { - setSelectedFilterOption('') - setSelectedNestedFilter('') - setSelectedFilterOptionMultiple([]) - setSelectedFilter(e.target.value) - } - const handleSelectedFilterOption = (e) => { - setSelectedFilterOption(e.target.value) - } - const handleSelectedFilterAutocomplete = (e,v) => { - if(v){ - setSelectedFilterOption(v.value) - }else{ - setSelectedFilterOption('') - } - } - const handleSelectedFilterOptionMultiple = (e) => { - console.log("mult options") - console.log(e.target.value) - const currArray = e.target.value - let newArray = [] - currArray.forEach(element => { - newArray = [...newArray,element.value] - }); - - setSelectedFilterOptionMultiple(e.target.value) - setSelectedFilterOption(newArray) - } - const handleSelectedNestedFilter = (e) => { - console.log("Selected Nested Filter: ",e.target.value) - if(e.target.value.nestedOptions){ - setSelectedNestedFilter(e.target.value) - }else{ - setSelectedNestedFilter(e.target.value) - setSelectedFilterOption(e.target.vlue) - } - } - const handleApplyFilter = (e) =>{ - // Find the target filter in the headerCustomFilters array - let targetFilter = headerCustomFilters.find(obj => obj.label === selectedFilter.label); - console.log("Target Filter: ", targetFilter); - // consider nested property - if(targetFilter.type==='nestedAutocomplete'){ - // newFilter = selectedFilterOption - console.log("Nested: ", selectedFilterOption) - } - // Update the target filter's isActive property - if (targetFilter) { - targetFilter.isActive = true; - - // Create a new array with the updated filter - const updatedFilters = headerCustomFilters.map(obj => obj.label === selectedFilter.label ? targetFilter : obj); - - // Update the state with the updated filters - setHeaderCustomFilters(updatedFilters); - } - - handlePopoverFilterClose() - - } - const handleChipDelete = (deletedElement) => { - const updatedFilters = headerCustomFilters.map(element => { - if (element === deletedElement) { - return { ...element, isActive: false }; - } - return element; - }); - - setHeaderCustomFilters(updatedFilters); - console.log(headerCustomFilters); - - } - // Debug - useEffect(() => { - console.log("Custom Filters: ",headerCustomFilters) - }, [headerCustomFilters]) - useEffect(() => { - console.log("selectedFilter: ",selectedFilter) - }, [selectedFilter]) - useEffect(() => { - console.log("Selected Filter Option: ",selectedFilterOption) - }, [selectedFilterOption]) - - return ( - - - - - {/* If filter: */} - { headerCustomFilters.length > 0 && ( - -
- - - Filters: - - { //Display chips here - headerCustomFilters.filter(obj => obj.isActive === true).map(element => ( - handleChipDelete(element)} style={{marginLeft:'0.5rem',paddingTop:'2px'}} /> - )) - } -
- { //only display add filter button if headerCustomFilter.length < activeFilters.length - (headerCustomFilters.filter(obj => obj.isActive === false).length > 0 )&& ( - <> - - - - -
-
- - {/* Filters: */} - - - - - { selectedFilter === '' ? //insert here filter type - <> - : - selectedFilter.type === 'default' ? - - { //loop for every active filter - selectedFilter?.options &&( - selectedFilter.options.map(element => ( - - {element.label} - - )) - ) - } - - : - selectedFilter.type === 'autocomplete' ? - } - /> - : - selectedFilter.type === 'multiple' ? - - - - : - <> - - - - - { selectedNestedFilter.nestedOptions && ( - <> - } - /> - - ) - } - - } - - - - - - - - -
-
-
- ) - } -
- )} -
- - {/* If has search */} - - {hasSearch && ( - - - - Search - - - - - - - } - /> - - - )} - -
-
- -
- - -
-
-
- ) -} - -export default NewComponent \ No newline at end of file diff --git a/src/components/NewComponent/index.js b/src/components/NewComponent/index.js deleted file mode 100644 index 4208fe3..0000000 --- a/src/components/NewComponent/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import NewComponent from "./NewComponent" -export {NewComponent}; \ No newline at end of file diff --git a/src/components/NewComponent/index.stories.js b/src/components/NewComponent/index.stories.js deleted file mode 100644 index 1a4e01f..0000000 --- a/src/components/NewComponent/index.stories.js +++ /dev/null @@ -1,161 +0,0 @@ -import React from 'react' -import {NewComponent} from "." - -const NewComponentStory = { - title: "NewComponent", - component: NewComponent -} - -export default NewComponentStory - -export const DefaultStory =({...args}) => { - return -} - -export const Default = DefaultStory.bind({}); -Default.args = { - hasSearch:true, - columns: [ - { - field: 'id', headerName:"ID", sortable:true , width:120, flex:0, - }, - { - field: 'title', sortable:true - }, - { - field:'location_scope', headerName:'Scope', sortable: true, - filter: { - type: 'nestedAutocomplete', - label: "Location Scope", - options:[ - { - label: 'Global', - value: 'global' - }, - { - label: 'Country', - value: 'country', - nestedOptions:[ - { - label: 'Philippines', - value: '1' - }, - { - label: 'US', - value: '2' - }, - { - label: 'Canada', - value: '3' - }, - { - label: 'Japan', - value: '4' - } - ] - }, - { - label:'Office', - value:'office', - nestedOptions:[ - { - label: 'Manila - Cebu', - value: '1' - }, - { - label: 'Manila - Makati', - value: '2' - } - ] - }, - ] - } - - }, - { - field: 'reviews',sortable:true, - filter:{ - type:'autocomplete', - options:[ - { - label:'Low', - value:6 - }, - { - label: 'High', - value: 5 - }, - { - label: 'Mid', - value: 4 - }, - { - label: 'Good', - value: 3 - }, - { - label: 'Bad', - value: 2 - } - ] - } - }, - { - field: 'comments',sortable:true}, - { - field: 'filler',sortable:true, - filter:{ - type:'multiple', - options:[ - { - label: 'True', - value: true - }, - { - label: 'False', - value: false - }, - { - label: 'Null', - value: null - } - ] - } - }, - { - field: 'enabled',sortable:true - ,filter:{ - label:"Enabled", - options:[ - { - label: 'Enabled', - value: 0, - key:'key1' - }, - { - label: 'Disabled', - value: 1, - key:'key2' - } - ]} - }, - ], - rows: [ - { id: 0, title: 'Example 4', reviews:10,comments: 'rad', filler: false, enabled: true,location_scope:'Global'}, - { id: 1, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Office'}, - { id: 2, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Regional'}, - { id: 3, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Global'}, - { id: 4, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Office'}, - { id: 5, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Global'}, - { id: 6, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Office'}, - { id: 7, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Regional'}, - { id: 8, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Global'}, - { id: 9, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Office'}, - { id: 10, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Regional'}, - { id: 11, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Global'}, - { id: 12, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Regional'}, - { id: 13, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Office'}, - { id: 14, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Global'}, - { id: 15, title: 'Demo' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Global'}, - ], -} \ No newline at end of file From c671d453a50b3f8a5b7161ff205d947802433f34 Mon Sep 17 00:00:00 2001 From: Guk Hum Jaeson Cho Date: Tue, 1 Aug 2023 16:50:38 +0800 Subject: [PATCH 08/10] ZI-14098 Modular data grid created w/ templates --- package.json | 4 +- src/components/DataGridv3/CustomHeader.jsx | 233 +++++++++++++++ src/components/DataGridv3/DataGrid.jsx | 109 +++++++ src/components/DataGridv3/GenerateMockData.js | 47 +++ src/components/DataGridv3/GridContext.jsx | 93 ++++++ src/components/DataGridv3/GridStyles.scss | 24 ++ src/components/DataGridv3/index.js | 2 + src/components/DataGridv3/index.stories.js | 270 ++++++++++++++++++ 8 files changed, 780 insertions(+), 2 deletions(-) create mode 100644 src/components/DataGridv3/CustomHeader.jsx create mode 100644 src/components/DataGridv3/DataGrid.jsx create mode 100644 src/components/DataGridv3/GenerateMockData.js create mode 100644 src/components/DataGridv3/GridContext.jsx create mode 100644 src/components/DataGridv3/GridStyles.scss create mode 100644 src/components/DataGridv3/index.js create mode 100644 src/components/DataGridv3/index.stories.js diff --git a/package.json b/package.json index a76cc89..07cc705 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,8 @@ "@testing-library/react": "^12.1.5", "@testing-library/user-event": "^14.4.3", "@wojtekmaj/react-hooks": "^1.17.2", - "ag-grid-community": "^27.0.1", - "ag-grid-react": "^27.0.1", + "ag-grid-community": "latest", + "ag-grid-react": "latest", "axios": "^1.2.1", "branch-sdk": "^2.59.0", "clsx": "^1.1.1", diff --git a/src/components/DataGridv3/CustomHeader.jsx b/src/components/DataGridv3/CustomHeader.jsx new file mode 100644 index 0000000..276fb31 --- /dev/null +++ b/src/components/DataGridv3/CustomHeader.jsx @@ -0,0 +1,233 @@ +import React, {useState, useEffect, useRef, useCallback, useMemo, useContext, memo} from 'react' +import { AgGridColumn, AgGridReact } from 'ag-grid-react'; +import {GridContext, actions} from "./GridContext"; +import { render } from 'react-dom'; +import { debounce } from 'lodash'; +import { makeStyles } from 'tss-react/mui'; +import {Autocomplete, Box, Button, Checkbox, Chip, Divider, FormControl, Grid, IconButton, InputLabel, InputAdornment, ListItemText , MenuItem, MenuList, OutlinedInput, Popover, Select, TextField, Typography, useTheme} from '@mui/material' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faSort , faSortUp, faSortDown, faPlus, faBars, faFilter, faThumbtack, faEye, faEyeSlash } from '@fortawesome/free-solid-svg-icons'; + +const CustomHeader= memo((props)=>{ + const [state,dispatch] = useContext(GridContext) + const [anchorEl, setAnchorEl] = useState(null) + const [isHovered, setIsHovered] = useState(false) + const [currentSort, setCurrentSort] = useState(false) + const [isColHidden, setIsColHidden] = useState(false) + + const handlePopoverClick = (event) => { + setAnchorEl(event.currentTarget); + } + + const handlePopoverClose = () => { + setAnchorEl(null); + } + // Pinning + const handlePinRight = () => { + props.columnApi.setColumnPinned(props.column.colId,'right') + handlePopoverClose() + } + const handlePinLeft = () => { + props.columnApi.setColumnPinned(props.column.colId,'left') + handlePopoverClose() + } + const handleUnpin = () => { + props.columnApi.setColumnPinned(props.column.colId, false) + handlePopoverClose() + } + const handleHide = () => { + props.columnApi.setColumnVisible(props.column.colId,false) + } + const handleUnhide = () => { + props.columnApi.getColumns().map((element)=>{ + props.columnApi.setColumnVisible(element.colId,true) + }) + } + + function onSortClicked(event) { + // alternative client side sort + props.progressSort(event.shiftKey); + }; + + const checkColHidden= ()=>{ + props.columnApi.getColumns().map((element)=>{ + if(!element.visible){ + return setIsColHidden(true) + } + }) + return setIsColHidden(false) + } + + useEffect(() => { + if(state?.sortDirection != null){ + if(state?.sortColumn && state?.sortColumn === props?.column?.colId){ + return setCurrentSort(true) + }else{ + return setCurrentSort(false) + } + }else{ + return setCurrentSort(false) + } + + }, [state?.sortColumn]) + + const setHoveredTrue =()=>{ + setIsHovered(true) + } + const setHoveredFalse= ()=>{ + setIsHovered(false) + } + + const handleSort=(props)=>{ + if( state?.sortColumn !== null && props?.column?.colId == state?.sortColumn){ + if(state?.sortDirection === 'asc'){ + dispatch({ + type: actions.SORT_DIRECTION, + payload:{ + sortDirection: 'desc' + } + }) + + }else if(state?.sortDirection === 'desc'){ + // setSortDirection(null) + dispatch({ + type: actions.SORT_DIRECTION, + payload:{ + sortDirection: null + } + }) + dispatch({ + type:actions.SORT_COLUMN, + payload:{ + sortColumn: null + } + }) + }else{ + // setSortDirection('asc') + dispatch({ + type: actions.SORT_DIRECTION, + payload:{ + sortDirection: 'asc' + } + }) + } + }else{//set to asc + dispatch({ + type:actions.SORT_COLUMN, + payload:{ + sortColumn: props?.column?.colId + } + }) + dispatch({ + type: actions.SORT_DIRECTION, + payload:{ + sortDirection: 'asc' + } + }) + } + } + + return ( +
+ + + + + + { (props.column.pinned === null || props.column.pinned === 'left') && ( +
+ +
) + } + { (props.column.pinned === null || props.column.pinned === 'right') && ( +
+ +
) + } + { (props.column.pinned === 'right' || props.column.pinned === 'left') && ( +
+ +
) + } + + +
+ +
+ + +
+ +
+ +
+
+ { + //this is a sample of a client-side sorting + // onSortClicked(event) + // }} + + onClick={(event)=> {if(props?.enableSorting) handleSort(props)}} + onTouchStart ={(event)=>{if(props?.enableSorting) handleSort(props)}} + onMouseEnter={setHoveredTrue} + onMouseLeave={setHoveredFalse} + > + {props?.displayName} + + { props?.enableSorting && (isHovered || currentSort) && ( + (!currentSort || state?.sortDirection === null )? + <> + + + + : state?.sortDirection === 'desc' ? + <> + + + : + <> + + + )} + + +
+ ) +}) + +export default CustomHeader \ No newline at end of file diff --git a/src/components/DataGridv3/DataGrid.jsx b/src/components/DataGridv3/DataGrid.jsx new file mode 100644 index 0000000..023eeea --- /dev/null +++ b/src/components/DataGridv3/DataGrid.jsx @@ -0,0 +1,109 @@ +import React, {useState, useEffect, useRef, useCallback, useMemo, useContext, memo} from 'react' +import { AgGridColumn, AgGridReact } from 'ag-grid-react'; +import {GridContext, actions} from "./GridContext"; +import CustomHeader from "./CustomHeader" +import { render } from 'react-dom'; +import { debounce } from 'lodash'; +import { makeStyles } from 'tss-react/mui'; +import {Autocomplete, Box, Button, Checkbox, Chip, Divider, FormControl, Grid, IconButton, InputLabel, InputAdornment, ListItemText , MenuItem, MenuList, OutlinedInput, Popover, Select, TextField, Typography, useTheme} from '@mui/material' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faSort , faSortUp, faSortDown, faPlus, faBars, faFilter, faThumbtack,faEyeSlash } from '@fortawesome/free-solid-svg-icons'; + +//======================= MAIN ===================== +function DataGrid(props) { + const [state,dispatch] = useContext(GridContext) + const [sortColumn, setSortColumn] = useState(null) + const [sortDirection, setSortDirection] = useState(null) + const gridRef = useRef() + + + const components = { + agColumnHeader: CustomHeader + } + + const defaultColDef = { + resizable: true, + flex:1 + } + const columnTypes ={ + centerAligned: { + cellStyle: { + display: 'flex ', + justifyContent: 'center', + alignItems: 'center ' + } + }, + } + + useEffect(() => { + if(state.loading == true){ + // Start Loading + gridRef?.current?.api?.showLoadingOverlay() + + }else{ + // Remove loading + gridRef?.current?.api?.hideOverlay() + + } + }, [state.loading]) + + useEffect(() => { + dispatch({ + type:actions.SORT_DIRECTION, + payload:{ + sortDirection: sortDirection + } + }) + }, [sortDirection]) + + + useEffect(() => { + dispatch({ + type:actions.SORT_COLUMN, + payload:{ + sortColumn: sortColumn + } + }) + }, [sortColumn]) + + + + useEffect(() => { + console.log("props passed") + dispatch({ + type: actions.LOAD_ROWS, + payload:{ + rows: props?.gridProps?.rows ?? [] + } + }) + dispatch({ + type: actions.LOAD_COLUMNS, + payload:{ + columns: props?.gridProps?.columns ?? [] + } + }) + + }, []) + + return ( +
+ Please wait while your rows are loading` + + // } + {...props.gridProps} + /> +
+ ) +} + + + +export default DataGrid \ No newline at end of file diff --git a/src/components/DataGridv3/GenerateMockData.js b/src/components/DataGridv3/GenerateMockData.js new file mode 100644 index 0000000..7a9dd7b --- /dev/null +++ b/src/components/DataGridv3/GenerateMockData.js @@ -0,0 +1,47 @@ +import React from 'react' + +function getRandomNumber(min, max) { + return Math.floor(Math.random() * (max - min + 1) + min); +} + +function getRandomTitle() { + const names = ['Breaking Bad', 'Peaky Blinders', 'Game Of Thrones', 'The Boys', 'Missing', 'The Three Idiots', 'Overlord', 'Taken']; + return names[getRandomNumber(0, names.length - 1)]; +} + +function getRandomComment() { + const comments = [ + 'Great work!', + 'Needs improvement.', + 'Very informative.', + 'Not clear enough.', + 'Excellent!', + 'Could be better.', + 'Nice job!', + 'Confusing.', + ]; + return comments[getRandomNumber(0, comments.length - 1)]; +} + +function GenerateMockData(numRows) { + const rowData = []; + let idCounter = 1; + + for (let i = 0; i < numRows; i++) { + const row = { + id: idCounter++, + title: getRandomTitle(), + location_scope: ['Global', 'Office', 'Regional'][getRandomNumber(0, 2)], + reviews: getRandomNumber(1, 10), + comments: getRandomComment(), + filler: Math.random() < 0.5, // true or false randomly + enabled: Math.random() < 0.5, // true or false randomly + }; + + rowData.push(row); + } + + return rowData; +} + +export default GenerateMockData \ No newline at end of file diff --git a/src/components/DataGridv3/GridContext.jsx b/src/components/DataGridv3/GridContext.jsx new file mode 100644 index 0000000..9c30b23 --- /dev/null +++ b/src/components/DataGridv3/GridContext.jsx @@ -0,0 +1,93 @@ +import {createContext, useReducer} from 'react' + + +export const initialState = { + columns: [], + rows:[], + loading: false, + sortColumn: null, + sortDirection: null, + filterColumns: [], + search: null +} + +export const actions ={ + RESET_GRID:'RESET_GRID', + SORT_COLUMN: 'SORT_COLUMN', + SORT_DIRECTION:'SORT_DIRECTION', + FILTER_COLUMN: 'FILTER_COLUMN', + CLEAR_FILTER_COLUMN:'CLEAR_FILTER_COLUMN', + LOAD_COLUMNS: 'LOAD_COLUMNS', + LOAD_ROWS: 'LOAD_ROWS', + SET_LOADING: 'SET_LOADING', + SET_LOADING_DONE: 'SET_LOADING_DONE', + SET_SEARCH: 'SET_SEARCH', + TEST_DISPATCH: 'TEST_DISPATCH' +} + +export const GridContext = createContext() + +export function gridReducer(state,action){ + switch (action.type) { + case actions.TEST_DISPATCH: + return {...state} + case actions.SET_SEARCH: + return { + ...state, + search: action.payload.search + } + case actions.SORT_COLUMN: + return { + ...state, + sortColumn: action.payload.sortColumn + } + case actions.SORT_DIRECTION: + return { + ...state, + sortDirection: action.payload.sortDirection + } + case actions.FILTER_COLUMN: + return { + ...state, + filterColumns: action.payload.filterColumns ?? [] + } + case actions.CLEAR_FILTER_COLUMN: + return { + ...state + } + case actions.LOAD_COLUMNS: + return { + ...state, + columns: action.payload.columns + } + case actions.LOAD_ROWS: + return { + ...state, + rows: action.payload.rows + } + case actions.SET_LOADING: + return { + ...state, + loading: true + } + case actions.SET_LOADING_DONE: + return { + ...state, + loading: false + } + default: { + throw new Error(`Unhandled action type: ${action.type}`); + } + } +} + +export function DataGridProvider({ children }){ + const [state, dispatch] = useReducer(gridReducer, initialState); + return ( + + {children} + + ); +}; + +export default GridContext \ No newline at end of file diff --git a/src/components/DataGridv3/GridStyles.scss b/src/components/DataGridv3/GridStyles.scss new file mode 100644 index 0000000..cef9bf5 --- /dev/null +++ b/src/components/DataGridv3/GridStyles.scss @@ -0,0 +1,24 @@ +@use "~ag-grid-community/styles" as ag; + +@include ag.grid-styles(( + themes: (alpine, alpine-dark, belham ,belham-dark, material), + +)); + +.ag-theme-alpine { + &.custom-colors{ + --ag-header-background-color: hsl(177, 88%, 90%); + --ag-background-color: hsl(177, 88%, 97%); + --ag-odd-row-background-color: hsl(177, 88%, 95%); + --ag-alpine-active-color: hsl(0, 100%, 50%); + } +} + +.ag-theme-alpine-dark { + &.custom-border{ + --ag-borders: 1px; + } +} +// .ag-root-wrapper { +// // border: none +// } \ No newline at end of file diff --git a/src/components/DataGridv3/index.js b/src/components/DataGridv3/index.js new file mode 100644 index 0000000..8b8c3b0 --- /dev/null +++ b/src/components/DataGridv3/index.js @@ -0,0 +1,2 @@ +import DataGrid from "./DataGrid" +export {DataGrid}; \ No newline at end of file diff --git a/src/components/DataGridv3/index.stories.js b/src/components/DataGridv3/index.stories.js new file mode 100644 index 0000000..9dd4a98 --- /dev/null +++ b/src/components/DataGridv3/index.stories.js @@ -0,0 +1,270 @@ +import React, { useState, useEffect, useContext, useReducer, useMemo} from 'react' +import DataGrid from './DataGrid' +import { GridContext, actions, initialState, gridReducer , DataGridProvider} from './GridContext' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faSort , faSortUp, faSortDown, faPlus, faBars, faFilter, faThumbtack,faEyeSlash } from '@fortawesome/free-solid-svg-icons'; +import {Button, Chip, IconButton, Paper, Typography } from '@mui/material' +import GenerateMockData from './GenerateMockData' +import './GridStyles.scss' +const DataGridv3 = { + title: "DataGrid v3", + component: DataGrid +} + +export default DataGridv3 + +export const DefaultStory = ({...args}) => { + const [state,dispatch] = useReducer(gridReducer,initialState) + const [sortColumn, setSortColumn] = useState(null) + const [sortDirection, setSortDirection] = useState(null) + return ( + + + + + + ) +} + +export const Default = DefaultStory.bind({}); + + +Default.args = { + gridProps:{ + rows:GenerateMockData(100), + columns: [ + { field: 'id', headerName:"ID", sortable:true , flex:0, width:80 }, + { field: 'title', sortable:true }, + { field:'location_scope', headerName:'Scope', sortable: true }, + { field: 'reviews',sortable:true}, + { field: 'comments',sortable:true}, + { field: 'filler',sortable:true}, + { field: 'enabled',sortable:true}, + ] + } +} + + +export const LightTheme = DefaultStory.bind({}) + +LightTheme.args = { + gridProps:{ + gridTheme: 'ag-theme-alpine', + rows:GenerateMockData(15), + columns: [ + { field: 'id', headerName:"ID", sortable:true , flex:0, width:80 }, + { field: 'title', sortable:true }, + { field:'location_scope', headerName:'Scope', sortable: true }, + { field: 'reviews',sortable:true}, + { field: 'comments',sortable:true}, + { field: 'filler',sortable:true}, + { field: 'enabled',sortable:true}, + ] + } +} + +export const CustomColors = DefaultStory.bind({}) + +CustomColors.args = { + gridProps:{ + gridTheme: 'ag-theme-alpine custom-colors', + rows:GenerateMockData(15), + columns: [ + { field: 'id', headerName:"ID", sortable:true , flex:0, width:80 }, + { field: 'title', sortable:true }, + { field:'location_scope', headerName:'Scope', sortable: true }, + { field: 'reviews',sortable:true}, + { field: 'comments',sortable:true}, + { field: 'filler',sortable:true}, + { field: 'enabled',sortable:true}, + ] + } +} + +export const CellAlignment = DefaultStory.bind({}) + +CellAlignment.args={ + gridProps:{ + rows:GenerateMockData(15), + columns: [ + { field: 'id', headerName:"ID", sortable:true , flex:0, width:80 }, + { field: 'title', sortable:true }, + { field:'location_scope', headerName:'Scope', sortable: true }, + { field: 'reviews',sortable:true, type: 'rightAligned' }, + { field: 'comments',sortable:true}, + { field: 'filler',sortable:true,type: 'centerAligned'}, + { field: 'enabled',sortable:true, type: 'centerAligned'}, + ] + } +} + +export const CellRender = DefaultStory.bind({}) + +CellRender.args={ + gridProps:{ + rows:GenerateMockData(15), + columns: [ + { field: 'id', headerName:"ID", sortable:true , flex:0, width:80 }, + { field: 'title', sortable:true }, + { field:'location_scope', headerName:'Scope', sortable: true }, + { field: 'reviews',sortable:true}, + { field: 'comments',sortable:true}, + { field: 'filler',sortable:true, cellRenderer: params => { + return ( +
+ {params.value ? + + + : + + } +
+ ) + }}, + { field: 'enabled',sortable:true, cellRenderer: params => { + return ( +
+ {params.value ? + True + : + False + } +
+ ) + }}, + ] + } +} + +const LoadingStory = ({...args}) => { + const [state,dispatch] = useReducer(gridReducer,initialState) + + return ( + + + + + + ) +} + +function DGWrapper({...args}){ + const [state,dispatch] = useContext(GridContext) + + return( +
+ + + +
+ ) +} + +export const LoadingSample = LoadingStory.bind({}) + +LoadingSample.args = { + gridProps:{ + rows:GenerateMockData(10), + columns: [ + { field: 'id', headerName:"ID", sortable:true , flex:0, width:80 }, + { field: 'title', sortable:true }, + { field:'location_scope', headerName:'Scope', sortable: true }, + { field: 'reviews',sortable:true}, + { field: 'comments',sortable:true}, + { field: 'filler',sortable:true}, + { field: 'enabled',sortable:true}, + ] + } +} + +export const TemplateHeader = DefaultStory.bind({}) + +TemplateHeader.args = { + headerType:'serverSide', + gridProps:{ + rows:GenerateMockData(10), + columns: [ + { field: 'id', headerName:"ID", sortable:true , width:80 }, + { field: 'title', sortable:true }, + { field:'location_scope', headerName:'Scope', sortable: true }, + { field: 'reviews',sortable:true}, + { field: 'comments',sortable:true}, + { field: 'filler',sortable:true}, + { field: 'enabled',sortable:true}, + ] + } +} + + +const CustomHeaderStory = ({...args}) => { + const [state,dispatch] = useReducer(gridReducer,initialState) + + return ( + + + + + + ) +} + +function DGWrapperCustomHeader({...args}){ + const [state,dispatch] = useContext(GridContext) + + const CustomHeaderComponent=(props)=>{ + return ( +
+ + {props.displayName} + +
) + } + + const components = useMemo(()=>{ + return { + agColumnHeader: CustomHeaderComponent + } + }) + return( +
+ +
+ ) +} + + +export const CustomHeader = CustomHeaderStory.bind({}) + + +CustomHeader.args = { + gridProps:{ + rows:GenerateMockData(10), + columns: [ + { field: 'id', headerName:"ID", sortable:true , flex:0, width:80 }, + { field: 'title', sortable:true }, + { field:'location_scope', headerName:'Scope', sortable: true }, + { field: 'reviews',sortable:true}, + { field: 'comments',sortable:true}, + { field: 'filler',sortable:true}, + { field: 'enabled',sortable:true}, + ] + } +} + +function emulateFetch(rows){ + setTimeout(() => { + return rows.append(GenerateMockData(10)) + }, 2000); +} \ No newline at end of file From 68966d4b2fb9097110531db24763f3f8cdd2cb4f Mon Sep 17 00:00:00 2001 From: Guk Hum Jaeson Cho Date: Tue, 1 Aug 2023 17:25:53 +0800 Subject: [PATCH 09/10] ZI-14098 fixed build issues --- package.json | 4 ++-- src/components/table/Table.js | 6 ++++-- yarn.lock | 18 +++++++++--------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 07cc705..17982d2 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,8 @@ "@testing-library/react": "^12.1.5", "@testing-library/user-event": "^14.4.3", "@wojtekmaj/react-hooks": "^1.17.2", - "ag-grid-community": "latest", - "ag-grid-react": "latest", + "ag-grid-community": "30.0.6", + "ag-grid-react": "30.0.6", "axios": "^1.2.1", "branch-sdk": "^2.59.0", "clsx": "^1.1.1", diff --git a/src/components/table/Table.js b/src/components/table/Table.js index 78a13e6..c311bfa 100644 --- a/src/components/table/Table.js +++ b/src/components/table/Table.js @@ -2,8 +2,10 @@ import React, { useState } from "react"; import { AgGridColumn, AgGridReact } from "ag-grid-react"; import LogoCellRender from "./logoCellRender"; import TagCellRender from "./tagCellRender"; -import "ag-grid-community/dist/styles/ag-grid.css"; -import "ag-grid-community/dist/styles/ag-theme-alpine.css"; +// import "ag-grid-community/dist/styles/ag-grid.css"; +// import "ag-grid-community/dist/styles/ag-theme-alpine.css"; +import 'ag-grid-community/styles/ag-grid.css'; // Core grid CSS, always needed +import 'ag-grid-community/styles/ag-theme-alpine.css'; // Optional theme CSS import "./table.css"; export const Table = () => { diff --git a/yarn.lock b/yarn.lock index fd4d44e..bf68342 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5610,15 +5610,15 @@ adjust-sourcemap-loader@^4.0.0: loader-utils "^2.0.0" regex-parser "^2.2.11" -ag-grid-community@^27.0.1: - version "27.3.0" - resolved "https://registry.yarnpkg.com/ag-grid-community/-/ag-grid-community-27.3.0.tgz#b1e94a58026aaf2f0cd7920e35833325b5e762c7" - integrity sha512-R5oZMXEHXnOLrmhn91J8lR0bv6IAnRcU6maO+wKLMJxffRWaAYFAuw1jt7bdmcKCv8c65F6LEBx4ykSOALa9vA== - -ag-grid-react@^27.0.1: - version "27.3.0" - resolved "https://registry.yarnpkg.com/ag-grid-react/-/ag-grid-react-27.3.0.tgz#fe06647653f8b0b349b8e613aab8ea2e07915562" - integrity sha512-2bs9YfJ/shvBZQLLjny4NFvht+ic6VtpTPO0r3bHHOhlL3Fjx2rGvS6AHSwfvu+kJacHCta30PjaEbX8T3UDyw== +ag-grid-community@latest: + version "30.0.5" + resolved "https://registry.yarnpkg.com/ag-grid-community/-/ag-grid-community-30.0.5.tgz#284623c0af46f87bf0db84975caf7ae7461de59b" + integrity sha512-3AXrNx5hnH0/c4QNgNv5ub1Kna3wVPecCFq2ddMYQ6b7Ob8JhU4bMwcBf+GOiDepVc6I+Df6Bop6rGrc4O8OZw== + +ag-grid-react@latest: + version "30.0.5" + resolved "https://registry.yarnpkg.com/ag-grid-react/-/ag-grid-react-30.0.5.tgz#12c10bf2e977a785f1142062ae8957dd82b2b2cb" + integrity sha512-CmO2T52M4DDBXUJJO3R+7GTNFCBSWh5eDBQWdble9W7LhggLcEiQjaGHc7ZZlZbY1mUW9ov0EACbSB4N0qMDPw== dependencies: prop-types "^15.8.1" From 601c274163000e50e147f25460faf682502e1be3 Mon Sep 17 00:00:00 2001 From: Guk Hum Jaeson Cho Date: Tue, 1 Aug 2023 17:38:01 +0800 Subject: [PATCH 10/10] ZI-14098 fixed build issues 1 --- src/components/DataGridRemake2/DataGrid.jsx | 767 ------------------ .../DataGridRemake2/GridContext.jsx | 82 -- .../DataGridRemake2/GridStyles.scss | 16 - src/components/DataGridRemake2/index.js | 2 - .../DataGridRemake2/index.stories.js | 179 ---- 5 files changed, 1046 deletions(-) delete mode 100644 src/components/DataGridRemake2/DataGrid.jsx delete mode 100644 src/components/DataGridRemake2/GridContext.jsx delete mode 100644 src/components/DataGridRemake2/GridStyles.scss delete mode 100644 src/components/DataGridRemake2/index.js delete mode 100644 src/components/DataGridRemake2/index.stories.js diff --git a/src/components/DataGridRemake2/DataGrid.jsx b/src/components/DataGridRemake2/DataGrid.jsx deleted file mode 100644 index 1d93bc1..0000000 --- a/src/components/DataGridRemake2/DataGrid.jsx +++ /dev/null @@ -1,767 +0,0 @@ -import React, {useState, useEffect, useRef, useCallback, useMemo, useContext} from 'react' -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faSort , faSortUp, faSortDown, faPlus, faBars, faFilter, faThumbtack,faEyeSlash } from '@fortawesome/free-solid-svg-icons'; -import SearchIcon from '@mui/icons-material/Search'; -import { render } from 'react-dom'; -import { AgGridColumn, AgGridReact } from 'ag-grid-react'; -import {GridContext, actions} from "./GridContext"; -import {Autocomplete, Button, Checkbox, Chip, Divider, FormControl, Grid, IconButton, InputLabel, InputAdornment, ListItemText , MenuItem, MenuList, OutlinedInput, Popover, Select, TextField, Typography, useTheme} from '@mui/material' -import { makeStyles } from 'tss-react/mui'; -import { debounce } from 'lodash'; -import './GridStyles.scss' - -function DataGrid({columns, rows, hasSearch}) { - const [state,dispatch] = useContext(GridContext) - const [gridApi, setGridApi] = useState(null); - const [gridColumnApi, setGridColumnApi] = useState(null); -// Sort - const [headerCustomSortDirection, setHeaderCustomSortDirection] = useState(null) - const [headerCustomSortColumn, setHeaderCustomSortColumn] = useState(null) -// Filters - const [anchorElFilter, setAnchorElFilter] = useState(null) - const [selectedFilter, setSelectedFilter] = useState('') - const [headerCustomFilters, setHeaderCustomFilters] = useState([]) - const [selectedFilterOption, setSelectedFilterOption] = useState('') - const [selectedFilterOptionMultiple, setSelectedFilterOptionMultiple] = useState([]) - const [selectedNestedFilter, setSelectedNestedFilter] = useState('') -// Search - const [searchValue, setSearchValue] = useState('') -// useRefs - const tableRef = useRef(null) - const columnApi = useRef(null) -// Data - const [rowData,setRowData] = useState([]); - const [columnDefs,setColumnDefs] = useState([]) - - const constructFilter = (element) => { - // Sort input type = autocomplete, default, checkbox, nested, ... - console.log("Filter: ",element) - let filterObject = { - label:element.field.charAt(0).toUpperCase() + element.field.slice(1), - isActive:false, - type:'default', - selectedOption:null, - selectedNestedOption:null - } - if(element.filter.label){ - filterObject={ - ...filterObject, - label:element.filter.label - } - } - if(element.filter.type){ - filterObject = { - ...filterObject, - type: element.filter.type - } - } - if(element.filter.options){ - filterObject={ - ...filterObject, - options: element.filter.options - } - } - console.log(filterObject) - return filterObject - } -// Mounting - - - -// Update Handlers - const updateSortColumn = (colId) => { - // setHeaderCustomSortColumn(colId) - dispatch({ - type: actions.SORT_COLUMN, - payload:{ - sortColumn: colId - } - }) - } - - const updateSortDirection = (sortDir) => { - // setHeaderCustomSortDirection(sortDir) - dispatch({ - type: actions.SORT_DIRECTION, - payload:{ - sortDirection: sortDir - } - }) - } - - const appendCustomFilter = (filter) => { - // insert custom filter here - dispatch({ - type: actions.FILTER_COLUMN, - payload: [...state.filterColumns, filter] - }) - } - - const removeCustomFilter = (filter) => { - // Remove custom filter here - let newCustomFilters = [] - state?.filterColumns?.map((curr)=> { - if(curr === filter){ - // insert ignore here - }else{ - // add to newCustomFilters - } - }) - } - - - // Header Events: - const SortColumn = async (col) => { - // await ResetSort(col) - let newColDef = col - if(state?.sortColumn === col.column.colId){ - if(state?.sortDirection === 'asc'){ - return col.updateSortDirection('desc') - }else if(state?.sortDirection === 'desc'){ - col.updateSortDirection(null) - return col.updateSortColumn(null) - }else{ - // set ascending sort logic here - return col.updateSortDirection(('asc')) - } - }else{ - col.updateSortDirection('asc') - - return col.updateSortColumn(col.column.colId) - } - } - // useEffect Trackers / Memoization - // Debugging - useEffect(() => { - console.log("Sort: ", headerCustomSortColumn , headerCustomSortDirection) - }, [headerCustomSortColumn,headerCustomSortDirection]) - - useEffect(() => { - console.log("gridContext: ",state) - // dispatch({ - // type: actions.TEST_DISPATCH - // }) - }, [state]) - - - // Render: - const CustomizedHeader = (col) => { - const [anchorEl, setAnchorEl] = useState(null) - const [isHovered, setIsHovered] = useState(false) - const [currentSort, setCurrentSort] = useState(false) - useEffect(() => { - if(state?.sortColumn === col.column.colId){ - setCurrentSort(true) - } - }, [ state?.sortColumn]) - - const handleMouseEnter = () => { - setIsHovered(true); - } - - const handleMouseLeave = () => { - setIsHovered(false); - } - - const handleDivClick = async () => { - if(col.enableSorting){ - await SortColumn(col) - } - } - const handlePopoverClick = (event) => { - setAnchorEl(event.currentTarget); - } - - const handlePopoverClose = () => { - setAnchorEl(null); - } - // Pinning - const handlePinRight = () => { - col.columnApi.setColumnPinned(col.column.colId,'right') - handlePopoverClose() - } - const handlePinLeft = () => { - col.columnApi.setColumnPinned(col.column.colId,'left') - handlePopoverClose() - } - const handleUnpin = () => { - col.columnApi.setColumnPinned(col.column.colId, false) - handlePopoverClose() - } - const handleHide = () => { - col.columnApi.setColumnVisible(col.column.colId,false) - } - const sampleClick =() => { - handlePopoverClose() - } - return ( -
- - - - - - { (col.column.pinned === null || col.column.pinned === 'left') && ( -
- -
) - } - { (col.column.pinned === null || col.column.pinned === 'right') && ( -
- -
) - } - { (col.column.pinned === 'right' || col.column.pinned === 'left') && ( -
- -
) - } - -
- -
-
-
-
- {col.displayName} - { col.enableSorting && (isHovered || currentSort) && ( - (!currentSort || col.sortDirection === null )? - <> - - - - : state?.sortDirection === 'desc' ? - <> - - - : - <> - - - )} -
-
- ) - } - useEffect(() => { - console.log("Columns: ", columns) - if(columns){ - dispatch({ - type: actions.LOAD_COLUMNS, - payload:{ - columns: columns - } - }) - if(columns.length >= 0){ - let newColumns = [] - let updatedArray = [] - columns.forEach((element,i) => { - console.log("Checking out this column: ",element) - const newElement = { - ...element - } - newColumns[i] = newElement - // Filters - if(element.filter){ - let filterObject = constructFilter(element) - // default value - updatedArray = [...updatedArray,filterObject] - } - - }); - console.log("updatedArray: ",updatedArray) - dispatch({ - type: actions.FILTER_COLUMN, - payload: { - filterColumns: updatedArray - } - }) - dispatch({ - type: actions.LOAD_COLUMNS, - payload:{ - columns: columns - } - }) - dispatch({ - type: actions.SET_LOADING_DONE - }) - // setColumnDefs(newColumns) - } - } - }, [columns]); - -// Context listeners - useEffect(() => { - if(state.columns) - setColumnDefs(state.columns) - }, [state.columns]) - - useEffect(() => { - if(rows){ - if(rows.length >= 0){ - // setRowData(rows) - dispatch({ - type:actions.LOAD_ROWS, - payload:{ - rows: rows - } - }) - } - } - }, [rows]) - - // Grid - const defaultColDef = { - resizable: true, - flex: 1, - headerComponent: CustomizedHeader, - headerComponentParams: { - headerCustomSortDirection: headerCustomSortDirection, - updateSortDirection: updateSortDirection, - headerCustomSortColumn: headerCustomSortColumn, - updateSortColumn: updateSortColumn, - } - } - const onGridReady = (params) => { - columnApi.current = params.columnApi - } -// - const handlePopoverFilterClick = (e) => { - setAnchorElFilter(e.currentTarget) - } - const handlePopoverFilterClose = () => { - setSelectedFilter('') - setSelectedFilterOption('') - setSelectedNestedFilter('') - setSelectedFilterOptionMultiple([]) - setAnchorElFilter(null) - } - const sampleClick = () => { - console.log('click') - } - - const handleSearchChange =(e) => { - setSearchValue(e.target.value) - // Insert Search - debounce(()=>{ - dispatch({ - type: actions.SET_SEARCH, - payload: { - ...state, - search: e.target.value - } - }) - },500)() - - } - const handleSearchSubmit = (e) => { - dispatch({ - type: actions.SET_SEARCH, - payload: { - ...state, - search: searchValue - } - }) - } - -// FILTERS - const handleSelectedFilter = (e) => { - setSelectedFilterOption('') - setSelectedNestedFilter('') - setSelectedFilterOptionMultiple([]) - setSelectedFilter(e.target.value) - } - const handleSelectedFilterOption = (e) => { - setSelectedFilterOption(e.target.value) - } - const handleSelectedFilterAutocomplete = (e,v) => { - if(v){ - setSelectedFilterOption(v.value) - }else{ - setSelectedFilterOption('') - } - } - - const handleSelectedFilterOptionMultiple = (e) => { - console.log("mult options") - console.log(e.target.value) - const currArray = e.target.value - let newArray = [] - currArray.forEach(element => { - newArray = [...newArray,element.value] - }); - - setSelectedFilterOptionMultiple(e.target.value) - setSelectedFilterOption(newArray) - } - - const handleSelectedNestedFilter = (e) => { - console.log("Selected Nested Filter: ",e.target.value) - if(e.target.value.nestedOptions){ - setSelectedNestedFilter(e.target.value) - }else{ - setSelectedNestedFilter(e.target.value) - setSelectedFilterOption(e.target.vlue) - } - } - - - const handleApplyFilter = (e) =>{ - // Find the target filter in the headerCustomFilters array - let targetFilter = state?.filterColumns.find(obj => obj.label === selectedFilter.label); - const targetFilterIndex = state?.filterColumns.findIndex(obj => obj.label === selectedFilter.label); - let updatedFilterColumns = [...state.filterColumns]; - console.log("Target Filter: ", targetFilter, targetFilterIndex, e); - // consider nested property - if (targetFilterIndex !== -1){ - console.log("isActive") - // Update the target filter's isActive property - if (targetFilter) { - updatedFilterColumns[targetFilterIndex] = { - ...updatedFilterColumns[targetFilterIndex], - isActive: true, - selectedOption: selectedFilterOption, - }; - if(targetFilter.type==='nestedAutocomplete'){ - updatedFilterColumns[targetFilterIndex] = { - ...updatedFilterColumns[targetFilterIndex], - selectedNestedOption: selectedNestedFilter - }; - } - // Create a new array with the updated filter - // Update the state with the updated filters - // setHeaderCustomFilters(updatedFilters); - dispatch({ - type:actions.FILTER_COLUMN, - payload:{ - filterColumns:updatedFilterColumns - } - }) - } - } - console.log("Close") - handlePopoverFilterClose() - } - - const handleChipDelete = (deletedElement) => { - const updatedFilters = state?.filterColumns.map(element => { - if (element === deletedElement) { - console.log("Element: ",element," deleted Element: ",deletedElement) - return { ...element, - isActive: false, - selectedOption: null, - selectedNestedOption: null - }; - } - return element; - }); - - // setHeaderCustomFilters(updatedFilters); - dispatch({ - type:actions.FILTER_COLUMN, - payload:{ - filterColumns:updatedFilters - } - }) - console.log(state?.filterColumns); - } - - - return ( - - - - - {/* If filter: */} - { state?.filterColumns.length > 0 && ( - -
- - - Filters: - - - { //Display chips here - state?.filterColumns.filter(obj => obj.isActive === true).map(element => ( - handleChipDelete(element)} style={{marginLeft:'0.5rem',paddingTop:'2px',padding:'0 8px 0px 9px'}} /> - )) - } - -
- { //only display add filter button if headerCustomFilter.length < activeFilters.length - (state?.filterColumns.filter(obj => obj.isActive === false).length > 0 )&& ( - <> - - - - -
-
- - {/* Filters: */} - - - - - { selectedFilter === '' ? //insert here filter type - <> - : - selectedFilter.type === 'default' ? - - { //loop for every active filter - selectedFilter?.options &&( - selectedFilter.options.map(element => ( - - {element.label} - - )) - ) - } - - : - selectedFilter.type === 'autocomplete' ? - } - /> - : - selectedFilter.type === 'multiple' ? - - - - : - <> - - - - - { selectedNestedFilter.nestedOptions && ( - <> - } - /> - - ) - } - - } - - - - - - - - -
-
-
- ) - } -
- )} -
- - {/* If has search */} - - {hasSearch && ( - - - - Search - - - - - - - } - /> - - - )} - -
-
- -
- - -
-
-
- ) -} - -export default DataGrid \ No newline at end of file diff --git a/src/components/DataGridRemake2/GridContext.jsx b/src/components/DataGridRemake2/GridContext.jsx deleted file mode 100644 index e39497c..0000000 --- a/src/components/DataGridRemake2/GridContext.jsx +++ /dev/null @@ -1,82 +0,0 @@ -import {createContext, useReducer} from 'react' - -export const initialState = { - columns: [], - rows:[], - loading: false, - sortColumn: null, - sortDirection: null, - filterColumns: [], - search: null -} - -export const actions ={ - RESET_GRID:'RESET_GRID', - SORT_COLUMN: 'SORT_COLUMN', - FILTER_COLUMN: 'FILTER_COLUMN', - CLEAR_FILTER_COLUMN:'CLEAR_FILTER_COLUMN', - LOAD_COLUMNS: 'LOAD_COLUMNS', - LOAD_ROWS: 'LOAD_ROWS', - SET_LOADING: 'SET_LOADING', - SET_LOADING_DONE: 'SET_LOADING_DONE', - SET_SEARCH: 'SET_SEARCH', - TEST_DISPATCH: 'TEST_DISPATCH' -} - -export const GridContext = createContext() - -export function gridReducer(state,action){ - switch (action.type) { - case actions.TEST_DISPATCH: - return {...state} - case actions.SET_SEARCH: - return { - ...state, - search: action.payload.search - } - case actions.SORT_COLUMN: - return { - ...state, - sortColumn: action.payload.sortColumn - } - case actions.SORT_DIRECTION: - return { - ...state, - sortDirection: action.payload.sortDirection - } - case actions.FILTER_COLUMN: - return { - ...state, - filterColumns: action.payload.filterColumns ?? [] - } - case actions.CLEAR_FILTER_COLUMN: - return { - ...state - } - case actions.LOAD_COLUMNS: - return { - ...state, - columns: action.payload.columns - } - case actions.LOAD_ROWS: - return { - ...state, - rows: action.payload.rows - } - case actions.SET_LOADING: - return { - ...state, - loading: true - } - case actions.SET_LOADING_DONE: - return { - ...state, - loading: false - } - default: { - throw new Error(`Unhandled action type: ${action.type}`); - } - } -} - - diff --git a/src/components/DataGridRemake2/GridStyles.scss b/src/components/DataGridRemake2/GridStyles.scss deleted file mode 100644 index c59bb17..0000000 --- a/src/components/DataGridRemake2/GridStyles.scss +++ /dev/null @@ -1,16 +0,0 @@ -@import "ag-grid-community/src/styles/ag-grid.scss"; -@import "ag-grid-community/src/styles/ag-theme-alpine/sass/ag-theme-alpine-mixin.scss"; - - -.grid-wrapper{ - .ag-theme-alpine{ - @include ag-theme-alpine(( - theme: alpine, - // header-background-color:#86cac7, - // header-foreground-color:red - )); - } -} -.ag-root-wrapper { - border-radius: 20px -} diff --git a/src/components/DataGridRemake2/index.js b/src/components/DataGridRemake2/index.js deleted file mode 100644 index 8b8c3b0..0000000 --- a/src/components/DataGridRemake2/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import DataGrid from "./DataGrid" -export {DataGrid}; \ No newline at end of file diff --git a/src/components/DataGridRemake2/index.stories.js b/src/components/DataGridRemake2/index.stories.js deleted file mode 100644 index 9618a46..0000000 --- a/src/components/DataGridRemake2/index.stories.js +++ /dev/null @@ -1,179 +0,0 @@ -import React, { useEffect, useContext, useReducer} from 'react' -import DataGrid from './DataGrid' -import { GridContext, actions, initialState, gridReducer - //, GridProvider -} from './GridContext' - -const DataGridRemakeStory = { - title: "DataGridRemake2", - component: DataGrid -} - -export default DataGridRemakeStory - -export const DefaultStory = ({...args}) => { - const [state,dispatch] = useReducer(gridReducer,initialState) - - return - - -} -function DGWrapper({...args}){ - const [state,dispatch] = useContext(GridContext) - useEffect(() => { - console.log("State Shallow:",state.sortColumn) - }, [state.sortColumn]) - - return( - - ) -} - -export const Default = DefaultStory.bind({}); -Default.args = { - hasSearch:true, - // onSort:, - columns: [ - { - field: 'id', headerName:"ID", sortable:true , width:120, flex:0, - }, - { - field: 'title', sortable:true - }, - { - field:'location_scope', headerName:'Scope', sortable: true, - filter: { - type: 'nestedAutocomplete', - label: "Location Scope", - options:[ - { - label: 'Global', - value: 'global' - }, - { - label: 'Country', - value: 'country', - nestedOptions:[ - { - label: 'Philippines', - value: '1' - }, - { - label: 'US', - value: '2' - }, - { - label: 'Canada', - value: '3' - }, - { - label: 'Japan', - value: '4' - } - ] - }, - { - label:'Office', - value:'office', - nestedOptions:[ - { - label: 'Manila - Cebu', - value: '1' - }, - { - label: 'Manila - Makati', - value: '2' - } - ] - }, - ] - } - - }, - { - field: 'reviews',sortable:true, - filter:{ - type:'autocomplete', - options:[ - { - label:'Low', - value:6 - }, - { - label: 'High', - value: 5 - }, - { - label: 'Mid', - value: 4 - }, - { - label: 'Good', - value: 3 - }, - { - label: 'Bad', - value: 2 - } - ] - } - }, - { - field: 'comments',sortable:true}, - { - field: 'filler',sortable:true, - filter:{ - type:'multiple', - options:[ - { - label: 'True', - value: true - }, - { - label: 'False', - value: false - }, - { - label: 'Null', - value: null - } - ] - } - }, - { - field: 'enabled',sortable:true - ,filter:{ - label:"Enabled", - options:[ - { - label: 'Enabled', - value: 0, - key:'key1' - }, - { - label: 'Disabled', - value: 1, - key:'key2' - } - ]} - }, - ], - rows: [ - { id: 0, title: 'Example 4', reviews:10,comments: 'rad', filler: false, enabled: true,location_scope:'Global'}, - { id: 1, title: 'Example 5' ,reviews:7.5,comments: 'Normal', filler: true, enabled: false,location_scope:'Office'}, - { id: 2, title: 'Life of Pi' ,reviews:7.5,comments: '...', filler: true, enabled: false,location_scope:'Regional'}, - { id: 3, title: 'South Park' ,reviews:7.5,comments: 'Random Comment here', filler: true, enabled: false,location_scope:'Global'}, - { id: 4, title: 'Cabinet of Curioisities' ,reviews:7.5,comments: 'wow 10/10 changed my life', filler: true, enabled: false,location_scope:'Office'}, - { id: 5, title: 'Babadook' ,reviews:7.5,comments: 'Member a comments', filler: true, enabled: false,location_scope:'Global'}, - { id: 6, title: 'Missing' ,reviews:7.5,comments: 'Nice movie', filler: true, enabled: false,location_scope:'Office'}, - { id: 7, title: 'Example 6' ,reviews:7.5,comments: 'Typical', filler: true, enabled: false,location_scope:'Regional'}, - { id: 8, title: 'Home Alone' ,reviews:7.5,comments: '', filler: true, enabled: false,location_scope:'Global'}, - { id: 9, title: 'Insert Title Here' ,reviews:7.5,comments: 'Some Comment insert here', filler: true, enabled: false,location_scope:'Office'}, - { id: 10, title: 'School of Rock' ,reviews:7.5,comments: '', filler: true, enabled: false,location_scope:'Regional'}, - { id: 11, title: 'Witcher' ,reviews:7.5,comments: 'Wow', filler: true, enabled: false,location_scope:'Global'}, - { id: 12, title: 'Pacific Rim' ,reviews:7.5,comments: '8/10', filler: true, enabled: false,location_scope:'Regional'}, - { id: 13, title: 'Journey to the center of the earth' ,reviews:7.5,comments: 'would recommend', filler: true, enabled: false,location_scope:'Office'}, - { id: 14, title: '2012' ,reviews:7.5,comments: 'Some other comment here', filler: true, enabled: false,location_scope:'Global'}, - { id: 15, title: 'Edge of Tomorrow' ,reviews:7.5,comments: 'meh', filler: true, enabled: false,location_scope:'Global'}, - ], -} \ No newline at end of file