Column of table from different API (React) - javascript

I have to fill the table with data which I have returned from different API : the first from smart contract and the second one from a MySQL table using axios.
Both of the sets of data returned are arrays and each elements with the same id I want to put it into a row.
I succeeded to put the data only from the smart contract.
Here's the code of my component :
function CandidaturesList() {
const [account, setAccounts] = useState(null);
const [contract, setContract] = useState(null);
const [candidatures, setCandidatures] = useState(null);
const [stateCandidatures, setStateCandidatures] = useState(null);
useEffect(() => {
async function fetchData() {
const web3 = await getWeb3();
const accounts = await web3.eth.getAccounts();
const networkId = await web3.eth.net.getId();
const deployedNetwork = OffreEmploiContract.networks[networkId];
const instance = new web3.eth.Contract(
OffreEmploiContract.abi,
deployedNetwork && deployedNetwork.address,
);
setAccounts(accounts);
setContract(instance);
const response = await instance.methods.getApply().call({ from: accounts[0] });
console.log(response);
setCandidatures(response);
axios.get('http://localhost:4000/api/getAll').then((res) => {
setStateCandidatures(res.data);
})
}
fetchData();
});
const project = [
{
title: "COMPANIES",
dataIndex: "nomCompagnie",
align: 'center',
render: text => (
<div className="avatar-info">
<Title level={5}>{text}</Title>
</div>
)
},
{
title: "JOB TITLE",
dataIndex: "titre_poste",
align: 'center',
render: text => (
<>
<div className="semibold">{text}</div>
</>)
},
{
title: "STATUS",
width: "15%",
dataIndex: "status",
align: 'center',
render: text => (
<>
<br>{text}</br>
<br></br>
<Steps current={1} progressDot={(dot, { status, index }) => (
<Popover
content={
<span>
step {index} status: {status}
</span>
}
>
{dot}
</Popover>
)} >
<Step title="Published" />
<Step title="Job interview" description="Mon, 18 Apr 2022" />
<Step title="Waiting for decision" />
<Step title="Completed" />
</Steps>,
</>)
},
{
title: "FINAL DECISION",
dataIndex: "decision",
align: 'center',
render: text => (
<>
{
text === "Valide" || text === "Refused" ?
<Tag color="cyan">{text}</Tag>
:
<Tag icon={<SyncOutlined spin />} color="processing">{text}</Tag>
}
</>
)
},
];
return (
<>
<Card
bordered={false}
className="criclebox tablespace mb-24"
title="Your Candidature"
extra={
<>
</>
}
>
<div className="table-responsive">
<Table
columns={project}
dataSource={candidatures }
pagination={false}
className="ant-border-space"
/>
</div>
</Card>
</>
);
}
export default CandidaturesList;
I must fill the Steps with the state stateCandidatures which is an array of objects , example :
{id: 1, date_entretien: 'Mon Apr 25 2022', status: 'waiting for interview'},
{id: 2, date_entretien: null, status: 'Published'}
and this is an example of the state candidatures :
[ id: '1', nomCompagnie:'Company1', titre_poste: 'manager', decision:'valide', …]
[ id: '2', nomCompagnie:'Company2', titre_poste: 'developer', decision:'processing', …]
and the second problem is i don't know how to fill the steps with those data ( the code shows a static steps)

Related

React setselectedType does not immediately update the selectedType

