I used the code from this article as an example.
It is possible to read the data, but not to save it.
Code:
const { Component, Fragment } = wp.element;
const {
RichText,
InspectorControls,
PanelColorSettings,
AlignmentToolbar,
BlockControls,
} = wp.editor;
const { Button, PanelBody, SelectControl, TextControl } = wp.components;
const { __ } = wp.i18n;
const { registerBlockType } = wp.blocks;
const { withSelect, withDispatch } = wp.data;
class Inspector extends Component {
constructor(props) {
super(...arguments);
}
render() {
const backgroundColors = [
{ color: "#525252", name: "Черный" },
{ color: "#872d2d", name: "Акцентный красный" },
{ color: "#e49312", name: "Акцентный желтый" },
{ color: "#bab3a6", name: "Акцентный кремовый" },
];
const fontSizeOptions = [
{ value: "14px", label: __("14px") },
{ value: "16px", label: __("16px") },
{ value: "18px", label: __("18px") },
{ value: "22px", label: __("22px") },
{ value: "28px", label: __("28px") },
];
const paddingTopOptions = [
{ value: "0px", label: __("0px") },
{ value: "10px", label: __("10px") },
{ value: "25px", label: __("25px") },
{ value: "50px", label: __("50px") },
];
const paddingBottomOptions = [
{ value: "0px", label: __("0px") },
{ value: "10px", label: __("10px") },
{ value: "25px", label: __("25px") },
{ value: "50px", label: __("50px") },
];
const {
setAttributes,
attributes: { text_color, font_size, padding_top, padding_bottom },
} = this.props;
let PluginMetaFields = (props) => {
return (
<>
<TextControl
value={props.text_metafield}
label={__("Text Meta", "textdomain")}
onChange={(value) => props.onMetaFieldChange(value)}
/>
</>
);
};
PluginMetaFields = withSelect((select) => {
return {
text_metafield: select("core/editor").getEditedPostAttribute("meta")[
"_myprefix_text_metafield"
],
};
})(PluginMetaFields);
PluginMetaFields = withDispatch((dispatch) => {
return {
onMetaFieldChange: (value) => {
dispatch("core/editor").editPost({
meta: { _myprefix_text_metafield: value },
});
},
};
})(PluginMetaFields);
return (
<InspectorControls key="inspector">
<PanelBody title={__("Настройки абзаца")}>
<PanelColorSettings
title={__("Цвет шрифта")}
initialOpen={true}
colorSettings={[
{
value: text_color,
colors: backgroundColors,
onChange: (value) => setAttributes({ text_color: value }),
label: __("Цвет шрифта"),
},
]}
/>
<SelectControl
label={__("Размер шрифта")}
options={fontSizeOptions}
value={font_size}
onChange={(value) => this.props.setAttributes({ font_size: value })}
/>
<SelectControl
label={__("Отступ сверху")}
options={paddingTopOptions}
value={padding_top}
onChange={(value) =>
this.props.setAttributes({ padding_top: value })
}
/>
<SelectControl
label={__("Отступ снизу")}
options={paddingBottomOptions}
value={padding_bottom}
onChange={(value) =>
this.props.setAttributes({ padding_bottom: value })
}
/>
<PluginMetaFields />
</PanelBody>
</InspectorControls>
);
}
}
class HeadlineBlock extends Component {
render() {
const {
attributes: {
headline,
text_color,
font_size,
padding_top,
padding_bottom,
alignment,
},
setAttributes,
} = this.props;
const onChangeAlignment = (newAlignment) => {
this.props.setAttributes({
alignment: newAlignment === undefined ? "none" : newAlignment,
});
};
return [
<Inspector {...{ setAttributes, ...this.props }} />,
<div>
{
<BlockControls>
<AlignmentToolbar value={alignment} onChange={onChangeAlignment} />
</BlockControls>
}
<RichText
tagName="p"
placeholder={__("Текст...")}
keepPlaceholderOnFocus
value={headline}
formattingControls={["bold", "italic", "strikethrough", "link"]}
className={"font-" + font_size + " post-desc__p-text"}
style={{
color: text_color,
textAlign: alignment,
}}
onChange={(value) => setAttributes({ headline: value })}
/>
</div>,
];
}
}
registerBlockType("amm-custom-block/test-block", {
title: __("Тест блок"),
icon: "shield",
category: "AMM",
attributes: {
headline: {
type: "string",
},
alignment: {
type: "string",
default: "none",
},
text_color: {
type: "string",
default: "#525252",
},
font_size: {
type: "string",
default: "14px",
},
padding_top: {
type: "string",
default: "50px",
},
padding_bottom: {
type: "string",
default: "0px",
},
},
edit: HeadlineBlock,
save: function (props) {
const {
attributes: {
headline,
text_color,
font_size,
padding_top,
padding_bottom,
alignment,
},
} = props;
return (
<Fragment>
{headline && !!headline.length && (
<RichText.Content
tagName="p"
className={"font-" + font_size + " post-desc__p-text"}
style={{
color: text_color,
paddingTop: padding_top,
paddingBottom: padding_bottom,
textAlign: alignment,
}}
value={headline}
/>
)}
</Fragment>
);
},
});
So far just added a text field to the block and am trying to read and save the data.
With reading everything is OK, but saving the data does not work and there are no errors.
Any idea why this is happening?
sorry english is not a native language
The meta field _myprefix_text_metafield is a protected field as it starts with a "_" (underscore). This is why you can read the value in withSelect() but not save over it withDispatch() without passing auth_callback.
To save to a protected field, the auth_callback is required, eg:
<?php
register_post_meta( 'post', '_myprefix_text_metafield', array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'auth_callback' => function() {
return current_user_can( 'edit_posts' );
})
);
?>
There is an example in the tutorial you are following:
https://css-tricks.com/managing-wordpress-metadata-in-gutenberg-using-a-sidebar-plugin/#post-291605
Alternatively, if your meta field is not required to be protected/private: re-register your meta field as myprefix_text_metafield (no underscore in the name and no auth_callback) and your current code will work, eg:
<?php
register_post_meta( 'post', 'myprefix_text_metafield', array(
'show_in_rest' => true,
'single' => true,
'type' => 'string'
);
?>
Related
My goal is that when user select a checkbox of one of the fathers ('Non Veg Biryanis','Pizzas','Drinks','Deserts') in the flatlist, then those sons who belong to him are also selected.
When the check box is removed from all the children belonging to the same father, then the check box is also removed for the father as well.
this is my example (but its not works as can see, the father 'Pizzas' not checked but his sons checked)
The data is:
[
{
title: 'Non Veg Biryanis',
checked: false,
data: [
{ key: 'chicken', value: false, checked: false },
{ key: 'meat', value: false, checked: false },
{ key: 'veg', value: false, checked: false },
],
},
{
title: 'Pizzas',
checked: false,
data: [
{ key: 'olives', value: false, checked: false },
{ key: 'green cheese', value: false, checked: false },
{ key: 'paprika', value: false, checked: false },
],
},
{
title: 'Drinks',
checked: false,
data: [
{ key: 'cola', value: false, checked: false },
{ key: 'sprite', value: false, checked: false },
{ key: 'orange', value: false, checked: false },
],
},
{
title: 'Deserts',
checked: false,
data: [
{ key: 'cake', value: false, checked: false },
{ key: 'ice-cream', value: false, checked: false },
{ key: 'pie', value: false, checked: false },
],
},
]
The Accordian:
import React, { useState } from 'react';
import { View, TouchableOpacity, Text, FlatList, LayoutAnimation, Platform, UIManager } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons';
import styles from './AccordianStyle';
const Accordian = props => {
const [data, setData] = useState(props.item);
const [expanded, setExpanded] = useState(false);
if (Platform.OS === 'android') {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
const onClick = (index: number) => {
console.log(data);
const temp = { ...data };
temp.data[index].checked = !temp.data[index].checked;
setData(temp);
};
const onClickFather = () => {
const temp = { ...data };
temp.checked = !temp.checked;
if (temp.checked) {
temp.data = temp.data.map((item: { checked: boolean }) => {
item.checked = true;
});
}
console.log(temp);
setData(temp);
};
const toggleExpand = () => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
setExpanded(!expanded);
};
return (
<View>
<View style={styles.row}>
<TouchableOpacity onPress={() => onClickFather()}>
<Icon name={'check-circle'} size={24} color={data.checked ? 'green' : '#d3d7de'} />
</TouchableOpacity>
<Text style={[styles.title]}>{data.title}</Text>
<TouchableOpacity style={styles.row} onPress={() => toggleExpand()}>
<Icon name={expanded ? 'keyboard-arrow-up' : 'keyboard-arrow-down'} size={30} color={'grey'} />
</TouchableOpacity>
</View>
<View style={styles.parentHr} />
{expanded && (
<View style={{}}>
<FlatList
data={data.data}
numColumns={1}
scrollEnabled={false}
renderItem={({ item, index }) => (
<View>
<TouchableOpacity
style={[styles.childRow, styles.button, item.checked ? styles.btnActive : styles.btnInActive]}
onPress={() => onClick(index)}
>
<Text style={[styles.itemInActive]}>{item.key}</Text>
<Icon name={'check-circle'} size={24} color={item.checked ? 'green' : '#d3d7de'} />
</TouchableOpacity>
<View style={styles.childHr} />
</View>
)}
/>
</View>
)}
</View>
);
};
export default Accordian;
Modify your onClick function so that it loops through each entry in the data array with the some() method and check if any of the children (sons) are clicked.
If one of them is, then update set the checked property accordingly.
const onClick = (index: number) => {
setData(prevState => {
const newData = prevState.data.map((entry, entryIndex) =>
index === entryIndex ?
({ ...entry, checked: !entry.checked }) :
entry
);
const isAnyChildChecked = newData.some(({ checked }) =>
checked === true
);
return ({
...prevState,
checked: isAnyChildChecked,
data: newData
})
});
};
If the parent is clicked, then check or uncheck all the children as well.
const onClickFather = () => {
setData(prevState => {
const isParentChecked = !prevState.checked;
return ({
...prevState,
checked: isParentChecked,
data: prevState.data.map(item => ({ ...item, checked: isParentChecked }))
});
});
};
When I updated the cell in the data grid, I was only able to retrieve the ID and field through the prop selectedCellParams here but I could not get its modified value.
I want to get the selected value inside the handleSaveOrEdit() function in order to accomplish the PUT request to update the API. How to use the getValue as given in the MUI Docs.
The entire code is below;
import * as React from 'react';
import PropTypes from 'prop-types';
import { Typography, Grid } from "#mui/material";
import Box from '#mui/material/Box';
import Button from '#mui/material/Button';
import { DataGrid, GridCellModes } from '#mui/x-data-grid';
import { styled } from '#mui/material/styles';
import { useState, useEffect } from "react";
import Avatar from "#mui/material/Avatar";
import axios from 'axios';
const DrawerHeader = styled('div')(({ theme }) => ({
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-end',
padding: theme.spacing(0, 1),
...theme.mixins.toolbar,
}));
function EditToolbar(props) {
const { selectedCellParams, cellMode, cellModesModel, setCellModesModel } = props;
const handleSaveOrEdit = () => {
if (!selectedCellParams) {
return;
}
const { id, field } = selectedCellParams;
if (cellMode === 'edit') {
setCellModesModel({
...cellModesModel,
[id]: { ...cellModesModel[id], [field]: { mode: GridCellModes.View } },
});
const getValue = (params) => console.log(params.value);
console.log('value:::', getValue);
} else {
setCellModesModel({
...cellModesModel,
[id]: { ...cellModesModel[id], [field]: { mode: GridCellModes.Edit } },
});
}
};
const handleCancel = () => {
if (!selectedCellParams) {
return;
}
const { id, field } = selectedCellParams;
setCellModesModel({
...cellModesModel,
[id]: {
...cellModesModel[id],
[field]: { mode: GridCellModes.View, ignoreModifications: true },
},
});
};
const handleMouseDown = (event) => {
// Keep the focus in the cell
event.preventDefault();
};
return (
<Box
sx={{
borderBottom: 1,
borderColor: 'divider',
p: 1,
}}
>
<Button
onClick={handleSaveOrEdit}
onMouseDown={handleMouseDown}
disabled={!selectedCellParams}
color="primary"
variant="outlined"
>
{cellMode === 'edit' ? 'Save' : 'Edit'}
</Button>
<Button
onClick={handleCancel}
onMouseDown={handleMouseDown}
disabled={cellMode === 'view'}
color="primary"
variant="outlined"
sx={{ ml: 1 }}
>
Cancel
</Button>
</Box>
);
}
EditToolbar.propTypes = {
cellMode: PropTypes.oneOf(['edit', 'view']).isRequired,
cellModesModel: PropTypes.object.isRequired,
selectedCellParams: PropTypes.shape({
field: PropTypes.string.isRequired,
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
}),
setCellModesModel: PropTypes.func.isRequired,
};
export default function Donees() {
const [selectedCellParams, setSelectedCellParams] = React.useState(null);
const [cellModesModel, setCellModesModel] = React.useState({});
const [tableData, setTableData] = useState([])
const [fname, setFname] = useState("");
const [lname, setLname] = useState("");
const [address, setAddress] = useState("");
const [dob, setDob] = useState("");
const [gender, setGender] = useState("");
const [email, setEmail] = useState("");
const [phone, setPhone] = useState("");
const [grade, setGrade] = useState("");
const [photo, setPhoto] = useState("");
useEffect(() => {
fetch("http://localhost:4000/donees")
.then((data) => data.json())
.then((data) => setTableData(data))
}, [])
useEffect(() => {
axios.get("http://localhost:4000/donees")
.then((response) => {
setFname(response.data.fname);
setLname(response.data.lname);
setAddress(response.data.address);
setDob(response.data.dob);
setGender(response.data.gender);
setEmail(response.data.email);
setPhone(response.data.phone);
setGrade(response.data.grade);
setPhoto(response.data.photo);
})
}, [])
// console.log(tableData);
const handleCellFocus = React.useCallback((event) => {
const row = event.currentTarget.parentElement;
const id = row.dataset.id;
const field = event.currentTarget.dataset.field;
setSelectedCellParams({ id, field });
}, []);
const cellMode = React.useMemo(() => {
if (!selectedCellParams) {
return 'view';
}
const { id, field } = selectedCellParams;
return cellModesModel[id]?.[field]?.mode || 'view';
}, [cellModesModel, selectedCellParams]);
const handleCellKeyDown = React.useCallback(
(params, event) => {
if (cellMode === 'edit') {
// Prevents calling event.preventDefault() if Tab is pressed on a cell in edit mode
event.defaultMuiPrevented = true;
}
},
[cellMode],
);
return (
<Box component="main">
<DrawerHeader />
<Typography sx={{ textAlign: "center", pt: 5 }} variant="h5">Donees Table</Typography>
<Grid container spacing={3} sx={{ pl: 15, pr: 15, pt: 5 }}>
<div style={{ height: 400, width: '100%' }}>
<DataGrid
rows={tableData}
columns={columns}
getRowId={(row) => row._id}
onCellKeyDown={handleCellKeyDown}
cellModesModel={cellModesModel}
components={{
Toolbar: EditToolbar,
}}
componentsProps={{
toolbar: {
cellMode,
selectedCellParams,
setSelectedCellParams,
cellModesModel,
setCellModesModel,
},
cell: {
onFocus: handleCellFocus,
},
}}
experimentalFeatures={{ newEditingApi: true }}
/>
</div>
</Grid>
</Box>
);
}
const columns = [
{ field: 'fname', headerName: 'First Name', width: 140, editable: true },
{ field: 'lname', headerName: 'Last Name', width: 140, editable: true },
{ field: 'address', headerName: 'Address', width: 200, editable: true },
{ field: 'dob', headerName: 'Date of Birth', width: 140, editable: true },
{ field: 'gender', headerName: 'Gender', width: 100, editable: true },
{ field: 'email', headerName: 'Email ID', width: 140, editable: true },
{ field: 'phone', headerName: 'Mobile Number', type: 'number', width: 140, editable: true },
{ field: 'grade', headerName: 'Grade', width: 180, editable: true },
{
field: 'photo', headerName: 'Photo', width: 180, editable: true, renderCell: (params) => {
// console.log(params);
return (
<>
<Avatar src={params.value} />
</>
);
}
},
];
add following to dataGrid
<DataGrid
processRowUpdate={processRowUpdate}
/>
add
const processRowUpdate = (newRow: any) => {
const updatedRow = { ...newRow, isNew: false };
console.log(updatedRow);
//handle send data to api
return updatedRow;
};
I have a working prototype where I cant seem to figure out when I click on a particular button in my nav, then pass that index to another component. It doesn't update the index when I query using "document.querySelector". My goal is to just move the content to the front child position/firstChild depending on what button you clicked. So if you clicked the first button then the last, my last content would be first and so and so on...I've tried a timeout and still no luck.
JS:
.....
const Context = createContext(false);
const dataArr = [
{
id: "113062",
name: "Blue",
region: "US",
sort: "1"
},
{
id: "115102",
name: "Red",
region: "DE",
sort: "2"
},
{
id: "70884",
name: "Green",
region: "US",
sort: "3"
},
{
id: "114683",
name: "Yellow",
region: "US",
sort: "4"
},
{
id: "112878",
name: "Pale",
region: "US",
sort: "5"
},
{
id: "114682",
name: "Orange",
region: "US",
sort: "6"
},
{
id: "120093",
name: "Black",
region: "CH",
sort: "8"
},
{
id: "120594",
name: "White",
region: "CH",
sort: "9"
}
];
const useStyles = makeStyles((theme) => ({
root: {
display: "flex",
"& > *": {
margin: theme.spacing(1)
}
},
grey: {
border: "4px solid white"
},
orange: {
color: theme.palette.getContrastText(deepOrange[500]),
backgroundColor: deepOrange[500],
border: "4px solid black"
},
info: {
margin: "10px"
},
wrapper: {
display: "flex"
},
contentWrapper: {
display: "flex",
flexDirection: "column"
},
elWrapper: {
opacity: 0,
"&.active": {
opacity: 1
}
}
}));
const ToggleItem = ({ id, description }) => {
const { handleChange, selected, classes } = useContext(Context);
const isSelected = selected.includes(description);
const handleClick = (idx) => {
console.log("idx====", idx);
handleChange(description, idx);
};
return (
<>
<Avatar
className={isSelected ? classes.orange : classes.grey}
onClick={() => handleClick(id)}
>
<span style={{ fontSize: ".75rem" }}>{description}</span>
</Avatar>
</>
);
};
const ToggleContainer = ({ selected, list }) => {
const isSelected = list.filter((element) => selected.includes(element));
return (
<>
{dataArr.map((item, idx) => (
<div
key={idx}
className="carouselWrapper"
style={{ display: isSelected.includes(item.name) ? "block" : "none" }}
>
{item.name}
</div>
))}
</>
);
};
const ToggleWrapper = () => {
const data = [];
dataArr.map((el) => data.push(el.name));
const classes = useStyles();
const [selected, setSelected] = useState([]);
const [viewAll, setViewAll] = useState(true);
const handleChange = (val, idx) => {
setViewAll(false);
setSelected((selected) => {
if (selected.length === 1 && selected.includes(val)) {
return handleViewAll();
}
if (selected.includes(val)) {
return selected.filter((v) => v !== val);
} else {
return [val, ...selected];
}
});
setTimeout(() => {
const someParentObject = document.getElementById("contentWrapper");
const someChildObject = document.querySelectorAll(".carouselWrapper")[
idx
];
// eslint-disable-next-line no-unused-expressions
selected.length > 0 &&
someParentObject.insertBefore(
someChildObject,
someParentObject.firstChild
);
console.log(
"someParentObject.children[0]==",
someParentObject.firstChild
);
console.log("someChildObject", someChildObject);
}, 2000);
};
const handleViewAll = () => {
setViewAll(true);
setSelected([]);
};
return (
<Context.Provider
value={{
viewAll,
handleChange,
handleViewAll,
selected,
classes
}}
>
<div className={classes.wrapper}>
<Avatar
className={viewAll ? classes.orange : null}
onClick={handleViewAll}
>
<span style={{ fontSize: "0.75rem", textAlign: "center" }}>
View All
</span>
</Avatar>
{dataArr.map((d, id) => {
return (
<div key={id}>
<ToggleItem id={id} description={d.name} />
</div>
);
})}
</div>
<div id="contentWrapper" className={classes.contentWrapper}>
<ToggleContainer selected={viewAll ? data : selected} list={data} />
</div>
</Context.Provider>
);
};
export default function App() {
return <ToggleWrapper />;
}
Here is a very quick example of one option. It stores the data in a Map which allows for efficient retrieval (this could be moved to context to avoid passing it to multiple child components) and tracks selected by id in a separate state array. It's then just a matter of mapping the selected array to get your ordered list. If selected is empty render the full values() of the Map.
const { useState, useEffect } = React;
function App({ data }) {
const [selected, setSelected] = useState([]);
const [itemMap, setItemMap] = useState(new Map());
useEffect(() => {
setItemMap(new Map(data.map(({ id, ...rest }) => [id, { id, ...rest }])));
}, [data]);
const selectHandler = (id) => {
setSelected(selected => {
if (id === undefined) return [];
return selected.includes(id)
? selected.filter(_id => _id !== id)
: [id, ...selected];
});
}
return (
<div>
<Header itemMap={itemMap} selected={selected} selectHandler={selectHandler} />
<Selected itemMap={itemMap} selected={selected} />
</div>
);
}
function Header({ itemMap, selected, selectHandler }) {
return (
<div className={"header-container"}>
<div className={!selected.length && 'selected'} onClick={() => selectHandler()}>All</div>
{[...itemMap.values()].map(({ id, name }) => (
<div key={id} className={selected.includes(id) && 'selected'} onClick={() => selectHandler(id)}>
{name}
</div>
))}
</div>
);
}
function Selected({ itemMap, selected }) {
return (
<div className={"selected-container"}>
{selected.length
? selected.map((id) => (
<div key={id} >
{itemMap.get(id).name}
</div>
))
: [...itemMap.values()].map(({ id, name }) => (
<div key={id} >
{name}
</div>
))
}
</div>
);
}
const dataArr = [{ id: "113062", name: "Blue", region: "US", sort: "1" }, { id: "115102", name: "Red", region: "DE", sort: "2" }, { id: "70884", name: "Green", region: "US", sort: "3" }, { id: "114683", name: "Yellow", region: "US", sort: "4" }, { id: "112878", name: "Pale", region: "US", sort: "5" }, { id: "114682", name: "Orange", region: "US", sort: "6" }, { id: "120093", name: "Black", region: "CH", sort: "8" }, { id: "120594", name: "White", region: "CH", sort: "9" }];
const container = document.getElementById('root');
const root = ReactDOM.createRoot(container);
root.render(<App data={dataArr} />);
.header-container { width: 100vw; display: flex; justify-content: flex-start;}
.header-container div { width: 40px; height: 40px; display: flex; overflow: hidden; position: relative; margin: 4px; font-size:.75rem; align-items: center; user-select: none; border-radius: 50%; justify-content: center; color: #fafafa; background-color: #bdbdbd;}
.header-container div.selected { background-color: tomato;}
<script crossorigin src="https://unpkg.com/react#18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#18/umd/react-dom.production.min.js"></script>
<div id='root'></div>
I have one Lock-Unlock button and a delete button, So the problem is when I render data from axios using useEffect hook its working, but if I lock or unlock a user the table is not changing automatically. That means axios is not getting called.
In that case if I put the useState hook in the useEffect, API is getting called multiple times, that is not as expected. In that case can anyone suggest me how can I re render data table as soon as user clicks on lock-unlock button.
FYI, lock unlock functionality is working 100% correctly. What is needed I have to go to other page and again come back to my datatable page in order to see the change.
code snippet:
const useStyles = makeStyles(theme => ({
button: {
margin: theme.spacing(1)
},
input: {
display: "none"
}
}));
/*
Customization of mui
*/
const getMuiTheme = () => createMuiTheme({
overrides: {
MUIDataTableBodyCell: {
root: {
backgroundColor: "#FFFFFE"
}
}
}
});
/* eslint-disable */
const UserDetailsDatatable = () => {
// console.log('POS: ' + localStorageService.getItem("auth_user"));
if(localStorageService.getItem("auth_user") == null){
history.push({
pathname: "/session/signin"
});
}
const [responsive, setResponsive] = useState("vertical");
const [dataRenderHook, setDataRenderHook] = useState([]);
const [tableBodyHeight, setTableBodyHeight] = useState("650px");
const [tableBodyMaxHeight, setTableBodyMaxHeight] = useState("");
const classes = useStyles();
// Redirect to edit
const newMountpage = (rowData) => {
var pickedUpRowData = rowData.rowData;
let path = `/Admin/users/editUser`;
history.push({
pathname: path,
state: {detail: pickedUpRowData}
});
};
/* Deletion */
const deleteRow = (rowDatam) => {
deleteUser(rowDatam);
};
/* User Locker/Unlocker */
const LockerUnlocker = (Iopticore_ID, state) => {
console.log('State: '+ state);
lockerUnlocker(Iopticore_ID, Boolean(state));
}
const ChangeHandler = (event) => {
console.log(event);
};
const columns = [
{
name: "userID",
label: "Iopticore_ID",
options: {
filter: true,
sort: true,
}
},
{
name: "userName",
label: "Corporate ID",
options: {
filter: true,
sort: true,
}
},
{
name: "name",
label: "User Name",
options: {
filter: true,
sort: true,
}
},
{
name: "email",
label: "Email",
options: {
filter: true,
sort: true,
}
},
{
name: "role",
label: "Role",
options: {
filter: true,
sort: true,
}
},
{
name: "external",
label: "IsExternal",
options: {
filter: true,
sort: true,
filterOptions: {
names: ["Yes", "No"],
logic(v, filterVal) {
const show =
(filterVal.indexOf("Yes") >= 0 && ( v === true || v === 'true') ) ||
(filterVal.indexOf("No") >= 0 && ( v === false || v === 'false') );
return !show;
}
},
customBodyRender: (val) => {
return val === true ? "Yes" : "No";
}
}
},
{
name: "locked",
label: "Access",
options: {
filter: true,
sort: true,
empty: true,
filter: true,
sort: true,
filterOptions: {
names: ["Yes", "No"],
logic(v, filterVal) {
const show =
(filterVal.indexOf("Yes") >= 0 && ( v === true || v === 'true') ) ||
(filterVal.indexOf("No") >= 0 && ( v === false || v === 'false') );
return !show;
}
},
customBodyRender: (val, tableMeta) => {
//console.log('v: ' + val + ' ' + JSON.stringify(tableMeta)) ;
return val === true ? (
<Fab
size="small"
variant="extended"
aria-label="Delete"
className={classes.button}
color="default"
onClick={() => LockerUnlocker(tableMeta.rowData[0], tableMeta.rowData[6])}
>
<img src="https://img.icons8.com/plasticine/25/000000/unlock.png"/>
<b>UnLock </b>
</Fab>
) : (
<Fab
size="small"
variant="extended"
aria-label="Delete"
className={classes.button}
color="default"
onClick={() => LockerUnlocker(tableMeta.rowData[0])}
>
<img src="https://img.icons8.com/dusk/25/000000/unlock.png"/>
<b> Lock </b>
</Fab>
);
}
}
},
{
name: "Edit",
options: {
filter: true,
sort: false,
empty: true,
customBodyRender: (value, tableMeta, updateValue) => {
return (
<Fab
size="small"
color="primary"
aria-label="Edit"
className={classes.button}
onClick={() => newMountpage(tableMeta)}
>
<Icon>edit_icon</Icon>
</Fab>
);
}
}
},
{
name: "Delete",
options: {
filter: true,
textAlign: 'center',
sort: false,
empty: true,
customBodyRender: (value, tableMeta, updateValue) => {
return (
<Fab size="small"
color="secondary"
aria-label="Edit"
className={classes.button}
onClick={() => deleteRow(tableMeta.rowData[0])}
>
<Icon>delete_icon</Icon>
</Fab>
);
}
}
}];
const options = {
selectableRows: 'none',
filter: true,
textAlign: 'center',
filterType: "dropdown",
rowsPerPage: 5,
pagination: true,
responsive,
enableNestedDataAccess: '.',
tableBodyHeight,
tableBodyMaxHeight
};
var recentReceivedToken = localStorage.getItem('jwtAuthtokenManager');
var res= [];
useEffect(() => {
(async () => {
res = await axios.get('<URL>', {
headers: {"Authorization" : `Bearer ${recentReceivedToken}`}
},
// console.log('Hola : ' + JSON.stringify(res))
)
.catch((error)=> {
if(error.response.status != 200){
swal({
title: "Opps! Access Denied",
imageUrl: 'https://notionpress.com/new-rewamp/images/404-error.gif',
text: "You Might Not Have Access To This Page.",
icon: "error",
});
}
})
//console.log('Res : ' + JSON.stringify(res));
setDataRenderHook(res.data);
})();
}, []);
//console.log('Data Promise : ' + renderDatatable());
if(dataRenderHook.length === 0){
//console.log('Length: 0');
return(
<React.Fragment>
<div style={{padding:40}}>
<MuiThemeProvider theme={getMuiTheme()}>
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center"
}}
>
<LinearBuffer />
</div>
</MuiThemeProvider>
</div>
</React.Fragment>
)
}else{
//console.log('Length: 1');
return (
<React.Fragment>
<div style={{padding:40}}>
<MuiThemeProvider theme={getMuiTheme()}>
<MUIDataTable
title={"IoptiCore User List"}
data={dataRenderHook}
columns={columns}
options={options}
/>
</MuiThemeProvider>
</div>
</React.Fragment>
);
}
}
export default UserDetailsDatatable;
import React, { useState, useEffect } from "react";
import MUIDataTable from "mui-datatables";
import { makeStyles,createMuiTheme, MuiThemeProvider } from "#material-ui/core/styles";
import { Icon, Fab } from "#material-ui/core";
import history from "history.js";
import axios from "axios";
import swal from 'sweetalert';
import LinearBuffer from './EditUserHelper/progresscircle';
import lockerUnlocker from './Lock_Unlock/lockerUnlocker';
import deleteUser from './DeleteUser/DeleteUser'
import localStorageService from "../../../services/localStorageService";
import apiDataReturner from "./userAxios";
const useStyles = makeStyles(theme => ({
button: {
margin: theme.spacing(1)
},
input: {
display: "none"
}
}));
/*
Customization of mui
*/
const getMuiTheme = () => createMuiTheme({
overrides: {
MUIDataTableBodyCell: {
root: {
backgroundColor: "#FFFFFE"
}
}
}
});
/* eslint-disable */
const UserDetailsDatatable = () => {
// console.log('POS: ' + localStorageService.getItem("auth_user"));
if(localStorageService.getItem("auth_user") == null){
history.push({
pathname: "/session/signin"
});
}
const [responsive, setResponsive] = useState("vertical");
const [dataRenderHook, setDataRenderHook] = useState([]);
const [tableBodyHeight, setTableBodyHeight] = useState("650px");
const [tableBodyMaxHeight, setTableBodyMaxHeight] = useState("");
const [tracker, setTracker] = useState();
const classes = useStyles();
// Redirect to edit
const newMountpage = (rowData) => {
var pickedUpRowData = rowData.rowData;
let path = `/Admin/users/editUser`;
history.push({
pathname: path,
state: {detail: pickedUpRowData}
});
};
/* Deletion */
const deleteRow = (rowDatam) => {
deleteUser(rowDatam);
var x = apiDataReturner();
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
setTracker(x);
}, 3000);
});
promise.then(values => {
setDataRenderHook(values);
});
};
/* User Locker/Unlocker */
const LockerUnlocker = (Iopticore_ID, state) => {
lockerUnlocker(Iopticore_ID, Boolean(state));
var x = apiDataReturner();
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
setTracker(x);
}, 3000);
});
promise.then(values => {
setDataRenderHook(values);
});
}
const ChangeHandler = (event) => {
console.log(event);
};
const columns = [
{
name: "userID",
label: "Iopticore_ID",
options: {
filter: true,
sort: true,
responsive: 'scrollFullHeightFullWidth',
display: false
}
},
{
name: "userName",
label: "Corporate ID",
options: {
filter: true,
responsive: 'scrollFullHeightFullWidth',
sort: true,
}
},
{
name: "name",
label: "User Name",
options: {
filter: true,
responsive: 'scrollFullHeightFullWidth',
sort: true,
}
},
{
name: "email",
label: "Email",
options: {
filter: true,
responsive: 'scrollFullHeightFullWidth',
sort: true,
}
},
{
name: "role",
label: "Role",
options: {
filter: true,
responsive: 'scrollFullHeightFullWidth',
sort: true,
}
},
{
name: "external",
label: "IsExternal",
options: {
filter: true,
sort: true,
responsive: 'scrollFullHeightFullWidth',
filterOptions: {
names: ["Yes", "No"],
logic(v, filterVal) {
const show =
(filterVal.indexOf("Yes") >= 0 && ( v === true || v === 'true') ) ||
(filterVal.indexOf("No") >= 0 && ( v === false || v === 'false') );
return !show;
}
},
customBodyRender: (val) => {
return val === true ? "Yes" : "No";
}
}
},
{
name: "locked",
label: "Access",
options: {
filter: true,
sort: true,
empty: true,
filter: true,
sort: true,
responsive: 'scrollFullHeightFullWidth',
filterOptions: {
names: ["Yes", "No"],
logic(v, filterVal) {
const show =
(filterVal.indexOf("Yes") >= 0 && ( v === true || v === 'true') ) ||
(filterVal.indexOf("No") >= 0 && ( v === false || v === 'false') );
return !show;
}
},
customBodyRender: (val, tableMeta) => {
//console.log('v: ' + val + ' ' + JSON.stringify(tableMeta)) ;
return val === true ? (
<Fab
size="small"
variant="extended"
aria-label="Delete"
className={classes.button}
color="default"
onClick={() => LockerUnlocker(tableMeta.rowData[0], tableMeta.rowData[6])}
>
<img src="https://img.icons8.com/plasticine/25/000000/unlock.png"/>
<b>UnLock </b>
</Fab>
) : (
<Fab
size="small"
variant="extended"
aria-label="Delete"
className={classes.button}
color="default"
onClick={() => LockerUnlocker(tableMeta.rowData[0])}
>
<img src="https://img.icons8.com/dusk/25/000000/unlock.png"/>
<b> Lock </b>
</Fab>
);
}
}
},
{
name: "Edit",
options: {
filter: true,
sort: false,
empty: true,
responsive: 'scrollFullHeightFullWidth',
customBodyRender: (value, tableMeta, updateValue) => {
return (
<Fab
size="small"
color="primary"
aria-label="Edit"
className={classes.button}
onClick={() => newMountpage(tableMeta)}
>
<Icon>edit_icon</Icon>
</Fab>
);
}
}
},
{
name: "Delete",
options: {
filter: true,
textAlign: 'center',
sort: false,
empty: true,
responsive: 'scrollMaxWidth',
customBodyRender: (value, tableMeta, updateValue) => {
return (
<Fab size="small"
color="secondary"
aria-label="Edit"
className={classes.button}
onClick={() => deleteRow(tableMeta.rowData[0])}
>
<Icon>delete_icon</Icon>
</Fab>
);
}
}
}];
const options = {
selectableRows: 'none',
filter: true,
textAlign: 'center',
filterType: "dropdown",
fixedHeaderOptions:true,
rowsPerPage: 5,
pagination: true,
responsive: 'stacked',
enableNestedDataAccess: '.',
tableBodyHeight,
tableBodyMaxHeight
};
//var recentReceivedToken = localStorage.getItem('jwtAuthtokenManager');
var res= [];
useEffect(() => {
var x = apiDataReturner();
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(x);
}, 2000);
});
promise.then(values => {
setDataRenderHook(values);
});
}, [tracker]);
if(dataRenderHook.length === 0){
return(
<React.Fragment>
<div style={{padding:0}}>
<MuiThemeProvider theme={getMuiTheme()}>
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center"
}}
>
<LinearBuffer />
</div>
</MuiThemeProvider>
</div>
</React.Fragment>
)
}else{
return (
<div>
<React.Fragment>
<div style={{padding:0}}>
<MuiThemeProvider theme={getMuiTheme()}>
<MUIDataTable
title={"IoptiCore User List"}
data={dataRenderHook}
columns={columns}
options={options}
/>
</MuiThemeProvider>
</div>
</React.Fragment>
</div>
);
}
}
export default UserDetailsDatatable;
Sharing the code, it might help someone.
I have this component which is a filter for a table..
handleSearch function is responsible to update const filters... its work perfectly when dataIndex props is the same, but when it changes, filters value is backing to it's initial value, an empty array.
I can't manage to resolve it, I've already console log everything.
import React, { useState, } from "react";
import { SearchOutlined } from "#ant-design/icons";
import { Select, Button, Space } from "antd";
const TableFilter = (props) => {
const {
filterType,
filterMode,
filterOptions,
FilterSelectOnFocus,
dataIndex,
setSelectedKeys,
selectedKeys,
confirm,
clearFilters,
} = props;
const [filters, setFilters] = useState([]);
const SelectFilter = (
<Select
style={{ width: 188, marginBottom: 8, display: "block" }}
type={filterType}
mode={filterMode}
name={dataIndex}
value={selectedKeys}
optionFilterProp="children"
placeholder={`Search ${dataIndex}`}
onFocus={FilterSelectOnFocus}
showSearch
onChange={(value) => setSelectedKeys(value ? value : [])}
getPopupContainer={(trigger) => trigger}
notFoundContent
>
{filterOptions?.map((type, key) => (
<Select.Option value={type.value} key={key}>
{type.label}
</Select.Option>
))}
</Select>
);
const defaultFilterTypes = [
{
type: "select",
element: SelectFilter,
},
];
const handleFilterType = () => {
const type = defaultFilterTypes.find((types) => types.type === filterType);
return type.element;
};
const handleSearch = () => {
console.log(filters) //is empty when dataIndex value change, when it's is the same it get the update value of the 75 line
confirm();
const newFilterValues = [...filters]
const index = newFilterValues.findIndex(newValue => newValue.searchedColumn === dataIndex)
if(index === -1){
newFilterValues.push({ searchText: selectedKeys, searchedColumn: dataIndex})
}
else{
newFilterValues[index] = {searchText: selectedKeys, searchedColumn: dataIndex}
}
setFilters(newFilterValues)
}
const handleReset = () => {
console.log('reset');
clearFilters();
setFilters({ searchText: "" });
setSelectedKeys([]);
};
return (
<div style={{ padding: 8 }}>
{handleFilterType()}
<Space>
<Button
type="primary"
onClick={() => handleSearch()}
icon={<SearchOutlined />}
size="small"
style={{ width: 90 }}
>
Search
</Button>
<Button
onClick={() => handleReset()}
size="small"
style={{ width: 90 }}
>
Reset
</Button>
</Space>
</div>
);
};
export default TableFilter;
Table Component
import React, { useEffect, useState } from "react";
import { Table } from "antd";
import { getTransactions } from "../../../../api/Transactions";
import { formatCnpjCpf, formatCurrency } from "../../../../utils/masks";
import TableFilter from "../../../../shared-components/ant-design/containers/TableFilters";
import { getPartnersAsOptions } from "../../../../api/Partners";
const Insider = (props) => {
const [data, setData] = useState([]);
const [paginationValues, setPaginationValues] = useState({
current: 1,
pageSize: 50,
total: 0,
position: ["topRight"],
});
const [partners, setPartners] = useState([{value: null, label: 'carregando...'}])
const context = "insider";
function getColumnSearchProps(
dataIndex,
filterType,
filterMode,
filterOptions,
FilterSelectOnFocus
) {
return {
filterDropdown: ({
setSelectedKeys,
selectedKeys,
confirm,
clearFilters,
}) => {
return (
<TableFilter
dataIndex={dataIndex}
filterType={filterType}
filterMode={filterMode}
filterOptions={filterOptions}
FilterSelectOnFocus={FilterSelectOnFocus}
setSelectedKeys={setSelectedKeys}
selectedKeys={selectedKeys}
confirm={confirm}
clearFilters={clearFilters}
/>
);
},
};
}
async function getPartners(){
if(partners.length > 2){
return
}
const response = await getPartnersAsOptions(paginationValues)
setPartners(response.data)
}
const columns = [
{
dataIndex: ["transactionType", "desc"],
title: "Tipo de Transação",
sorter: true,
key: "orderTransactionType",
...getColumnSearchProps("orderTransactionType"),
},
{
dataIndex: "transactionDate",
title: "Data Transação",
key: "orderTransactionDate",
sorter: true,
...getColumnSearchProps("orderTransactionDate"),
},
{
title: "Nome origem",
dataIndex: ["source", "name"],
sorter: true,
key: "orderSourceCustomerName",
},
{
render: (render) => formatCnpjCpf(render.source.document.value),
title: "Documento origem",
key: "sourceCustomer",
...getColumnSearchProps("sourceCustomer", "select", "tags")
},
{
title: "Nome destino",
dataIndex: ["target", "name"],
sorter: true,
key: "orderTargetCustomerName",
},
{
render: (render) => formatCnpjCpf(render.target.document.value),
title: "Documento destino",
},
{
render: (render) => formatCurrency(render.value),
title: "Valor da transação",
key: "orderValue",
sorter: true,
align: "right",
},
{
render: (render) => formatCurrency(render.chargedTariff),
title: "Tarifa",
key: "orderChargedTariff",
sorter: true,
align: "right",
},
{
render: (render) => formatCurrency(render.cost),
title: "Custo",
key: "orderCost",
sorter: true,
align: "right",
},
{
render: (render) => formatCurrency(render.revenue),
title: "Receita",
key: "orderRevenue",
sorter: true,
align: "right",
},
{
title: "Parceiro",
name: "Parceiro",
dataIndex: ["partner", "name"],
key: "orderPartnerName",
sorter: true,
align: "center",
...getColumnSearchProps(
"orderPartnerName",
"select",
"multiple",
partners,
getPartners)
},
{
title: "id da transação",
name: "id da transação",
dataIndex: "id",
},
];
useEffect(function transactions() {
async function fetchTransactions() {
const response = await getTransactions(context, paginationValues);
if (response) {
const { data, pagination } = response;
setData(data);
setPaginationValues(pagination);
}
}
fetchTransactions();
// eslint-disable-next-line
}, []);
return <Table dataSource={data} columns={columns} />;
};
export default Insider;
You could move this piece of code
const [filters, setFilters] = useState([]);
In a higher level