I have a page with an order fetch, one can use a select to sort by furthest date or nearest date. On the select everything works, the problem comes from the input where I can enter a command number for the search, it works except that the state does not change on the page when retrieving the state, and if the number command does not exist I am unable to change the state and retrieve the error message. If anyone can look at my code that would be cool. Thanks
part redux
const initialState = {
data:[{
dateCommande: "",
dateDuJour: "",
heureDuJourCommande: "",
horaire: "",
patisseriesList: "",
pays: "",
phone: "",
prixTotal: "",
ville: ""
}],
message:""
}
export default function CommandManagementAdmin(state = initialState,action){
const {type, payload} = action;
switch (type) {
case ActionTypes.GET_ALL_COMMAND_ADMIN:
return {state : payload.data}
case ActionTypes.GET_ALL_COMMAND_ID_CLIENT_ADMIN:
return payload;
case ActionTypes.GET_COMMAND_BY_NUMBER_COMMAND_ADMIN:
return {state: payload};
case ActionTypes.RESULT_COMMAND_NULL_MESSAGE:
return {...state,state:payload[0].message} ;
case ActionTypes.DELETE_COMMAND_BY_ID_ADMIN:
return state === Object.values(state).filter((command) => command.id_commande !== payload)
case ActionTypes.ERROR_GET_ALL_COMMAND_BY_ID_CLIENT_ADMIN:
return { ...state, payload };
default:
return state;
}
}
Service get
export const getCommandByNumberCommandAdminService = (dispatch, numberCommand) =>{
axios.get(BASE_URL + Url_api.API_URL_GET_COMMAND_BY_NUMERO_COMMAND + numberCommand, { headers: ConfigHeaderAdmin()})
.then((response)=>{
const ifCommand = response.data.result
if (ifCommand.length > 0) {
const dataCommand = response.data.result[0]
dispatch(ActionTypes.actionGetCommandByNumberCommandAdmin(dataCommand))
}else{
const message = response.data.message
dispatch(ActionTypes.actionCommandNullMessageAdmin(message))
}
})
.catch((error)=>{
console.log({error: error.message})
})
}
view
const AllCommandComponent = () =>{
const dispatch = useDispatch()
const ifIsCommand = useSelector(state=> state?.reducerCommandAdmin?.state)
const [listCommand, setListCommand ] = useState([])
const [ filterDate, setFilterDate ] = useState("all");
const [ commandByNumber, setCommandByNumber ] = useState("");
useEffect(()=>{
setListCommand(ifIsCommand)
getAllCommandAllClientsAdminService(dispatch)
},[ listCommand, filterDate])
const handleChange = (e) =>{
setFilterDate(e.target.value)
}
const ResultChoiceDateCommand = () =>{
if (filterDate === "oldDay") {
const sortListCommandOld = listCommand?.sort((a, b) => new Date(a.dateDuJour) - new Date(b.dateDuJour))
return setListCommand(sortListCommandOld)
}
if (filterDate === "recentDate") {
const sortListCommandOld = listCommand?.sort((a, b) => new Date(b.dateDuJour) - new Date(a.dateDuJour))
return setListCommand(sortListCommandOld)
}
}
const ListAllCommand = () => {
return listCommand?.map((command, index) => {
return (
<Commands command={command} index={index} />
)
})
}
return(
<div className="esai">
<select className="command_tri_select" onChange={(e)=> handleChange(e)} defaultValue={"all"}>
<option value="all">Toutes les commandes</option>
<option value="oldDay">Commande la plus ancienne</option>
<option value="recentDate">Commande la plus récente</option>
</select>
{ListAllCommand}
<ResultChoiceDateCommand />
</div>
)
}
Related
I have these codes trying to implement a crypto return calculator that takes in a coin ID, a buy and sell date and the coin amount.
My issue is that the API is being fetched after every input and by the time I reach the sell date, my API limit has been reached.
Is there a way to prevent this from happening?
Here are the codes below.
export default function App() {
const [trade, setTrade] = useState({
sellData: {},
buyData: {},
gains: 0
});
const coinList = [
{ id: 0, name: "bitcoin" },
{ id: 1, name: "ethereum" },
{ id: 2, name: "tezos" },
{ id: 3, name: "cardano" }
];
const [buyDate, setBuyDate] = useState("");
const [sellDate, setSellDate] = useState("");
const [volume, setVolume] = useState(0);
const [coin, setCoin] = useState("");
const coingeckoUrl = (coin, date) => {
return `https://api.coingecko.com/api/v3/coins/${coin}/history?date=${date}&localization=false`;
};
const calcGains = () => {
setTrade({
...trade,
gains:
(trade.sellData.market_data?.current_price.usd -
trade.buyData.market_data?.current_price.usd) *
volume
});
};
const coingeckoFetch = async (buy, coin, date) => {
fetch(coingeckoUrl(coin, date)).then((response) =>
response.json().then((jsonData) => {
if (buy) {
setTrade({ ...trade, buyData: jsonData });
} else {
setTrade({ ...trade, sellData: jsonData });
}
})
);
};
const handleBuyChange = (e) => {
let val = e.target.value;
setBuyDate(val);
coingeckoFetch(true, coin, val);
};
const handleSellChange = (e) => {
let val = e.target.value;
setSellDate(val);
coingeckoFetch(false, coin, val);
};
const handleCoinChange = (e) => {
let val = e.target.value;
setCoin(val);
coingeckoFetch(null, coin, val);
};
return (
<div className="App">
<select defaultValue={coin} onChange={(val) => handleCoinChange(val)}>
{coinList.map((item) => (
<option key={item.id}>{item.name}</option>
))}
</select>
<input
placeholder="Insert Buy Date"
defaultValue={buyDate}
onChange={(val) => handleBuyChange(val)}
/>
<h3> {trade.buyData.market_data?.current_price.usd} USD</h3>
<input
placeholder="Insert Sell Date"
defaultValue={sellDate}
onChange={(val) => handleSellChange(val)}
/>
<h3> {trade.sellData.market_data?.current_price.usd} USD</h3>
<input
placeholder="Insert Amount of Tokens"
value={volume}
onChange={(e) => setVolume(e.target.value)}
/>
<h3>{volume}</h3>
<button onClick={calcGains}> Calculate </button>
<h3>{trade.gains} USD</h3>
</div>
);
}
Thank you for your help.
Summary
if you are just don't want to request too many times.
Maybe you can add a state like
const [fetchNow, setFetchNow] = useState(false);
And in your handleChange() functions, do not carry out the coingeckoFetch(). But execute the setFetchNow()
like this
const handleBuyChange = (e) => {
let val = e.target.value;
setBuyDate(val);
// or your buy condition
if (val) {
setFetchNow(true)
}
};
const handleSellChange = (e) => {
let val = e.target.value;
setSellDate(val);
// or your sell condition
if (val) {
setFetchNow(true)
}
};
const handleCoinChange = (e) => {
let val = e.target.value;
setCoin(val);
// or your coin condition
if (val) {
setFetchNow(true)
}
};
Then add a useEffect(), and use a conditional if statement to determine that whether the coingeckoFetch() be carry out or not
useEffect(()=>{
if (fetchNow) {
coingeckoFetch(true, coin, val);
}
}, [fetchNow]);
Other
Or just simply add conditional if statement in your coingeckoFetch()
like
const coingeckoFetch = async (buy, coin, date) => {
// conditional if statement
if (buy !== "MyCondition") {
return;
}
else if (coin !== "MyCondition") {
return;
}
else if (date !== "MyCondition") {
return;
}
fetch(coingeckoUrl(coin, date)).then((response) =>
response.json().then((jsonData) => {
if (buy) {
setTrade({ ...trade, buyData: jsonData });
} else {
setTrade({ ...trade, sellData: jsonData });
}
})
);
};
So this is my app which i have created in react and store data in firestore, i have a form in which ingredients is an array, i can dynamically add the input feilds and when i submit the form it gets submiited and the data gets stored in firebase. My problem is when i click the add feild button instead of one feild two feilds are simultaneously created and i am unable to understand how to do that so if anyone can explain what to do thanks .
code :
function App() {
const [recipes, setRecipes] = useState([])
const [form, setForm] = useState({
ingredients: [],
})
const [popupActive, setPopupActive] = useState(false)
const recipesCollectionRef = collection(db, "recipes")
useEffect(() => {
onSnapshot(recipesCollectionRef, snapshot => {
setRecipes(snapshot.docs.map(doc => {
return {
id: doc.id,
viewing: false,
...doc.data()
}
}))
})
}, [])
const handleView = id => {
const recipesClone = [...recipes]
recipesClone.forEach(recipe => {
if (recipe.id === id) {
recipe.viewing = !recipe.viewing
} else {
recipe.viewing = false
}
})
setRecipes(recipesClone)
}
const handleSubmit = e => {
e.preventDefault()
if (
!form.ingredients ||
) {
alert("Please fill out all fields")
return
}
addDoc(recipesCollectionRef, form)
setForm({
ingredients: [],
})
setPopupActive(false)
}
const handleIngredient = (e, i) => {
const ingredientsClone = [...form.ingredients]
ingredientsClone[i] = e.target.value
setForm({
...form,
ingredients: ingredientsClone
})
}
const handleIngredientCount = () => {
setForm({
...form,
ingredients: [...form.ingredients, ""]
})
{ recipe.viewing && <div>
<h4>Ingredients</h4>
<ul>
{ recipe.ingredients.map((ingredient, i) => (
<li key={i}>{ ingredient }</li>
))}
</ul>
As far as I have understood. Just do like below,
const handleIngredientCount = () => {
setForm({
...form,
ingredients: [...form.ingredients, "", ""],
})
}
You will be created with two input fields simultaneously instead of one when you click the add ingredient button.
I'm trying to pass data from useState([]) to the variables for filtering products. It works, but on very strange way.
When I click on a category checkbox, it is not checked, but the products are filtered, when I click on another category, again checkbox didn't checked, but already two values in the array useState([1,2]), and when I click again, the checkbox is checked, but is removed from the array useState([]).
const GET_PRODUCTS = gql`
query GetProducts($filterByCategory: [ID]) {
products(filters: {category: {id:{in: $filterByCategory}}}) {
....
}
}
`
const VacanciesPage = () => {
const [selectCategories, setSelectedCategories] = useState([]);
const getSetSelectedCategories = (category) => {
console.log(category);
if(selectCategories.includes(category)){
setSelectedCategories(selectCategories.filter(item => item != category));
return;
}
setSelectedCategories([...selectCategories, category]);
}
useEffect(() => {
console.log(selectCategories);
},[selectCategories]);
const { loading, error, data } = useQuery(GET_PRODUCTS, {
variables: { "filterByCategory": selectCategories},
});
if (loading) return null;
if (error) return `Error! ${error}`;
const { products, categories } = data;
return(
{categories.data.map(category => (
<label key={category.id} className="inline-flex items-center mt-3 mr-3">
<input type="checkbox" className="w-5 h-5" value={category.id} onChange={e => getSetSelectedCategories(+e.target.value)}/><span className="ml-2 text-gray-700">{category.attributes.name}</span>
</label>
))}
);
}
I completely rewrote the code, moved the variables to a separate function and everything finally worked.
const [selectedCategories, setSelectedCategories] = useState([]);
const [searchStatus, setSearchStatus] = useState(false);
useEffect(() => {
console.log(selectedCategories);
},[selectedCategories]);
const { loading, error, data } = useQuery(GET_PRODUCTS);
const { loading: loadingCategories, error: errorCategories, data: categories } = useQuery(GET_CATEGORIES);
const [ getFilteredProducts,
{ loading: filterLoading, error: filterError, data: filteredProducts }
] = useLazyQuery(FILTER_PRODUCTS_QUERY);
if (loading || loadingCategories || filterLoading) return "Loading";
if (error || errorCategories || filterError) return `Error! ${error}`;
const { products: allProducts } = data;
const { categories: allCategories } = categories;
const clearSearch = () => {
setSelectedCategories([]);
setSearchStatus(false);
};
const searchProducts = () => {
let filter = {};
setSearchStatus(true);
if (Object.keys(filter).length === 0) {
if (!selectedCategories) {
setSearchStatus(false);
return;
}
}
getFilteredProducts({
variables: {
filterByCategories: selectedCategories
? selectedCategories
: allCategories.data.map((category) => category.id),
},
});
};
const dataset = searchStatus && filteredProducts ? filteredProducts?.products : allProducts;
I'm new to React and I created a small admin panel where you can add, edit, remove products. I would like to display 3 products from API when someone opens the app the first time and don't have edited products yet, but this data only shows if I manually refresh the page. I only want to display that if edited product is false, but initially I set edited products to false yet somehow it's not displaying, though I see the data as well as edited is set to false in the console.
Demo
https://react-storeadminpanel.herokuapp.com/
Here is the related code:
const Products = () => {
const {products, setProducts, setAllProducts, allProducts, editedItems, setEditedItems} = useProduct();
useEffect(() => {
async function fetchProducts() {
const res = await axios.get('https://a.nacapi.com/LimeGreen/products/').catch(err => console.log(err));
if(res) {
setProducts(res.data)
setEditedItems(false);
if(allProducts.length === 0 && editedItems === false) setAllProducts(products);
if(allProducts.length === 0 && editedItems === true) setAllProducts(allProducts);
if(allProducts.length > 0) setAllProducts([...allProducts]);
}
return res;
}
fetchProducts();
}, []);
return (
<Wrapper classname="wrapper">
<h1>All Products</h1>
<Cards>
{!!allProducts.length && (
allProducts.map(product => (
<ProductCard name={product.name} description={product.Description} price={product.Price} discount={product.Discount} key={product.uuid}/>
))
)}
</Cards>
</Wrapper>
)
}
The context, where I use LocalStorage
export const ProductContext = React.createContext();
export function useProduct() {
return useContext(ProductContext);
}
export function ProductProvider({children}) {
const [products, setProducts] = useLocalStorage('Api Data', []);
const [addedProduct, setAddedProduct] = useLocalStorage('Added Item', []);
const [allProducts, setAllProducts] = useLocalStorage('All Products', []);
const [editedItems, setEditedItems ] = useLocalStorage('Edited', false);
const [isAdded, setIsAdded] = useState(false);
const value = {
products,
setProducts,
addedProduct,
setAddedProduct,
allProducts,
setAllProducts,
editedItems,
setEditedItems,
isAdded,
setIsAdded,
}
return (
<ProductContext.Provider value={value}>
{children}
</ProductContext.Provider>
)
}
And Code where I set edit products to true
const ProductEdit = () => {
const {allProducts, setAllProducts, setEditedItems} = useProduct();
const [editProductId, setEditProductId] = useState(null);
const [editForm, setEditForm] = useState({
name: "",
Description: "",
Price: "",
Discount: "",
})
const saveEditHandler = (e) => {
e.preventDefault();
const fieldName = e.target.getAttribute("name");
const fieldValue = e.target.value;
const newForm = {...editForm};
newForm[fieldName] = fieldValue;
setEditForm(newForm);
}
const editHandler = (e, product) => {
e.preventDefault();
setEditProductId(product.uuid);
const formValues = {
name: product.Name,
Description: product.Description,
Price: product.Price,
Discount: product.Discount
}
setEditForm(formValues);
}
const submitEditsHandler = (e) => {
e.preventDefault();
const editedProduct = {
name: editForm.Name,
Description: editForm.Description,
Price: editForm.Price,
Discount: editForm.Discount,
uuid: editProductId
}
const newProducts = [...allProducts];
const index = allProducts.findIndex((product) => product.uuid === editProductId);
newProducts[index] = editedProduct;
setAllProducts(newProducts);
setEditedItems(true);
setEditProductId(null);
}
const cancelHandler = () => {
setEditProductId(null);
}
const deleteHandler = (productId) => {
const newProducts = [...allProducts];
const index = allProducts.findIndex((product) => product.uuid === productId);
newProducts.splice(index, 1);
setAllProducts(newProducts);
setEditedItems(true);
};
I'm trying to filter users with input search inside the function searchByName.
I manage to get the right result in copyUsersvariable but unfortunately it does not reflect the change inside the state.
Forgot to mention, using bare React-App with hooks and typescript.
For example, i write 'p' in the input and recieve the right filtered array in copyUsers variable but then i push it into the state it does not update.
Attaching screenshot for understanding the situation better:
what i have tried instead setFilteredUsers(copyUsers):
setFilteredUsers(() => [...filteredUsers, copyUsers]);
setFilteredUsers(() => copyUsers);
main component:
const { value } = useSelector(({ test }: any) => test);
const [users, setUsers] = useState<Users>([]);
const [filteredUsers, setFilteredUsers] = useState<Users>([]);
const [searchNameValue, setSearchNameValue] = useState<string>("");
const [selectedUser, setSelectedUser] = useState<User>();
const [searchOrderBy, setSearchOrderBy] = useState<string>("");
const dispatch = useDispatch();
useEffect(() => {
const get = async () => {
const response = await ApiTest.testGet();
setUsers(response);
setSearchOrderBy("desc");
};
get();
}, []);
useEffect(() => {
searchByName();
setNewOrder();
}, [searchOrderBy]);
useEffect(() => {
console.log('search value changed!', searchNameValue);
searchByName();
setNewOrder()
}, [searchNameValue]);
const setNewOrder = () => {
if (users.length) {
let copyUsers = JSON.parse(
JSON.stringify(filteredUsers.length ? filteredUsers : users)
);
switch (searchOrderBy) {
case "desc":
copyUsers.sort((a: any, b: any) => {
if (a.id > b.id) {
return -1;
}
if (b.id > a.id) {
return 1;
}
return 0;
});
break;
case "asc":
copyUsers.sort((a: any, b: any) => {
if (b.id > a.id) {
return -1;
}
if (a.id > b.id) {
return 1;
}
return 0;
});
break;
default:
break;
}
filteredUsers.length ? setFilteredUsers(copyUsers) : setUsers(copyUsers);
}
};
const searchByName = () => {
if (searchNameValue) {
let copyUsers = JSON.parse(JSON.stringify(users));
copyUsers = copyUsers.filter((user: User) => {
return user.name
.toLocaleLowerCase()
.includes(searchNameValue.toLocaleLowerCase());
});
console.log("copyUsers =", copyUsers);
setFilteredUsers(copyUsers);
console.log("filteredUsers =", filteredUsers);
}
};
const UserCards =
!!users.length &&
(searchNameValue ? filteredUsers : users).map(user => {
return (
<UserCard
selectedUser={selectedUser}
setSelectedUser={(user: User) => setSelectedUser(user)}
user={user}
/>
);
});
return (
<div>
<FilterBar
searchOrderBy={searchOrderBy}
searchSetOrderBy={(value: string) => setSearchOrderBy(value)}
setSearchNameValue={(value: string) => setSearchNameValue(value)}
searchNameValue={searchNameValue}
/>
<div style={{ display: "flex", flexFlow: "wrap" }}>{UserCards}</div>
</div>
);