Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I need some help with my code below.
import React, { useState, useEffect } from 'react';
import { Container, Row, Col, ListGroup, Button, InputGroup, FormControl } from 'react-bootstrap';
import FileUpload from './Components/FileUpload'
const MyComponent = () => {
//dump
const importData = {
myFields: ['field1', 'field2','field3','field4'],
exampleData: {
field1: "value1",
field2: "value2",
field3: "value3",
field4: "value4"
},
}
const [currentSelectedField, setCurrentSelectedField] = useState();
const [currentSelectedValue, setCurrentSelectedValue] = useState();
const [selectedFields, setSelectedFields] = useState({})
const [currentItemToEdit, setCurrentItemToEdit] = useState()
const [editValue, setEditValue] = useState('');
const [editKey, setEditKey] = useState('');
const alertDilog = (item) => {
console.log(`You clicked the third ListGroupItem ${item}`);
console.log(selectedFields[item])
let exampleData = importData.exampleData
// console.log(exampleData)
let exampleValue = exampleData[item];
setCurrentSelectedField(item);
let selectedFieldsObject = selectedFields;
console.log(selectedFieldsObject)
selectedFields[item] = item
console.log(selectedFieldsObject)
setSelectedFields(selectedFieldsObject)
// console.log(importProduct)
//console.log(item)
//console.log(exampleValue)
setCurrentSelectedValue(exampleValue)
}
const showExample = (data) => {
if (currentSelectedField) {
if (data) {
return (
<span>Example Data = {data} </span>
)
}
}
else {
return (
<span>You didnt select any field
<br/>
</span>
)
}
}
const checkListData = (item) => {
let flag = 0;
Object.keys(selectedFields).map(function (keyName, keyIndex) {
if (keyName === item) {
flag = 1;
}
})
if (flag === 0) {
return false
} else {
return true
}
}
const selectForEditting = (keyName, value) => {
console.log(keyName)
setCurrentItemToEdit({ key: keyName, value: value })
setEditValue(value)
setEditKey(keyName)
}
const selectToDelete = (keyName, value) => {
let fields = selectedFields;
delete fields[keyName];
console.log(fields)
setSelectedFields(fields);
}
const showselectedItems = () => {
// console.log('render')
// console.log(item)
console.log('existing!')
if (selectedFields) {
// console.log('here')
// console.log(item)
return (
<ListGroup defaultActiveKey="#link1">
{Object.keys(selectedFields).map((keyName, keyIndex)=>
// use keyName to get current key's name
// and a[keyName] to get its value
<ListGroup.Item key={keyIndex} action>
<Container fluid >
<Row>
<Col xs={8}>key : {keyName} <br /> value : {selectedFields[keyName]}</Col>
<Col xs={2}> <Button size="sm" onClick={() => selectForEditting(keyName, selectedFields[keyName])} variant="outline-primary">Edit</Button></Col>
<Col xs={2}> <Button size="sm" onClick={() => selectToDelete(keyName, selectedFields[keyName])} variant="outline-primary">x</Button></Col>
</Row>
</Container>
</ListGroup.Item>
)}
</ListGroup>
)
} else {
return (
<span>No selected Fields</span>
)
}
}
const handleProductEdit = (value) => {
console.log(value)
setEditValue(value)
}
const saveEditfield = (item) => {
console.log('save fields')
console.log(item)
selectedFields[editKey] = editValue
let selectedFieldsObject = item;
Object.keys(selectedFieldsObject).map(function (keyName, keyIndex) {
// use keyName to get current key's name
// and a[keyName] to get its value
if (keyName === editKey) {
selectedFieldsObject[keyName] = editValue
}
})
console.log(selectedFieldsObject)
setSelectedFields(selectedFieldsObject)
}
const showEditArea = () => {
// console.log(currentItemToEdit)
if (currentItemToEdit) {
return (
<div>
<InputGroup className="mb-3">
<InputGroup.Prepend>
<InputGroup.Text id="basic-addon1">Value ({editKey}) </InputGroup.Text>
</InputGroup.Prepend>
<FormControl
placeholder="New value"
aria-label="New value"
aria-describedby="basic-addon1"
value={editValue}
onChange={e => handleProductEdit(e.target.value)}
/>
</InputGroup>
<Button onClick={() => saveEditfield(selectedFields)} variant="primary">Save</Button>
</div>
)
}
}
const showMainArea = () => {
return (<div> <Row>
<Col>
{showExample(currentSelectedValue)}
<ListGroup defaultActiveKey="#link1">
{importData.myFields.map(item => {
return (
<ListGroup.Item className={'my-1'} key={item} active={checkListData(item)} onClick={() => alertDilog(item)}>
{item}
</ListGroup.Item>
)
})
}
</ListGroup>
</Col>
<Col>Custom Fields
{showselectedItems()}
</Col>
<Col>Edit Area
{showEditArea()}
</Col>
</Row>
<Button variant="success" className={'my-2 mx-1 '}>Send</Button>
</div>)
}
return (
<Container fluid>
<Row>
<Col>
{JSON.stringify(selectedFields)}
</Col>
</Row>
{showMainArea()}
</Container>)
}
export default MyComponent;
When I click on the "delete" button, I can delete the data from selectedFields. But it doesn't show on screen.
For example:
I clicked value 1
I deleted value 1
I can't see empty object on screen, but when I click value 2
I can see value 2 only on the screen.
When you mutate the state and set it to state, react doesn't re-render your component as it thinks that nothing has changed in your state since the reference is same.
Its recommended that you clone the state before updating it
const selectToDelete = (keyName, value) => {
let fields = {...selectedFields}; // cloning it.
delete fields[keyName]; // Not update the cloned data
console.log(fields)
setSelectedFields(fields); // Now this will trigger a re-render and reflect the change
}
Related
I'm building a chatbox, on a card I have a messageList that I made with useState:
I'm trying to add images to the initMessageList to be displayed on the card with preview using useRef but it does not show the image (I'm changing the 'messageList' func):
function ConvBoard({ name }) {
const [initMessageList, setMessageList] = useState([])
const messageList = initMessageList.map((now, key) => {
if (now.Image) {
return <img src={preview} />
}
return <Message text={now.text} key={key} />
});
let newText = useRef(null);
const addMessage = () => {
if (newText.current.value != "") {
setMessageList([...initMessageList, {
text: newText.current.value,
key: initMessageList.length
}])
newText.current.value = ""
}
}
const onKeyFunc = function onKeyEnter(e) {
if (e.key === "Enter" && newText.current.value != "") {
{ addMessage() };
}
}
const [image, setImage] = useState();
const [preview, setPreview] = useState();
const pressRef = useRef();
useEffect(() => {
if (image) {
const reader = new FileReader()
reader.onloadend = () => {
setPreview(reader.result)
};
reader.readAsDataURL(image)
setMessageList([...initMessageList, {
text: preview,
key: initMessageList.length
}])
} else {
setPreview(null)
}
}, [image]);
return (
<Tab.Pane eventKey={name}>
<Card className='card'>
<extraWarper className="extra">
{messageList}
</extraWarper>
</Card>
<InputGroup>
<FormControl className='inputLine' ref={newText}
placeholder="your text" onKeyPress={onKeyFunc}
/>
<Button variant="outline-secondary">record</Button>
<DropdownButton title="upload" variant="outline-secondary">
<button onClick={(event) =>
pressRef.current.click()
}>
Send image
</button>
<input ref={pressRef} id="filePicker" style={{ display: "none" }} type={"file"}
onChange={(event) => {
const file = event.target.files[0]
if (file) {
setImage(file)
} else {
setImage(null)
}
}
} />
</DropdownButton>
<Button variant="outline-secondary" onClick={addMessage}>send</Button>
</InputGroup>
</Tab.Pane>
);
export default ConvBoard
}
now the site looks like this:
but when i try to add an Image its blank.
Any ideas?
(Sorry for the mess, and thank you!)
There is no now.Image in this code.
if (now.Image) {
return <img src={preview} />
}
return <Message text={now.text} key={key} />
});
there may be now.Text which represents now.Image and preview in your code
because you set it in this part of code
setMessageList([...initMessageList, {
text: preview,
key: initMessageList.length
}])
I'm trying to get the updated/newly created records and send it to the backend in "queryparam"
import React, { useState, useEffect } from "react";
//import { Container, Row, Col } from "reactstrap";
// import Box from "#mui/material/Box";
// import "bootstrap/dist/css/bootstrap.css";
// import "./index.css";
const Index = () => {
const [formValues, setFormValues] = useState([
{ orderno: 0, inputValue1: "", inputValue2: "", checked: false }
]);
const [isDisabled, setDisabled] = useState(false);
// const [inputVal1, setInputval1] = useState();
const [isChanged, setIsChanged] = useState([]);
const [error, setError] = useState(false);
const [orderNumber, setOrderNumber] = useState(1);
const addFormFields = () => {
// if (error) {
// setDisabled(false)
// }
// else {
// setDisabled(true)
// }
setFormValues((prevState) => [
...prevState,
{
orderno: orderNumber,
inputValue1: "",
inputValue2: "",
checked: false
}
]);
setOrderNumber((prev) => prev + 1);
};
const removeFormFields = (i) => {
let newFormValues = [...formValues];
newFormValues.splice(i, 1);
setFormValues(newFormValues);
setOrderNumber((prev) => prev - 1);
};
const onChangeFieldValue = (index, key, value) => {
setFormValues((prevState) => {
let copyState = [...prevState];
if (value?.length > 0) {
setError(false);
} else {
setError(true);
}
copyState[index][key] = value;
return copyState;
});
};
const saveFields = (e) => {
const queryparam = {
inputData: formValues
};
setIsChanged(queryparam);
setIsChanged((prevState, nextState) => {
let copyState = [];
if (prevState === nextState) {
copyState = [...prevState];
} else {
copyState = [...nextState];
}
return copyState;
});
console.log(isChanged, "lllllllll");
};
// useEffect(() => {
// saveFields()
// }, [isChanged])
return (
<>
{formValues.map((element, index) => (
<div className="form-inline" key={index}>
{/* <Container>
<Row>
<Col xs="12" sm="6"> */}
<label>{index + 1}</label>
<input
type="text"
value={element.inputVal1}
onChange={(e) =>
onChangeFieldValue(index, "inputValue1", e.target.value)
}
/>
<input
type="text"
value={element.inputVal2}
required
onChange={(e) =>
onChangeFieldValue(index, "inputValue2", e.target.value)
}
/>
{/* </Col>
<Col xs="12" sm="6">
<Box> */}
<button
className={`button ${error ? "add" : "btn-secondary"}`}
type="button"
disabled={error}
onClick={(e) => addFormFields(e)}
>
Add{console.log(isDisabled, "ooooooo", error)}
</button>
<button
type="button"
className="button remove"
onClick={() => removeFormFields(index)}
>
Remove
</button>
{/* </Box>
</Col>
</Row>
</Container> */}
</div>
))}
{/* <Row>
<Col sm="6" md={{ size: 4, offset: 2 }}>
<Box> */}
<button
type="button"
className="button save"
onClick={(e) => saveFields(e)}
>
Save
</button>
<button
type="button"
className="button remove"
//onClick={(e) => cancelFields(e)}
>
cancel
</button>
{/* </Box>
</Col>
</Row> */}
</>
);
};
export default Index;
https://codesandbox.io/s/black-fire-ixeir?file=/src/App.js:3662-3701
In the above link,
Step1 : when I add values for inputs "123" in input1 and "345" in input2.Then when I click on "Save" the values sent are {"input1":"123","input2":"345"}.
Step2: Again I try to add one row for inputs "456" in input1 and "678" in input2.Then when I click on save the values sent are {"input1":"456","input2":"678"}.
When I edit the existing row, for example the first row values and when I click on "Save" then only the first row value should be sent as the second row values hasn't changed.Also, If I add new rows then the newly added only should be sent if the existing row values aren't changed. Is there any way to send only the updated/newly created values to the backend using react hook
You could use a separate changes object to track changes by orderno property; saved during add/update/remove, and committed when submitting.
const [changes, setChanges] = useState({});
...
const addFormFields = () => {
const newItem = {
orderno: orderNumber,
inputValue1: "",
inputValue2: "",
checked: false,
type: "add"
};
setFormValues((values) => [...values, newItem]);
setChanges((changes) => ({
...changes,
[newItem.orderno]: newItem
}));
setOrderNumber((prev) => prev + 1);
};
const removeFormFields = (index) => {
const item = {
...formValues[index],
type: "remove"
};
setFormValues((values) => values.filter((el, i) => i !== index));
setChanges((changes) => ({
...changes,
[item.orderno]: item
}));
};
const onChangeFieldValue = (index, key, value) => {
const item = {
...formValues[index],
[key]: value,
type: "edit"
};
setFormValues((prevState) => {
if (value?.length > 0) {
setError(false);
const copyState = [...prevState];
copyState[index] = item;
return copyState;
} else {
setError(true);
return prevState;
}
});
setChanges((changes) => ({
...changes,
[item.orderno]: item
}));
};
const saveFields = (e) => {
const queryparam = {
inputData: Object.values(changes)
};
console.log("Changes to commit", queryparam);
setChanges({});
};
I find myself struggling to change the form input value from the button onClick handler. My problem is escalated by the fact that I have the line items on a form and things become even more complex that way. I tried to bring in a ref to set value,,, the value is displayed but at the form state after submission it remains empty which means the value is not being set. Below are all my code files. May someone kindly help me on where I may be missing the point.
class VehicleTemplate extends React.Component {
constructor(props){
super(props);
this.ws = new WebSocket('ws://localhost:8000/ws/weightData/');
this.socketRef = null;
this.state = {
data: 0,
name: '',
model: '',
plate_number: '',
type: 'truck',
wagons: [{ index: uuid(), label: '', type: 'once', weight: '' }],
total: 0,
};
this.onSubmit = this.onSubmit.bind(this);
this.handleChange= this.handleChange.bind(this);
this.handleChangeTable = this.handleChangeTable.bind(this);
this.addNewRow = this.addNewRow.bind(this);
this.deleteRow = this.deleteRow.bind(this);
this.handleLineItemChange = this.handleLineItemChange.bind(this);
}
componentDidMount() {
this.ws.onopen = () => {
// on connecting, do nothing but log it to the console
console.log('connected')
}
this.ws.onmessage = evt => {
// listen to data sent from the websocket server
// const message = JSON.parse(evt.data)
const {data} = this.state;
this.setState({data: evt.data})
// this.setState({this.state.lines.weight: data})
}
this.ws.onclose = () => {
console.log('disconnected')
// automatically try to reconnect on connection loss
}
};
onSubmit = (e) => {
e.preventDefault();
const {
name,
model,
plate_number,
type,
wagons,
} = this.state;
const vehicle = {
name,
model,
plate_number,
type,
wagons,
};
this.props.addVehicle(vehicle, this.props.token);
console.log(vehicle);
this.setState({
name: '',
model: '',
plate_number: '',
wagons: [],
});
};
handleLineItemChange = (elementIndex) => (event) => {
let wagons = this.state.wagons.map((item, i) => {
if (elementIndex !== i) return item
return {...item, [event.target.name]: event.target.value}
})
this.setState({wagons})
}
handleChange = name => event => {
this.setState({
[name]: event.target.value,
});
};
handleChangeTable = (name, id) => event => {
this.updateItem(id, { [name]: event.target.value });
};
addNewRow = (event) => {
this.setState({
wagons: this.state.wagons.concat(
[{index: uuid(), label: '', type: 'once', weight: '' }]
)
})
}
deleteRow = (index) => (event) => {
this.setState({
wagons: this.state.wagons.filter((item, i) => {
return index !== i
})
})
}
handleReorderLineItems = (newLineItems) => {
this.setState({
wagons: newLineItems,
})
}
clickOnDelete(record) {
this.setState({
wagons: this.state.lines.filter(r => r !== record)
});
}
render() {
const { classes } = this.props;
const {
data,
name,
model,
plate_number,
wagons,
} = this.state;
return (
<InformationTechnologyLayout>
<PapperBlock title="ADD VEHICLE" icon="ios-document-outline" desc="VEHICLE">
<Form>
<div style={{ clear: 'both' }} />
<h1>WEIGHT: {data}KG</h1>
<Grid container>
<Grid item xs={6}>
<Controls.Input
name="name"
label="Name"
value={name}
onChange={this.handleChange('name')}
/>
<Controls.Input
name="model"
label="MODEL"
value={model}
onChange={this.handleChange('model')}
/>
</Grid>
<Grid item xs={6}>
<Controls.Input
name="plate_number"
label="PLATE NUMBER"
value={plate_number}
onChange={this.handleChange('plate_number')}
/>
</Grid>
</Grid>
<Extensions
items={wagons}
addHandler={this.addNewRow}
changeHandler={this.handleLineItemChange}
focusHandler={this.handleFocusSelect}
deleteHandler={this.deleteRow}
reorderHandler={this.handleReorderLineItems}
data ={data}
/>
<div className='valueTable'>
<div className='row'>
<div className='label'>Subtotal</div>
<div className='value'>{this.calcLineItemsTotal()}KG</div>
</div>
<div className='row'>
<div className='label'>Total Due</div>
<div className='value'>{this.calcGrandTotal()}KG</div>
</div>
</div>
<Button variant="contained" onClick={this.onSubmit}>SUBMIT</Button>
</Form>
</PapperBlock>
</InformationTechnologyLayout>
);
}
}
On top is the main form component which has got Vehicle exetnsions and I am getting my weight from a websocket connection streaming scale outputs.
class Extensions extends Component {
handleDragEnd = (result) => {
if (!result.destination) return
// helper function to reorder result (src: react-beautiful-dnd docs)
const reorder = (list, startIndex, endIndex) => {
const result = Array.from(list)
const [removed] = result.splice(startIndex, 1)
result.splice(endIndex, 0, removed)
return result
}
// perform reorder
const lineItems = reorder(
this.props.items,
result.source.index,
result.destination.index
)
// call parent handler with new state representation
this.props.reorderHandler(lineItems)
}
render = () => {
const {
items,
addHandler,
changeHandler,
focusHandler,
deleteHandler,
reorderHandler,
products,
data,
readOnly,
} = this.props
return (
<form>
<div className='lineItems'>
<div className='gridTable'>
<DragDropContext onDragEnd={this.handleDragEnd}>
<Droppable droppableId="droppable">
{(provided, snapshot) => (
<div
ref={provided.innerRef}
className= 'listDraggingOver'
>
{this.props.items.map((item, i) => (
<Draggable key={item.index} draggableId={item.index} index={i}>
{(provided, snapshot) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
style={provided.draggableProps.style}
className='listItemDragging'
>
<Extension
addHandler={addHandler}
changeHandler={changeHandler}
focusHandler={focusHandler}
deleteHandler={deleteHandler}
reorderHandler={reorderHandler}
data={data}
style={{color: 'red'}}
key={i + item.index}
index={i}
name={item.index}
label={item.label}
weight={item.weight}
/>
</div>
)}
</Draggable>
))}
{provided.placeholder}
</div>
)}
</Droppable>
</DragDropContext>
</div>
<div className='addItem'>
<button type="button" onClick={addHandler}><AddIcon size="1.25em" className='addIcon' /> Add Item</button>
</div>
</div>
</form>
)
}
}
This are the extensions and the last file is where I would like to capture weight from
class LineItem extends Component {
constructor(props){
super(props);
this.ref = React.createRef();
this.state = {
buttonState: false,
};
}
requestWeight = () => {
const { weight } = this.props;
const {buttonState} =this.state;
this.ref.current.value = this.props.data;
this.setState({
buttonState: true
})
};
render = () => {
const { index, label, weight } = this.props;
const {buttonState} = this.state;
return (
<div className='lineItem'>
<div>{index + 1}</div>
<Controls.Input
name="label"
label="LABEL"
value={label}
onChange={this.props.changeHandler(index)}
/>
<input
className='currency'
type='number'
readOnly={true}
ref={this.ref}
name='weight'
onChange={this.props.changeHandler(index)}
/>
<div>
<button type="button"
className='requestItems'
onClick={this.requestWeight}
disabled={buttonState}
>REQUEST WEIGHT</button>
</div>
<div>
<button type="button"
className='deleteItem'
onClick={this.props.deleteHandler(index)}
><DeleteIcon size="1.25em" /></button>
</div>
</div>
)
}
}
export default LineItem
If I add the value and put weight on the input then the ref stops working. I assume I might be missing something between my handleChange function and the requestWeight function but I really dont know what exaclty
I've two different prices,
when i check the checkbox for second price,
the state show and display the second price properly
but when i press the pay button of that product with second price, it will send the first price
instead of what I've checked which was second price.
so i want increment both prices separately when i checked the check box and
it sends the specific price to the payment process
import React, { useState, useEffect } from "react";
import {
getProducts,
getBraintreeClientToken,
processPayment,
createOrder
} from "./apiCore";
import { emptyCart } from "./cartHelpers";
import { isAuthenticated } from "../auth";
import { Link } from "react-router-dom";
import "braintree-web";
import DropIn from "braintree-web-drop-in-react";
import { makeStyles } from '#material-ui/core/styles';
import TextField from '#material-ui/core/TextField';
const useStyles = makeStyles((theme) => ({
root: {
'& > *': {
margin: theme.spacing(1),
width: '25ch',
},
},
}));
const Checkout = ({ products, setRun = f => f, run = undefined }) => {
const classes = useStyles();
const [data, setData] = useState({
loading: false,
success: false,
clientToken: null,
error: "",
instance: {},
address: "",
mobile:""
});
>>>>>> const [price, setPrice]= useState(() => () => getTotal())
>>>>>> const [isChecked, setIsChecked]= useState(false);
const userId = isAuthenticated() && isAuthenticated().user._id;
const token = isAuthenticated() && isAuthenticated().token;
const getToken = (userId, token) => {
getBraintreeClientToken(userId, token).then(data => {
if (data.error) {
setData({ ...data, error: data.error });
} else {
setData({ clientToken: data.clientToken });
}
});
};
useEffect(() => {
getToken(userId, token);
}, []);
const handleAddress = event => {
setData({ ...data, address: event.target.value });
};
const handleMobile = event => {
setData({ ...data, mobile: event.target.value });
};
>>>>>> const getTotal = () => {
>>>>>> return products.reduce((currentValue, nextValue) => {
>>>>>> return currentValue + nextValue.count * nextValue.price;
>>>>>>
>>>>>> }, 0);
>>>>>> };
>>>>>> const getTotal2 = () => {
>>>>>> return products.reduce((currentValue, nextValue) => {
>>>>>> return currentValue + nextValue.count * nextValue.price2;
>>>>>> }, 0);
>>>>>> };**
const showCheckout = () => {
return isAuthenticated() ? (
<div>{showDropIn()}</div>
) : (
<Link to="/signin">
<button className="btn btn-primary">Sign in to checkout</button>
</Link>
);
};
let deliveryAddress = data.address
let deliveryMobile = data.mobile
const buy = () => {
setData({ loading: true });
// send the nonce to your server
// nonce = data.instance.requestPaymentMethod()
let nonce;
let getNonce = data.instance
.requestPaymentMethod()
.then(data => {
// console.log(data);
nonce = data.nonce;
// once you have nonce (card type, card number) send nonce as 'paymentMethodNonce'
// and also total to be charged
// console.log(
// "send nonce and total to process: ",
// nonce,
// getTotal(products)
// );
>>>>>> **const paymentData = {
>>>>>> paymentMethodNonce: nonce,
>>>>>> amount: getTotal(products)
>>>>>> };**
processPayment(userId, token, paymentData)
.then(response => {
console.log(response);
// empty cart
// create order
const createOrderData = {
products: products,
transaction_id: response.transaction.id,
amount: response.transaction.amount,
address: deliveryAddress,
mobile: deliveryMobile
};
createOrder(userId, token, createOrderData)
.then(response => {
emptyCart(() => {
setRun(!run); // run useEffect in parent Cart
console.log(
"payment success and empty cart"
);
setData({
loading: false,
success: true
});
});
})
.catch(error => {
console.log(error);
setData({ loading: false });
});
})
.catch(error => {
console.log(error);
setData({ loading: false });
});
})
.catch(error => {
// console.log("dropin error: ", error);
setData({ ...data, error: error.message });
});
};
const showDropIn = () => (
<div onBlur={() => setData({ ...data, error: "" })}>
{data.clientToken !== null && products.length > 0 ? (
<div>
<div className="gorm-group mb-3">
<label className="text-muted">Delivery address:</label>
<textarea
onChange={handleAddress}
className="form-control"
value={data.address}
placeholder="Type your delivery address here..."
/>
</div>
<div className="gorm-group mb-3">
<label className="text-muted">mobile number:</label>
<form className={classes.root} noValidate autoComplete="off">
<TextField placeholder="mobile number" onChange={handleMobile} type="text" value={data.mobile} id="outlined-basic" label="mobile" variant="outlined" />
</form>
</div>
<DropIn
options={{
authorization: data.clientToken,
paypal: {
flow: "vault"
}
}}
onInstance={instance => (data.instance = instance)}
/>
<button onClick={buy} className="btn btn-success btn-block">
Pay
</button>
</div>
) : null}
</div>
);
const showError = error => (
<div
className="alert alert-danger"
style={{ display: error ? "" : "none" }}
>
{error}
</div>
);
const showSuccess = success => (
<div
className="alert alert-info"
style={{ display: success ? "" : "none" }}
>
Thanks! Your payment was successful!
</div>
);
const showLoading = loading =>
loading && <h2 className="text-danger">Loading...</h2>;
return (
<div>
>>>>>> **<form>
>>>>>> <h1>قیمت کل: {isChecked ? getTotal2() : getTotal()} </h1>
>>>>>> <label>نیم لیتر :</label>
>>>>> <input type="checkbox"
>>>>>> checked={isChecked}
>>>>>> onChange={(e)=>{setIsChecked(e.target.checked)}}/>
>>>>>> </form>**
{showLoading(data.loading)}
{showSuccess(data.success)}
{showError(data.error)}
{showCheckout()}
</div>
);
};
export default Checkout;
my card component
import React, { useState, version,useEffect } from 'react';
import { Link, Redirect } from 'react-router-dom';
import ShowImage from './ShowImage';
import moment from 'moment';
import { addItem, updateItem, removeItem } from './cartHelpers';
import logo from '../images/logo.svg'
//material ui
import Card from '#material-ui/core/Card';
import CardContent from '#material-ui/core/CardContent';
import { makeStyles } from '#material-ui/core/styles';
import Button from '#material-ui/core/Button';
import Grid from '#material-ui/core/Grid'
import { Typography } from '#material-ui/core';
import CardHeader from '#material-ui/core/CardHeader';
import CardMedia from '#material-ui/core/CardMedia';
import CardActions from '#material-ui/core/CardActions';
import Collapse from '#material-ui/core/Collapse';
import Avatar from '#material-ui/core/Avatar';
import IconButton from '#material-ui/core/IconButton';
import MoreVertIcon from '#material-ui/icons/MoreVert';
import FormControlLabel from '#material-ui/core/FormControlLabel';
import Menu from '#material-ui/core/Menu';
import MenuItem from '#material-ui/core/MenuItem';
import { create } from 'jss';
import rtl from 'jss-rtl';
import { StylesProvider, jssPreset } from '#material-ui/core/styles';
const jss = create({ plugins: [...jssPreset().plugins, rtl()] });
const useStyles = makeStyles((theme) => ({
stock: {
marginBottom: '1rem'
},
Button: {
...theme.typography.button,
padding: '.3rem',
minWidth: 10,
},
media: {
height: 0,
paddingTop: '56.25%', // 16:9
},
title: {
backgroundColor: '#D8D8D8'
},
grid: {
padding: '0'
},
cardFont:{
...theme.typography.body,
textAlign:'right',
marginTop:'.8rem',
marginRight:'1rem'
},productName:{
...theme.typography.body,
textAlign:'right',
},
cardButton:{
marginLeft:'1.4rem'
}
}));
const Cardd = ({
product,
showViewProductButton = true,
showAddToCartButton = true,
cartUpdate = false,
showRemoveProductButton = false,
setRun = f => f,
run = undefined
// changeCartSize
}) => {
const [redirect, setRedirect] = useState(false);
const [count, setCount] = useState(product.count);
//material ui
const [anchorEl, setAnchorEl] = React.useState(null);
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
// console.log(price)
const classes = useStyles()
const showViewButton = showViewProductButton => {
return (
showViewProductButton && (
<Link to={`/product/${product._id}`} className="mr-2">
<Button className={classes.Button} size="small" variant="contained">مشاهده محصول</Button>
</Link>
)
);
};
const addToCart = () => {
// console.log('added');
addItem(product, setRedirect(true));
};
const shouldRedirect = redirect => {
if (redirect) {
return <Redirect to="/cart" />;
}
};
const showAddToCartBtn = showAddToCartButton => {
return (
showAddToCartButton && (
<Button className={classes.Button} size="small" onClick={addToCart} variant="contained" color="primary" disableElevation>
اضافه کردن به سبد
</Button>
)
);
};
const showStock = quantity => {
return quantity > 0 ? (
<Button disabled size="small" className={classes.stock}>موجود </Button>
) : (
<Button className={classes.stock}>ناموجود </Button>
);
};
const handleChange = productId => event => {
setRun(!run); // run useEffect in parent Cart
setCount(event.target.value < 1 ? 1 : event.target.value);
if (event.target.value >= 1) {
updateItem(productId, event.target.value);
}
};
const showCartUpdateOptions = cartUpdate => {
return (
cartUpdate && (
<div>
<div className="input-group mb-3">
<div className="input-group-prepend">
<span className="input-group-text">تعداد</span>
</div>
<input type="number" className="form-control" value={count} onChange={handleChange(product._id)} />
</div>
</div>
)
);
};
const showRemoveButton = showRemoveProductButton => {
return (
showRemoveProductButton && (
<Button className={classes.Button} size="small" variant="contained" color="secondary" disableElevation
onClick={() => {
removeItem(product._id);
setRun(!run); // run useEffect in parent Cart
}}
>
حذف محصول
</Button>
)
);
};
return (
<Grid container direction='column' >
<Grid item >
<Card style={{margin:'1rem'}}>
<Grid item className={classes.title}>
<Typography className={classes.productName} variant='h6'>
{product.name}
</Typography>
</Grid>
<CardHeader
avatar={
<Avatar alt="Remy Sharp" src={logo} className={classes.green}>
</Avatar>
}
action={
<IconButton aria-label="settings">
<MoreVertIcon />
</IconButton>
}
title="روغنک"
subheader="September 14, 2016"
/>
<CardContent className={classes.grid} >
{shouldRedirect(redirect)}
<ShowImage item={product} url="product" />
<StylesProvider jss={jss}>
<Typography className={classes.cardFont} variant="body2" component="p">
{product.description.substring(0, 100)}
</Typography>
</StylesProvider>
<div>
<Button aria-controls="simple-menu" aria-haspopup="true" onClick={handleClick}>
Open Menu
</Button>
<Menu
id="simple-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
>
<MenuItem onClick={handleClose}>Profile</MenuItem>
<MenuItem onClick={handleClose}>My account</MenuItem>
<MenuItem onClick={handleClose}>Logout</MenuItem>
</Menu>
</div>
<Typography className={classes.cardFont} variant="body2" component="p">
$یک لیتر {product.price}
</Typography>
<Typography className={classes.cardFont} variant="body2" component="p">
$نیم لیتر {product.price2}
</Typography>
<Typography className={classes.cardFont} variant="body2" component="p">
Category: {product.category && product.category.name}
</Typography>
<Typography className={classes.cardFont} variant="body2" component="p">
Added on {moment(product.createdAt).fromNow()}
</Typography>
<Typography className={classes.cardFont} variant="body2" component="p">
{showStock(product.quantity)}
</Typography>
<br />
<Grid container >
<Grid item className={classes.cardButton} >
{showViewButton(showViewProductButton)}
</Grid>
<Grid item className={classes.cardButton}>
{showAddToCartBtn(showAddToCartButton)}
</Grid>
<Grid item className={classes.cardButton}>
{showRemoveButton(showRemoveProductButton)}
</Grid>
</Grid>
{showCartUpdateOptions(cartUpdate)}
</CardContent>
</Card>
</Grid>
</Grid>
// <div className="card ">
// <div className="card-header card-header-1 ">{product.name}</div>
// <div className="card-body">
// {shouldRedirect(redirect)}
// <ShowImage item={product} url="product" />
// <p className="card-p mt-2">{product.description.substring(0, 100)} </p>
// <p className="card-p black-10">$ {product.price}</p>
// <p className="black-9">Category: {product.category && product.category.name}</p>
// <p className="black-8">Added on {moment(product.createdAt).fromNow()}</p>
// {showStock(product.quantity)}
// <br />
// {showViewButton(showViewProductButton)}
// {showAddToCartBtn(showAddToCartButton)}
// {showRemoveButton(showRemoveProductButton)}
// {showCartUpdateOptions(cartUpdate)}
// </div>
// </div>
);
};
export default Cardd;
CartHelper component
export const addItem = (item = [], count = 0, next = f => f) => {
let cart = [];
if (typeof window !== 'undefined') {
if (localStorage.getItem('cart')) {
cart = JSON.parse(localStorage.getItem('cart'));
}
cart.push({
...item,
count: 1
});
// remove duplicates
// build an Array from new Set and turn it back into array using Array.from
// so that later we can re-map it
// new set will only allow unique values in it
// so pass the ids of each object/product
// If the loop tries to add the same value again, it'll get ignored
// ...with the array of ids we got on when first map() was used
// run map() on it again and return the actual product from the cart
cart = Array.from(new Set(cart.map(p => p._id))).map(id => {
return cart.find(p => p._id === id);
});
localStorage.setItem('cart', JSON.stringify(cart));
next();
}
};
export const itemTotal = () => {
if (typeof window !== 'undefined') {
if (localStorage.getItem('cart')) {
return JSON.parse(localStorage.getItem('cart')).length;
}
}
return 0;
};
export const getCart = () => {
if (typeof window !== 'undefined') {
if (localStorage.getItem('cart')) {
return JSON.parse(localStorage.getItem('cart'));
}
}
return [];
};
export const updateItem = (productId, count) => {
let cart = [];
if (typeof window !== 'undefined') {
if (localStorage.getItem('cart')) {
cart = JSON.parse(localStorage.getItem('cart'));
}
cart.map((product, i) => {
if (product._id === productId) {
cart[i].count = count;
}
});
localStorage.setItem('cart', JSON.stringify(cart));
}
};
export const removeItem = productId => {
let cart = [];
if (typeof window !== 'undefined') {
if (localStorage.getItem('cart')) {
cart = JSON.parse(localStorage.getItem('cart'));
}
cart.map((product, i) => {
if (product._id === productId) {
cart.splice(i, 1);
}
});
localStorage.setItem('cart', JSON.stringify(cart));
}
return cart;
};
export const emptyCart = next => {
if (typeof window !== 'undefined') {
localStorage.removeItem('cart');
next();
}
};
How to add sort to the data by using a button
import React, { useState } from "react";
import { Container, Row, Col } from "reactstrap";
import EmployeeCard from "./EmployeeCard";
import data from "./data.json";
import Modal from "./Modal";
import Subheader from "./Subheader";
import "./Employeelist.css";
function Employeelist() {
const [state, setState] = useState({ search: null });
const searchSpace = event => {
let keyword = event.target.value;
setState({ search: keyword });
};
const employeeCards = data.employee
.filter(data => {
if (state.search == null) return data;
else if (
data.firstName.toLowerCase().includes(state.search.toLowerCase()) ||
data.lastName.toLowerCase().includes(state.search.toLowerCase())
) {
return data;
}
})
.map(person => {
return (
<Col sm="4">
<EmployeeCard key={person.id} person={person} />
</Col>
);
});
return (
<div>
<input
type="text"
placeholder="Search"
class="elementStyle"
onChange={e => searchSpace(e)}
/>
<br />
<br />
<br />
<Container fluid>
<Row>{employeeCards}</Row>
</Container>
</div>
);
}
export default Employeelist;
Add some state to hold the sorted/unsorted data and a sortActive boolean, and a handler to toggle the sort active or not. Use an effect to sort/unsort using the sortActive as a dependency.
Also fixed other discrepancies, I tried noting them.
function Employeelist() {
const [state, setState] = useState({ search: null });
const searchSpace = event => {
let keyword = event.target.value;
setState({ search: keyword });
};
// state to hold sorted/unsorted data array, sortActive, and handler
const [sortedData, setSortedData] = useState(data.employee);
const [sortActive, setSortActive] = useState(false);
const toggleSortActiveHandler = () => setSortActive(a => !a);
useEffect(() => {
if (sortActive) {
setSortedData(
// Gotcha: array::sort is an in-place sort, meaning it mutates
// the existing array.
// Spreading it into a new array then sorting addresses this.
[...data.employee].sort((a, b) => {
if (a.lastName < b.lastName) return -1;
if (a.lastName > b.lastName) return 1;
return 0;
})
);
} else {
setSortedData(data.employee);
}
}, [sortActive]);
const employeeCards = sortedData
.filter(data => {
// filter returns true/false if element should be filtered
if (state.search == null) return true;
return (
data.firstName.toLowerCase().includes(state.search.toLowerCase()) ||
data.lastName.toLowerCase().includes(state.search.toLowerCase())
);
})
.map(person => {
return (
<Col key={person.id} sm="4"> { /* <-- react key on outer most element */ }
<EmployeeCard person={person} />
</Col>
);
});
return (
<div>
<input
type="text"
placeholder="Search"
className="elementStyle"
onChange={e => searchSpace(e)}
/>
<br />
<br />
<br />
<Container fluid>
<Row>{employeeCards}</Row>
</Container>
{ /* button to toggle the sort */ }
<button type="button" onClick={toggleSortActiveHandler}>
Toggle Alpha Sort
</button>
</div>
);
}