I am setting the selectedType variable and opening ant design Modal containing ant design Form with initialValues filled with selectedType.
But the initialValues in the form are only working for the first time I click on Edit button and if I close the Modal and click on Edit button for a different selectedType the Modal shows the values of first time selected selectedType.
I have used destroyOnClose={true} for Modal to fetch the new value of selectedType but it doesn't solve the issue.
Here's my code:
import {
Button, Form,
Input,Table,
Modal
} from "antd";
import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
const ManageTypeScreen = () => {
const dispatch = useDispatch();
const productTypeList = useSelector(state => state.productTypeList);
const [editForm] = Form.useForm();
const [selectedType, setselectedType] = useState({});
const [showEditModal, setshowEditModal] = useState(false);
useEffect(() => {
getProductTypeList(dispatch);
}, [])
const handleEditClose = () => {
setshowEditModal(false);
};
const handleEditShow = (val) => {
console.log(val);
setselectedType(val);
setshowEditModal(true);
};
const columns = [
{
title: 'Type Name',
dataIndex: 'name',
key: 'name'
},
{
title: 'Short Cut',
dataIndex: 'shortCut',
key: 'shortCut'
},
{
title: 'Edit',
sortable: false,
filterable: false,
render: (text, pro) => (
<div>
<Button type="primary" size="sm block" onClick={() => handleEditShow(pro)}>
Edit
</Button>
</div>)
},
];
return (
{selectedType !== undefined &&
<Modal
title="Edit Type"
visible={showEditModal}
onCancel={handleEditClose}
destroyOnClose={true}
footer={null}
centered={true}
>
<Form
labelCol={{ span: 9 }}
wrapperCol={{ span: 12 }}
layout="horizontal"
form={editForm}
requiredMark={true}
initialValues={selectedType}
size="medium"
>
<Form.Item
label="Type Name:"
name="name"
rules={[
{ required: true, message: "Please input Name!" }
]}>
<Input maxLength={32} />
</Form.Item>
<Form.Item
label="ShortCut"
name="shortCut"
rules={[
{
required: true,
message: "Please input ShortCut!"
}
]}>
<Input maxLength={3} />
</Form.Item>
< Form.Item
wrapperCol={{
span: 5,
offset: 7
}}
style={{ marginTop: "35px" }}
>
<Button
type="primary"
htmlType="submit"
size="large"
loading={editLoading}
>
Update Type
</Button>
</Form.Item>
</Form>
</Modal>
}
{
productTypeList !== undefined &&
<div style={{ marginLeft: "30px", marginRight: "30px" }}>
<Table
className="product-type-list-table"
columns={columns}
pagination={false}
dataSource={productTypeList}
rowKey={record => record.id}
/>
</div>
}
</div >
)
}
I don't know if it's the solution, but I'd suggest not messing up the rendering of the modal with both conditional rendering and a visible prop, it makes it hard to track.
Try something like
visible={selectedType !== undefined && showEditModal}
Or better yet, just get rid of the showEditModal variable since you're always changing it in accord with selectedType.
I think you can do it by changing you close function to
const handleEditClose = () => {
setshowEditModal(null);
};
Set the initial value of selectedType to null
and your modal's props to
<Modal
title="Edit Type"
visible={!!selectedType}
(Though it might give you an error because it might try to render the modal when selectedType is null, then just switch back to conditional rendering and set the visible prop to be always true)
import {
Button, Form,
Input,Table,
Modal
} from "antd";
import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
const ManageTypeScreen = () => {
const dispatch = useDispatch();
const productTypeList = useSelector(state => state.productTypeList);
const [editForm] = Form.useForm();
const [selectedType, setselectedType] = useState({});
const [showEditModal, setshowEditModal] = useState(false);
useEffect(() => {
getProductTypeList(dispatch);
}, [])
const handleEditClose = () => {
setshowEditModal(false);
};
const handleEditShow = (val) => {
console.log(val);
setselectedType(val);
setshowEditModal(true);
};
const columns = [
{
title: 'Type Name',
dataIndex: 'name',
key: 'name'
},
{
title: 'Short Cut',
dataIndex: 'shortCut',
key: 'shortCut'
},
{
title: 'Edit',
sortable: false,
filterable: false,
render: (text, pro) => (
<div>
<Button type="primary" size="sm block" onClick={() => handleEditShow(pro)}>
Edit
</Button>
</div>)
},
];
return (
{selectedType !== undefined &&
<Modal
title="Edit Type"
visible={showEditModal}
onCancel={handleEditClose}
destroyOnClose={true}
footer={null}
centered={true}
>
<Form
labelCol={{ span: 9 }}
wrapperCol={{ span: 12 }}
layout="horizontal"
form={editForm}
requiredMark={true}
size="medium"
>
<Form.Item
label="Type Name:"
name="name"
initialValue={selectedType.name}
preserve={false}
rules={[
{ required: true, message: "Please input Name!" }
]}>
<Input maxLength={32} />
</Form.Item>
<Form.Item
label="ShortCut"
name="shortCut"
initialValue={selectedType.shortCut}
preserve={false}
rules={[
{
required: true,
message: "Please input ShortCut!"
}
]}>
<Input maxLength={3} />
</Form.Item>
< Form.Item
wrapperCol={{
span: 5,
offset: 7
}}
style={{ marginTop: "35px" }}
>
<Button
type="primary"
htmlType="submit"
size="large"
loading={editLoading}
>
Update Type
</Button>
</Form.Item>
</Form>
</Modal>
}
{
productTypeList !== undefined &&
<div style={{ marginLeft: "30px", marginRight: "30px" }}>
<Table
className="product-type-list-table"
columns={columns}
pagination={false}
dataSource={productTypeList}
rowKey={record => record.id}
/>
</div>
}
</div >
)
}

How to add and edit list items in a dual list in reactjs?

