import React, { useState, useEffect, Fragment } from "react";
import Button from "../../../Resources/Forms/Button";
import Switch from "../../../Resources/Forms/Switch";
import { POST } from "../../../Utils/api";
import Radio from "../../../Resources/Forms/Radio";
import withAppData from "../../../HOC/withAppData";
const InventorySettings = (props) => {
const [state, setState] = useState({});
const [isSaving, setIsSaving] = useState();
const [isStockRequestChecked, setIsStockRequestChecked] = useState(false);
const getStatus = id => {
return props.context.isSettingsActivated(id) ? 1 : 0;
};
const setBusinessSettings = async () => {
const defaultSettings = [
{ state: "enableStockRequest", id: 53 },
{ state: "connectWarehousePickStock", id: 52 },
{ state: "approveRequestOtp", id: 51 },
{ state: "approveRequestManually", id: 50 }
];
for (const setting of defaultSettings) {
await setState({ [setting.state]: getStatus(setting.id) });
}
};
function chooseApprovalMethod(methodType) {
const currentValue = state[methodType];
setState({[methodType]
: currentValue === 1 ? 0: 1})
}
async function saveApprovalMethod() {
setIsSaving(true)
const approvalSettings = [{text:"approvalRequestManually", id: 51}, {text:"approveRequestOtp", id: 50}]
for(const el of approvalSettings) {
const currentValue = state[el.text];
const data = {
settingId: el.id,
status: currentValue
}
await POST(`Common/AddBusinessSetting`, data);
}
setIsSaving(false);
props.context.getBusinessSettings();
}
const updateBasicSettings = async (id, key) => {
setState({ [key]: !state[key] ? 1 : 0 });
const data = {
SettingId: id,
Status: state[key],
};
await POST(`Common/AddBusinessSetting`, data);
props.context.getBusinessSettings();
};
useEffect(() => {
setBusinessSettings();
}, []);
return (
<Fragment>
<div className="basic-settings-section">
<Switch
label={"Connect Warehouse Stock to pick stock"}
light={true}
checked={state && state.connectWarehousePickStock === 1}
onChange={() => updateBasicSettings(52, "connectWarehousePickStock")}
></Switch>
</div>
<div className="basic-settings-section">
<Switch
label={"Stock Request"}
light={true}
checked={isStockRequestChecked}
onChange={() => setIsStockRequestChecked(!isStockRequestChecked)}
></Switch>
{isStockRequestChecked && (
<div className="basic-settings-plan-generate">
<div
className="form__label"
style={{ padding: "2px", marginBottom: "20px" }}
>
<p>Please choose an approval method</p>
</div>
<Radio
label={"Manual Approval"}
name="approval"
value="50"
id="50"
checked={state && state.approveRequestManually === 1}
// onChange={() => (chooseApprovalMethod)}
/>
<Radio
label={"OTP Approval"}
name="approval"
value="51"
id="51"
checked={state && state.approveRequestOtp === 1}
// onChange={() => (chooseApprovalMethod)}
/>
<div className="password-settings-btn"
// onClick={props.context.showToast}
>
<Button
type={"outline"}
size={"medium"}
text={"Save"}
disabled={!state.approveRequestOtp && !state.approveRequestManually}
withMargin={false}
loading={isSaving}
onClick={saveApprovalMethod}
></Button>
</div>
</div>
)}
</div>
</Fragment>
);
}
export default withAppData(InventorySettings);
I added the chooseApprovalMethod function to the radio buttons but still I wasn't getting it well. So I had to call there state using state.text is equal to 1. Please help me out I don't think I know what I'm doing anymore.
Please above are my code, the radio buttons aren't checking or highlighting, so I want them to be checked when clicked on, and I want there ids to be saved when clicking on the save button.
So please guys help me out, as I don't understand it anymore.
Related
Good morning. I am trying to integrate PayPal check out in my React app. Everything works fine except that the Paypal Checkout amount is not showing the same as the total cart amount. Checkout amount is fixed at $0.01 and not changing as cart amount changes. Please what could i be doing wrong ??? This is the code
#cart.js code
import React, { useContext, useState, useEffect } from "react";
import { GlobalState } from "../../../GlobalState";
import axios from "axios";
import PayPalButton from "./PaypalButton";
function Cart() {
const state = useContext(GlobalState);
const [cart, setCart] = state.userAPI.cart;
const [token] = state.token;
const [total, setTotal] = useState(0);
useEffect(() => {
const getTotal = () => {
const total = cart.reduce((prev, item) => {
return prev + item.price * item.quantity;
}, 0);
setTotal(total);
};
getTotal();
}, [cart]);
const addToCart = async () => {
await axios.patch(
"/user/addcart",
{ cart },
{
headers: { Authorization: token },
}
);
};
const increment = (id) => {
cart.forEach((item) => {
if (item._id === id) {
item.quantity += 1;
}
});
setCart([...cart]);
addToCart();
};
const decrement = (id) => {
cart.forEach((item) => {
if (item._id === id) {
item.quantity === 1 ? (item.quantity = 1) : (item.quantity -= 1);
}
});
setCart([...cart]);
addToCart();
};
const removeProduct = (id) => {
if (window.confirm("Do you want to delete this product?")) {
cart.forEach((item, index) => {
if (item._id === id) {
cart.splice(index, 1);
}
});
setCart([...cart]);
addToCart();
}
};
const tranSuccess = async (payment) => {
console.log(payment);
};
if (cart.length === 0)
return (
<h2 style={{ textAlign: "center", fontSize: "5rem" }}>Cart Empty</h2>
);
return (
<div>
{cart.map((product) => (
<div className="detail cart" key={product._id}>
<img src={product.images.url} alt="" />
<div className="box-detail">
<h2>{product.title}</h2>
<h3>${product.price * product.quantity}</h3>
<p>{product.description}</p>
<p>{product.content}</p>
<div className="amount">
<button onClick={() => decrement(product._id)}> - </button>
<span>{product.quantity}</span>
<button onClick={() => increment(product._id)}> + </button>
</div>
<div className="delete" onClick={() => removeProduct(product._id)}>
X
</div>
</div>
</div>
))}
<div className="total">
<h3>Total: $ {total}</h3>
<PayPalButton total={total} tranSuccess={tranSuccess} />
</div>
</div>
);
}
export default Cart;
PayPal button code
import React from "react";
import { PayPalScriptProvider, PayPalButtons } from "#paypal/react-paypal-js";
export default class PayPalButton extends React.Component {
render() {
const onSuccess = (payment) => {
console.log("The payment was succeeded!", payment);
this.props.tranSuccess(payment);
};
const onCancel = (data) => {
console.log("The payment was cancelled!", data);
};
const onError = (err) => {
console.log("Error!", err);
};
let env = "sandbox"; // you can set here to 'production' for production
let total = this.props.total;
let currency = "USD";
const client = {
sandbox:
"ARhnfWu_QrcGQa-PdvaY1RVriEmqGiSkfEWf-plauZQpQN_gyxaLjH9RXOhdQw7fxxxxxxxxxxxx",
production: "YOUR-PRODUCTION-APP-ID",
};
let style = {
size: "small",
color: "blue",
shape: "rect",
label: "checkout",
tagline: false,
};
return (
<PayPalScriptProvider
options={{
"client-id": "ARhnfWu_QrcGQa-PdvaY1RVriEmqGiSkfEWf-plauZQpQN_gyxaLjH9RXOhdQw7fxxxxxxxxxxxx",
}}
>
<PayPalButtons
env={env}
client={client}
commit={true}
total={total}
currency={currency}
onError={onError}
onSuccess={onSuccess}
onCancel={onCancel}
style={style}
/>
</PayPalScriptProvider>
);
}
}
I don't see a createOrder function anywhere. You need one, and it needs to invoke actions.order.create() with a JSON object that uses your total to set the amount.
See examples in the react-paypal-js storybook.
I have a simple React component and inside of it I am fetching data from a remote API, and I want to console.log it in useEffect. I am trying to do it but nothing doesn't get logged into the console, why? What am I missing here? Here is the component:
import React, { useState, useEffect } from 'react';
import { useLocalization } from '#progress/kendo-react-intl';
import { Card, CardHeader, Avatar, CardTitle, CardSubtitle } from '#progress/kendo-react-layout';
import { guid } from '#progress/kendo-react-common';
import { Scheduler } from './../components/Scheduler';
import { employees } from './../resources/employees';
import { images } from './../resources/images';
import { orders, ordersModelFields } from './../resources/orders';
import { teams } from './../resources/teams';
// const orderEmployees = employees.filter(employee => employee.jobTitle === 'Sales Representative');
// const initialFilterState = { };
// orderEmployees.forEach(employee => {
// if(employee.fullName === 'Wait Peperell') {
// initialFilterState[employee.id] = false;
// } else {
// initialFilterState[employee.id] = true;
// }
// });
const Planning = () => {
const localizationService = useLocalization();
const [filterState, setFilterState] = React.useState(initialFilterState);
const [data, setData] = React.useState(orders);
const [fetchedData, setFetchedData] = React.useState(null);
useEffect(() => {
fetch("https://mocki.io/v1/29b83c0b-1a55-430d-a173-92b3632e04aa")
.then(response => response.json())
// 4. Setting *dogImage* to the image url that we received from the response above
.then(data => setFetchedData(data))
console.log(fetchedData)
},[])
// console.log(fetchedData)
const onDataChange = React.useCallback(
({ created, updated, deleted }) => {
setData(old => old
// Filter the deleted items
.filter((item) => deleted.find(current => current[ordersModelFields.id] === item[ordersModelFields.id]) === undefined)
// Find and replace the updated items
.map((item) => updated.find(current => current[ordersModelFields.id] === item[ordersModelFields.id]) || item)
// Add the newly created items and assign an `id`.
.concat(created.map((item) => Object.assign({}, item, { [ordersModelFields.id]: guid() }))))
},
[]
);
const onEmployeeClick = React.useCallback(
(employeeId) => {
setFilterState({
...filterState,
[employeeId]: !filterState[employeeId]
});
},
[filterState, setFilterState]
);
return (
<div id="Planning" className="planning-page main-content">
<div className="card-container grid">
<h3 className="card-title">{localizationService.toLanguageString('custom.teamCalendar')}</h3>
{
orderEmployees.map(employee => {
return (
<div
key={employee.id}
onClick={() => onEmployeeClick(employee.id)}
style={!filterState[employee.id] ? {opacity: .5} : {}}
>
<Card style={{ borderWidth: 0, cursor: 'pointer'}}>
<CardHeader className="k-hbox" >
<Avatar type='image' shape='circle' size={'large'} style={{
borderWidth: 2,
borderColor: teams.find(({teamID}) => teamID === employee.teamId).teamColor,
}}>
<div className="k-avatar-image" style={{
backgroundImage: images[employee.imgId + employee.gender],
backgroundSize: 'cover',
backgroundPosition: 'center center',
}}
/>
</Avatar>
<div>
<CardTitle style={{color: teams.find(({teamID}) => teamID === employee.teamId).teamColor}}>{employee.fullName}</CardTitle>
<CardSubtitle>{employee.jobTitle}</CardSubtitle>
</div>
</CardHeader>
</Card>
</div>
);
})
}
<div className="card-component" >
<Scheduler
data={data.filter(event => filterState[event.employeeID])}
onDataChange={onDataChange}
modelFields={ordersModelFields}
resources={[
{
name: 'Teams',
data: teams,
field: 'teamID',
valueField: 'teamID',
textField: 'teamName',
colorField: 'teamColor'
}
]}
/>
</div>
</div>
</div>
);
}
export default Planning;
I also tried to place the console.log outside of useEffect but still, nothing gets console.logged.
You need to look how useEffect work, setFetchedData is async.
Create another useEffect only for console.log.
useEffect(() => {
console.log(fetchedData);
},[fetchedData]); // Update at the first render + when fetchedData state change.
You can do it like this
useEffect(() => {
fetch("https://mocki.io/v1/29b83c0b-1a55-430d-a173-92b3632e04aa")
.then((response) => response.json())
// 4. Setting *dogImage* to the image url that we received from the response above
.then((data) => {
setFetchedData(data);
console.log(data);
});
}, []);
or juste create another useEffect that listens to fetchedData change, like this
useEffect(() => {
console.log(fetchedData);
}, [fetchedData]);
I am trying to implement a dynamic dropdown menu. Clicking on the add button will show a dropdown menu that allow users to select an item, and each dropdown menu has the same list of options. I have the dropdown options store in an array, and clicking the add button will increment another array of options to the array
The issues I am having now is that, clicking the remove button doesn’t reflect what I have removed on the UI. For example, if I remove the first dropdown, it reflects that the second one is deleted.
import React, { useState } from "react";
const disciplines_fake_data = [
{ name: "discipline1", id: 0 },
{ name: "discipline2", id: 1 },
{ name: "discipline3", id: 2 },
{ name: "discipline4", id: 3 },
{ name: "discipline5", id: 4 },
{ name: "discipline6", id: 5 },
{ name: "discipline7", id: 6 },
{ name: "discipline8", id: 7 }
];
export default function Discipline({
registration,
handleRemoveDisciplineClick,
handleSelectDisciplineClick
// handleInputChange,
}) {
const [disciplinesDropdowns, setDisciplinesDropdowns] = useState([]);
const handleAddDisciplineClick = () => {
setDisciplinesDropdowns((prev) => [...prev, disciplines_fake_data]);
};
const handleRemoveDropdownClick = (index) => {
const newDisciplinesDropdowns = [...disciplinesDropdowns];
newDisciplinesDropdowns.splice(index, 1);
setDisciplinesDropdowns([...newDisciplinesDropdowns]);
handleRemoveDisciplineClick(`otherDisciplines_${index + 1}`);
};
return (
<div>
<div>
{disciplinesDropdowns.length > 0 &&
disciplinesDropdowns.map((disciplines, index) => (
<div style={{ marginTop: "10px" }} key={index}>
<article>
<label htmlFor={`otherDisciplines_${index + 1}`}>
Discipline {index + 1}
</label>
<button
onClick={(e) => {
e.preventDefault();
handleRemoveDropdownClick(index);
}}
>
REMOVE
</button>
</article>
<select
defaultValue="choose from all disciplines"
name={`otherDisciplines_${index + 1}`}
onChange={handleSelectDisciplineClick}
// onChange={handleInputChange}
>
<option disabled value="choose from all disciplines">
-choose from all disciplines-
</option>
{disciplines.map((discipline) => (
<option key={discipline.id} value={discipline.name}>
{discipline.name}
</option>
))}
</select>
</div>
))}
<div style={{ marginTop: "20px" }}>
<button
onClick={(e) => {
e.preventDefault();
handleAddDisciplineClick();
}}
>
<span> add another discipline</span>
</button>
</div>
</div>
</div>
);
}
import React, { useState, useReducer, useEffect } from "react";
import _ from "lodash";
import Discipline from "./Discipline";
const initialState = {
otherDisciplines: []
};
const FORM_ACTION = {
SELECT_DISCIPLINES: "select more disciplines",
REMOVE_DISCIPLINES: "remove disciplines"
};
function registrationReducer(state, action) {
switch (action.type) {
case FORM_ACTION.SELECT_DISCIPLINES:
const name = action.payload.name;
const value = action.payload.value;
const newDisciplines = [
...state.otherDisciplines,
{
[name]: value
}
];
newDisciplines.map((discipline) => {
if (discipline[name]) {
discipline[name] = value;
}
});
return {
...state,
otherDisciplines: _.uniqWith(newDisciplines, _.isEqual)
};
case FORM_ACTION.REMOVE_DISCIPLINES:
return {
...state,
otherDisciplines: state.otherDisciplines.filter(
(discipline) => Object.keys(discipline)[0] !== action.payload
)
};
default:
return { ...state, [action.input]: action.value };
}
}
export default function App() {
const [registration, dispatch] = useReducer(
registrationReducer,
initialState
);
console.log(registration);
const handleInputChange = ({ target }) => {
const { name, value } = target;
const action = {
input: name,
value: value
};
dispatch(action);
};
return (
<form
// onSubmit={handleFormSubmit}
>
<div>
<Discipline
registration={registration}
handleInputChange={handleInputChange}
handleSelectDisciplineClick={(e) => {
const { name, value } = e.target;
dispatch({
type: FORM_ACTION.SELECT_DISCIPLINES,
payload: { name, value }
});
}}
handleRemoveDisciplineClick={(discipline) => {
dispatch({
type: FORM_ACTION.REMOVE_DISCIPLINES,
payload: discipline
});
}}
/>
);
</div>
</form>
);
}
Using the list index as an identifier for the element is not recommended.
Instead of list (disciplinesDropdowns) you can make use of dictionary object to store dropdowns with unique identifiers and pass those unique identifiers to "handleRemoveDropdownClick".
Can have a function, that generates random and unique key before adding dropdowns to "disciplinesDropdowns".
In my React-hooks I am unable to limit my selections of items to 2, below code is not validating at the moment. Would like to display a validation message "Maximum items has been selected". What could be the reason ?
https://codesandbox.io/s/kind-brown-n8ki4?file=/src/App.js:463-492
import React, { useRef, useEffect, useState } from "react";
import { Link, useHistory } from "react-router-dom";
import Multiselect from "multiselect-react-dropdown";
const options = [
{ key: "Apple", id: 1 },
{ key: "Bags", id: 2 },
{ key: "Coat", id: 3 },
{ key: "Drum", id: 4 }
];
const App = () => {
const maxOptions = 2;
const [selectedOption, setSelectedOption] = useState([]);
const handleTypeSelect = (e) => {
setSelectedOption(e);
};
const onNominate = () => {
alert("hello");
// ...
};
return (
<div className="App">
<div className="navbar-nav">
<div className="leftNavItem"></div>
</div>
<h1>Maximum 2 selections</h1>
<div className="nomineeSelectBox">
<Multiselect
onChange={handleTypeSelect}
options={selectedOption.length === maxOptions ? [] : options}
displayValue="key"
showCheckbox={true}
noOptionsMessage={() => {
return selectedOption.length === maxOptions
? "You have reached the max options value"
: "No options available";
}}
/>
</div>
<div className="nominateButton">
<input type="button" value="Next" onClick={onNominate} />
</div>
</div>
);
};
export default App;
You have some problems in your code to Multiselect works properly:
You need onSelect event of the multiselect-react-dropdown component not onChange.
selectedOption.length === maxOptions ? [] should change to selectedOption.length + 1 === maxOptions ? []
For showing the correct message for the no options selected, you need to change noOptionsMessage to emptyRecordMsg
So, final result should be:
<Multiselect
onSelect={handleTypeSelect}
onRemove={handleTypeRemove}
// onChange={handleTypeSelect}
options={selectedOption.length + 1 === maxOptions ? [] : options}
displayValue="key"
showCheckbox={true}
emptyRecordMsg={"You have reached the max options value"}
/>
In addition you should change the handleTypeSelect to :
const handleTypeSelect = (e) => {
const copy = [...selectedOption];
copy.push(e);
setSelectedOption(copy);
};
Also you need to handle the multiselect when a item removes with onRemove method:
const handleTypeRemove = (e) => {
const copy = [...selectedOption];
let index = copy.indexOf(e);
copy.splice(index, 1);
setSelectedOption(copy);
};
You are always setting only one option. So you have always one option selected. What you need to do is
const handleTypeSelect = (e) => {
setSelectedOption(prevArr => [...prevArr, e]); };
Do it like this so you can pull the option selected before.
how I can update price value when update quantity value automatically ??
page design
interface ui
print values on the console:
print values on the console:
This sentence needs to be modified
{quantity[initQ] == 1 ? data.price : initP[initQ]}
i use setState to save multiple values
export default function Contaner({ setPressed, getPressed }) {
const [products, setProducts] = useState([]);
const [layout, setLayout] = useState('list');
let initQ = 1;
const [initP,setInitP] = useState({ [initQ]: 1 }) ;
const [quantity, setQuantity] = useState({ [initQ]: 1 });
function checkQuantity(e, data) {
if (e.value <= data.quantity) {
initQ = data.name;
setQuantity({ ...quantity, [data.name]: e.value});
setInitP( { ...quantity, [data.name]: data.price * e.value});
console.log(initP );
setCart(current => [...current, data.name]);
}
else {
showError();
}
}
const renderListItem = (data) => {
return (
<div style={{ display: "flex" }}>
<button className="button_color" onClick={() => removeItem(data)}>
<i className="pi pi-trash"></i>
</button>
<h6>{quantity[initQ] == 1 ? data.price : initP[initQ] }</h6>
<InputNumber id="stacked" showButtons min={1} value={quantity[initQ]}
onValueChange={(e) => checkQuantity(e, data)} />
<InputText disabled={true} value={"₪ " + data.price} />
<h6>{data.name}</h6>
</div>
);
}
const itemTemplate = (product, layout) => {
if (!product) {
return <></>;
}
if (layout === 'list') {
return renderListItem(product);
}
}
return(
<DataView value={products} layout={layout} itemTemplate={itemTemplate} rows={1} />
);
}