I am pretty new to React js and trying different ways to make a to-do list to understand it further. I have a parent component that renders two child components. I figured out how to transfer the items between the two lists. How do I add items to the 2 lists separately from the UI? I am not able to figure that out. I need two input textboxes for each list and also should be able to edit the list items. Can anybody please help me?
import React,{useState,useEffect} from 'react'
import { Completed } from './Completed'
import { Pending } from './Pending'
export const Items = () => {
const [items,setItems]=useState([
{
id: 1,
title:'Workout',
status:'Pending'
},
{
id: 2,
title:'Read Books',
status:'Pending'
},
{
id: 3,
title:'Cook Pizza',
status:'Pending'
},
{
id: 4,
title:'Pay Bills',
status:'Completed'
},
{
id: 5,
title:' Watch Big Short',
status:'Completed'
},
{
id: 6,
title:' Make nutrition Plan',
status:'Pending'
}
])
const updateStatus=(id,newStatus)=>{
let allItems=items;
allItems=allItems.map(item=>{
if(item.id===id){
console.log('in here')
item.status=newStatus;
}
return item
})
setItems(allItems)
}
return (
<div class="items">
<Pending items={items} setItems={setItems} updateStatus={updateStatus}/>
<Completed items={items} setItems={setItems} updateStatus={updateStatus}/>
</div>
)
}
import React from 'react'
export const Completed = ({items,setItems,updateStatus}) => {
return (
<div className="completed">
<h1>RIGHT</h1>
{
items && items.map(item=>{
if(item && item.status==='Completed')
return <><p className="item" key={item.id}>{item.title} <button className="mark_pending" key={item.id} onClick={()=>{updateStatus(item.id,'Pending')}}> Move Left</button></p></>
})
}
</div>
)
}
import React from 'react'
export const Pending = ({items,setItems,updateStatus}) => {
return (
<div className="pending">
<h1>LEFT</h1>
{
items && items.map(item=>{
if(item && item.status==='Pending')
return <><p className="item" key={item.id}>{item.title} <button className="mark_complete" key={item.id} onClick={()=>{updateStatus(item.id,'Completed')}}>Move Right</button></p></>
})
}
</div>
)
}
What do you mean by "separately from the UI" ?
import React, { useState } from "react";
const initialStatus = "Pending";
const initialData = [
{
id: 1,
title: "Workout",
status: "Pending",
},
{
id: 2,
title: "Read Books",
status: "Pending",
},
{
id: 3,
title: "Cook Pizza",
status: "Pending",
},
{
id: 4,
title: "Pay Bills",
status: "Completed",
},
{
id: 5,
title: " Watch Big Short",
status: "Completed",
},
{
id: 6,
title: " Make nutrition Plan",
status: "Pending",
},
];
const Box = ({ id, title, status, setItems, items }) => {
return (
<button
onClick={() => {
const newItems = [...items];
const index = items.findIndex((v) => v.id == id);
newItems[index].status =
newItems[index].status == initialStatus ? "Completed" : initialStatus;
setItems(newItems);
}}
>
{title}
</button>
);
};
export const Items = () => {
const [items, setItems] = useState(initialData);
return (
<div style={{ display: "flex" }}>
<div style={{ display: "flex", flexDirection: "column" }}>
<h1>LEFT</h1>
{items
.filter((v) => v.status === initialStatus)
.map((props) => (
<Box {...props} key={props.id} setItems={setItems} items={items} />
))}
</div>
<div style={{ display: "flex", flexDirection: "column" }}>
<h1>Right</h1>
{items
.filter((v) => v.status !== initialStatus)
.map((props) => (
<Box {...props} key={props.id} setItems={setItems} items={items} />
))}
</div>
</div>
);
};
export default Items;

Add custom add-button in material-table

Currently I have a simple material-table like this:
<MaterialTable
options={myOptions}
title="MyTitle"
columns={state.columns}
data={state.data}
tableRef={tableRef} // Not working
editable={{
onRowAdd: ...,
onRowDelete: ...,
onRowUpdate: ...
}}
/>;
where I'm trying to a create new add button (not edit the current one): each Row in the Bar Column should have a custom add button. I've looked through the MaterialTable source code but I couldn't reproduce the code that is used for the default add button which is:
calculatedProps.actions.push({
icon: calculatedProps.icons.Add,
tooltip: localization.addTooltip,
position: "toolbar",
disabled: !!this.dataManager.lastEditingRow,
onClick: () => {
this.dataManager.changeRowEditing();
this.setState({
...this.dataManager.getRenderState(),
showAddRow: !this.state.showAddRow,
});
},
});
in particular I can't get to access the dataManager variable.
That is how the current table looks like, and I need to add the add button where there is the red sign.
I think this is what you are looking for:
The Actions column represents the default actions set. I added an specific button using custom column rendering (docs):
//..previous columns definition
{
title: "Custom Add",
field: "internal_action",
editable: false,
render: (rowData) =>
rowData && (
<IconButton
color="secondary"
onClick={() => addActionRef.current.click()}
>
<AddIcon />
</IconButton>
)
}
*Using rowData as conditional, prevents from rendering while filling the addition row.
Then I triggered the add action as shown here:
const MyComponent() {
const addActionRef = React.useRef();
return (
<>
<button onClick={() => addActionRef.current.click()}>
Add new item
</button>
<MaterialTable
//...
components={{
Action: props => {
//If isn't the add action
if (typeof props.action === typeof Function || props.action.tooltip !== 'Add') {
return <MTableAction {...props} />
} else {
return <div ref={addActionRef} onClick={props.action.onClick}/>;
}}
}}
editable={{
onRowAdd: (newData, oldData) => Promise.resolve(); //your callback here
}}
/>
</>
);
}
I extended the original snippet in order to complete the addition cycle. If you need to handle different types of actions, I think Editable section from the oficial docs would be handy.
Hope this works for you! Full code and sandbox here:
import React, { Fragment, useState } from "react";
import MaterialTable, { MTableAction } from "material-table";
import AddIcon from "#material-ui/icons/AddAlarm";
import IconButton from "#material-ui/core/IconButton";
export default function CustomEditComponent(props) {
const tableRef = React.createRef();
const addActionRef = React.useRef();
const tableColumns = [
{ title: "Client", field: "client" },
{ title: "Name", field: "name" },
{ title: "Year", field: "year" },
{
title: "Custom Add",
field: "internal_action",
editable: false,
render: (rowData) =>
rowData && (
<IconButton
color="secondary"
onClick={() => addActionRef.current.click()}
>
<AddIcon />
</IconButton>
)
}
];
const [tableData, setTableData] = useState([
{
client: "client1",
name: "Mary",
year: "2019"
},
{
client: "client2",
name: "Yang",
year: "2018"
},
{
client: "client3",
name: "Kal",
year: "2019"
}
]);
return (
<Fragment>
<MaterialTable
tableRef={tableRef}
columns={tableColumns}
data={tableData}
title="Custom Add Mode"
options={{
search: false
}}
components={{
Action: (props) => {
//If isn't the add action
if (
typeof props.action === typeof Function ||
props.action.tooltip !== "Add"
) {
return <MTableAction {...props} />;
} else {
return <div ref={addActionRef} onClick={props.action.onClick} />;
}
}
}}
actions={[
{
icon: "save",
tooltip: "Save User",
onClick: (event, rowData) => alert("You saved " + rowData.name)
}
]}
editable={{
onRowAdd: (newData) =>
Promise.resolve(setTableData([...tableData, newData]))
}}
/>
</Fragment>
);

Why adding extra state helps to update other state?

Here is the full code:
import * as React from 'react';
import { View, ScrollView, StyleSheet } from 'react-native';
import {
Appbar,
Searchbar,
List,
BottomNavigation,
Text,
Button,
} from 'react-native-paper';
const AccordionCollection = ({ data }) => {
var bookLists = data.map(function (item) {
var items = [];
for (let i = 0; i < item.total; i++) {
items.push(
<Button mode="contained" style={{ margin: 10 }}>
{i}
</Button>
);
}
return (
<List.Accordion
title={item.title}
left={(props) => <List.Icon {...props} icon="alpha-g-circle" />}>
<View
style={{
flexDirection: 'row',
flexWrap: 'wrap',
alignItems: 'flex-start',
backgroundColor: 'white',
}}>
{items}
</View>
</List.Accordion>
);
});
return bookLists;
};
const MusicRoute = () => {
const DATA = [
{
key: 1,
title: 'Zain dishes',
total: 21,
},
{
key: 2,
title: 'Sides',
total: 32,
},
{
key: 3,
title: 'Drinks',
total: 53,
},
{
key: 4,
title: 'Aesserts',
total: 14,
},
];
const [data, setData] = React.useState(DATA);
const [searchQuery, setSearchQuery] = React.useState('');
const [sortAZ, setSortAZ] = React.useState(false);
const onChangeSearch = (query) => {
setSearchQuery(query);
const newData = DATA.filter((item) => {
return item.title.toLowerCase().includes(query.toLowerCase());
});
setData(newData);
};
const goSortAZ = () => {
setSortAZ(true);
setData(
data.sort((a, b) => (a.title > b.title ? 1 : b.title > a.title ? -1 : 0))
);
};
const goUnSort = () => {
setSortAZ(false);
setData(DATA);
};
return (
<View>
<Appbar.Header style={styles.appBar}>
<Appbar.BackAction onPress={() => null} />
<Searchbar
placeholder="Search"
onChangeText={onChangeSearch}
value={searchQuery}
style={styles.searchBar}
/>
<Appbar.Action
icon="sort-alphabetical-ascending"
onPress={() => goSortAZ()}
/>
<Appbar.Action icon="library-shelves" onPress={() => goUnSort()} />
</Appbar.Header>
<ScrollView>
<List.Section title="Accordions">
<AccordionCollection data={data} />
</List.Section>
</ScrollView>
</View>
);
};
const AlbumsRoute = () => <Text>Albums</Text>;
const MyComponent = () => {
const [index, setIndex] = React.useState(0);
const [routes] = React.useState([
{ key: 'music', title: 'Music', icon: 'queue-music' },
{ key: 'albums', title: 'Albums', icon: 'album' },
]);
const renderScene = BottomNavigation.SceneMap({
music: MusicRoute,
albums: AlbumsRoute,
});
return (
<BottomNavigation
navigationState={{ index, routes }}
onIndexChange={setIndex}
renderScene={renderScene}
/>
);
};
const styles = StyleSheet.create({
appBar: {
justifyContent: 'space-between',
},
searchBar: {
width: '60%',
shadowOpacity: 0,
borderRadius: 10,
backgroundColor: '#e4e3e3',
},
});
export default MyComponent;
Expo Snack Link
There are two weird mechanisms.
First
If I remove sortAZ(true) in goSortAZ() and sortAZ(false) in goUnSort(), the state data stops updating after you press on (1) sort and (2) unsort buttons more than three times.
Second
If I remove DATA array outside the component, sort and unsort buttons does not work/update.
If I do not remove these two, I can sort and unsort the list.
I feel that the code is messy although it achieves the function.
My questions is:
Why adding extra state (sortAZ) helps to update other state (data)?
Just totally remove sortAZ variable (no need to use it unless you somehow want to have a loading status, but since you are not making http requests, that's not necessary) and replace goSortAZ with the following:
Remember to clone the original array in order to create a new copy and then sort that copy.
This is working fine.
const goSortAZ = () => {
setData(
[...data].sort((a, b) => (a.title > b.title ? 1 : b.title > a.title ? -1 : 0))
);
};
i would suggest using the same technique for the unSort method too.

Using Apollo GraphQL refetch method from outside

My render function
translateFileAndRefetchQuery = (urn) => {
translateFile(urn);
// How do I refetch data from here?
};
render() {
const translateFormatter = (cell, row) => {
return (
<span>
<Button
onClick={() => translateFileAndRefetchQuery(row.urn)}
>
Translate
</Button>
</span>
);
};
const columns = [
{
dataField: 'name',
text: 'Name',
},
{
dataField: 'lastUpdated',
text: 'Last updated',
},
{
dataField: 'lastTranslated',
text: 'Translate',
formatter: translateFormatter,
},
];
return (
<>
<h3>Models</h3>
<h4>Root > Plans</h4>
{this.state.plansFolderUrn != null &&
<Query query={getProjects()}>
{(data, refetch) => (
<>
<BootstrapTable
keyField="name"
data={data.projects}
columns={columns}
/>
</>
)}
</Query>
}
</>
);
}
I'm using the apollo data fetcher which have a refetch method. I need to call this from outside the Query.
How do i do this?
You could pass the function around in different callbacks. I added a decorator to translateFormatter to not call it right away :
translateFileAndRefetchQuery = (urn, refetch) => {
translateFile(urn);
refetch();
};
render() {
const translateFormatter = refetch => (cell, row) => {
return (
<span>
<Button
onClick={() => translateFileAndRefetchQuery(row.urn, refetch)}
>
Translate
</Button>
</span>
);
};
const getColumns = refetch => [
{
dataField: 'name',
text: 'Name',
},
{
dataField: 'lastUpdated',
text: 'Last updated',
},
{
dataField: 'lastTranslated',
text: 'Translate',
formatter: translateFormatter(refetch),
},
];
return (
<>
<h3>Models</h3>
<h4>Root > Plans</h4>
{this.state.plansFolderUrn != null &&
<Query query={getProjects()}>
{(data, refetch) => (
<>
<BootstrapTable
keyField="name"
data={data.projects}
columns={getColumns(refetch)}
/>
</>
)}
</Query>
}
</>
);
}

Categories

Resources