SweetAlert2-react Cancel Button does not work - reactjs

I'm trying to confirm a user delete using Sweetalert2 in react, but when I use the 'Cancel' button, it still sends the form to delete the user, as if I've pressed 'Confirm'. Here's my code
export default function Users() {
const [users, setUsers] = useState([])
const [isModalOpen, setModal] = useState(false)
const [hover, setHover] = useState('')
const [userModal, setuserModal] = useState('')
const [show, setShow] = useState(false)
const [userDelete, setUserDelete] = useState('')
useEffect(() => {
fetch(`${OC_API}/users`)
.then(res => res.json())
.then(res => {
setUsers(res)
console.log(res)
})
.catch(e => console.log(`Hubo un error Cod. 200 ${e}`))
},[])
function toggleModal(user) {
setuserModal(user)
setModal(!isModalOpen)
}
function handleDeleteUser(user) {
fetch(`${OC_API}/userdelete`, {
method: 'POST',
headers: {'Content-Type':'application/json'},
body: JSON.stringify({"user_id": user._id})
}).then(res => {
if (res.ok){
alert('¡Usuario eliminado!')
} else {
alert('¡Hubo un error! Cod. 201')
}
}).then(() => {
fetch(`${OC_API}/users`)
.then(res => res.json(),
error => {alert(`Error de conexión ${error.message}`); throw error;})
.then(data => {
console.log(data)
setUsers(data)
})
.catch(e => console.log(`Hubo un error Cod. 202 ${e}`))
})
}
if (users == undefined || users == [] || users == null ){
return (
<Loading />
)
} else {
return(
<div className="container">
<motion.div className="row justify-content-center"
initial={{ opacity: 0 }}
animate={{ opacity: 1}}
transition={{ duration: 1}}
style={{'paddingTop':'3em'}}
>
<div className="col col-md-12 text-right" >
<AddUserButton />
</div>
<div className="col col-md-12 text-center" >
<ParagraphStyle>
<div className="card" >
<div className="card-header text-left">
Administrar Usuarios
</div>
<div className="card-body">
<div className="table-responsive">
<AdminTableStyle>
<table className="table">
<thead >
<tr>
<th scope="col">Nombre</th>
<th scope="col">RUT</th>
<th scope="col">Correo</th>
<th scope="col">Rol</th>
<th scope="col">Acciones</th>
</tr>
</thead>
<tbody>
{users.map(user => (
<Fragment key={user.id}>
<SweetAlert
show={show}
icon={'warning'}
title="Eliminar Usuario"
text={`¿Desea borrar a usuario ${userDelete.name}?`}
showCancelButton={true}
confirmButtonColor={'#3085d6'}
cancelButtonColor={'#d33'}
cancelButtonText={'Cancelar'}
confirmButtonText={'Confirmar'}
onCancel={ () => {setShow(false)
return }}
onConfirm={() => {
handleDeleteUser(userDelete)
setShow(false)
}}
/>
<tr onMouseOver={() => setHover(user._id)} onMouseLeave={() => setHover('')}>
<td style={{'textAlign': 'left'}}>{user.name}</td>
<td>{user.rut}</td>
<td>{user.email}</td>
<td>{user.role}</td>
<td>
<span style={{'marginRight': '5px'}}>
{
hover==user._id?
<a href="#" onClick={() => toggleModal(user)}>
<FontAwesomeIcon
icon='edit'
/>
</a>
:
''
}
</span>
<span>
{
hover==user._id?
<a href="#" onClick={() => {
setUserDelete(user)
setShow(true)
}}
>
<FontAwesomeIcon
icon='trash'
/>
</a>
:
''
}
</span>
</td>
</tr>
</Fragment>
))}
</tbody>
</table>
</AdminTableStyle>
</div>
</div>
</div>
</ParagraphStyle>
</div>
</motion.div>
<UserEdit
setuserModal={setuserModal}
isModalOpen={isModalOpen}
userModal={userModal}
toggleModal={toggleModal}
/>
</div>
)
}
}
I tried adding an onCancel option in the Sweetalert component and set the Show state to false, but it continues executing the handleDeleteUser function
Any suggestions?

Related

Axios Get request sometimes doesn't go through

recently i have been working on my react project. my code is working fine most of the time.
import React, { useState, useEffect } from "react";
import Axios from "axios";
import { Navigate, Link } from "react-router-dom";
import API from "../backend";
import { isAutheticated } from "../auth";
import ReactPaginate from "react-paginate";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import Spinner from "react-bootstrap/Spinner";
const Body = () => {
// set values (got from api)
const [values, setValues] = useState({
bookingId: "",
email: "",
status: "",
error: "",
success: "",
});
// set api response as array, so that i can loop through using map
const [data, setData] = useState([]);
// if some click submit
const [didsubmit, setDidSumbit] = useState(false);
// set and get default booking status
const [myValue, setMyValue] = useState("");
// if something changes
const [didChange, setDidChange] = useState(false);
// for pagination
const [pageChange, setPageChange] = useState(false);
// total pages in pagination
const [allTotalPages, setAllTotalPages] = useState("");
// default page number (used in api get response)
const [num, setNum] = useState(1);
// used for searching
const [details, setDetails] = useState({
email: false,
});
// search state
const [search, setSearch] = useState(false);
// if site is loading
const [loading, setLoading] = useState(true);
// destructuring token from localstorage
const { token } = isAutheticated();
// dataObject for api call
const tokenKey = {
headers: {
authorization: `Bearer ${token}`,
},
};
// api call
const axiosGetCall = async () => {
try {
let res;
if (search === true) {
res = await Axios.get(
`${API}/allorders?page=${num}&useremail=${details.email}`,
tokenKey
);
setSearch(false);
} else {
res = await Axios.get(`${API}/allorders?page=${num}`, tokenKey);
}
setValues({ ...values, success: "", error: "" });
const data = await res.data.bookings;
const totalItems = await res.data.Total;
setData(data);
const totalPages = Math.ceil(totalItems / 5);
setAllTotalPages(totalPages);
setPageChange(false);
setLoading(false);
} catch (error) {
setSearch(false);
setLoading(false);
setValues({ ...values, success: "", error: "" });
}
};
//GET API NORMAL FOR FIRST LOAD
useEffect(() => {
axiosGetCall();
// eslint-disable-next-line
}, []);
//GET API IF DID CHANGE
useEffect(() => {
if (didChange === true) {
// if there is something in details do this
if (details.email === false) {
axiosGetCall();
} else {
setSearch(true);
axiosGetCall();
}
}
// eslint-disable-next-line
}, [didChange]);
//GET API IF DID Search
useEffect(() => {
if (search === true) {
axiosGetCall();
}
// eslint-disable-next-line
}, [search]);
//GET API WHEN PAGE CHANGES
useEffect(() => {
if (pageChange === true) {
setValues({ ...values, success: "", error: "" });
// if there is something in details do this
if (details.email === false) {
axiosGetCall();
} else {
setSearch(true);
axiosGetCall();
}
}
// eslint-disable-next-line
}, [pageChange]);
const onSubmit = (event, id, mail, val) => {
event.preventDefault();
setValues({
...values,
bookingId: id,
email: mail,
status: val,
success: "",
error: "",
});
setMyValue(val);
setDidSumbit(true);
};
const newStatus = {
status: myValue,
id: values.bookingId,
};
// POST API
useEffect(() => {
const axiosUpdateCall = async () => {
try {
const res = await Axios.post(`${API}/changeorder`, newStatus, tokenKey);
setDidSumbit(false);
setDidChange(false);
setValues({ ...values, success: "Changed Successfully", error: "" });
} catch (error) {
setValues({
...values,
error: error.response.data.error[0],
success: "",
});
setDidChange(false);
}
};
if (didChange) {
axiosUpdateCall();
}
}, [didChange]);
// Error Toast
const errorToast = () => {
toast.error(`${values.error}`, {
position: "top-right",
autoClose: 8000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
theme: "dark",
});
};
// Sucess Toast
const successToast = () => {
toast.success(`${values.success}`, {
position: "top-right",
autoClose: true,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
theme: "dark",
});
};
// pagination stuff
const handlePageClick = async (data) => {
let currentPagex = data.selected + 1;
setNum(currentPagex);
setPageChange(true);
setLoading(true);
setValues({ ...values, success: "", error: "" });
};
// search stuff
const onSearch = (event) => {
event.preventDefault();
setSearch(true);
setLoading(true);
setValues({ ...values, success: "", error: "" });
};
// handling changes on pages
const onHandleChange = (val) => (event) => {
setDetails({ ...details, [val]: event.target.value });
setValues({ ...values, success: "", error: "" });
};
return (
<>
<ToastContainer
position="top-right"
autoClose={5000}
hideProgressBar={false}
newestOnTop={false}
closeOnClick={false}
rtl={false}
pauseOnFocusLoss
draggable
pauseOnHover
theme="dark"
/>
{values.error && errorToast()}
{values.success && successToast()}
<div style={{ display: didsubmit ? "none" : "block" }}>
<section className="section dashboard">
<div className="row justify-content-md-center">
<div className="col-lg-6">
<div className="input-group">
<input
type="search"
className="form-control rounded"
placeholder="example#gmail.com"
aria-label="Search"
aria-describedby="search-addon"
onChange={onHandleChange("email")}
/>
<button
type="button"
className="btn btn-outline-primary"
onClick={onSearch}
disabled={search}
>
{search === true ? "Loading.." : "Search"}
</button>
<a href="/main" className="btn btn-outline-primary">
Reload
</a>
</div>
</div>
</div>
</section>
</div>
<main id="main" className="main">
<section className="section dashboard ">
<div className="row justify-content-md-center">
<div className={didsubmit ? "col-lg-6" : "col-lg-12"}>
<div className="row">
{/* */}
<div className="col-12">
<div className="card recent-sales overflow-auto">
<div className="card-body">
<h3 className="card-title">
{didsubmit === true
? "Change Booking Status"
: "Recent Bookings "}
<span></span>
</h3>
{loading === true ? (
<>
{" "}
<Spinner animation="border" role="status">
<span className="visually-hidden">Loading...</span>
</Spinner>
</>
) : (
<>
<table className="table table-borderless datatable">
{didsubmit === true ? (
<></>
) : (
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">User Email</th>
<th scope="col">Customer Phone</th>
<th scope="col">Payment Recept</th>
<th scope="col">Order id</th>
<th scope="col">Package Name</th>
<th scope="col">Total Kids</th>
<th scope="col">Total Adults</th>
<th scope="col">Total Price</th>
<th scope="col">BookedFor</th>
<th scope="col">created On</th>
<th scope="col">Status</th>
</tr>
</thead>
)}
{/* */}
<tbody>
{didsubmit === true ? (
<>
<tr>
<td>
{" "}
<p>Email: {values.email}</p>
<p>Current Status: {values.status}</p>
<div className="col-3">
<select
onChange={(e) =>
setMyValue(e.target.value)
}
defaultValue={values.status}
>
<option>Pending</option>
<option>Unpaid</option>
<option>Bank</option>
<option>Bank-Paid</option>
<option>Success</option>
</select>
</div>
<div className="float-end">
<button
className="btnx btn-primary"
disabled={didChange}
onClick={() => {
setDidSumbit(false);
}}
>
Back
</button>
<button
className="btnx btn-primary"
disabled={didChange}
onClick={() => {
setDidChange(true);
}}
>
{didChange
? "Loading.."
: "Change Status"}
</button>
</div>
</td>
</tr>
</>
) : (
<>
{data.map((e, i) => (
<tr key={e._id}>
<td scope="row">
{e.tourDetails[0].username}
</td>
<td scope="row">
<p>{e.tourDetails[0].email}</p>
</td>
<td scope="row">
<p>{e.tourDetails[0].userphone}</p>
</td>
<td scope="row">
<p>{e.paymentid}</p>
</td>
<td scope="row">
<p>{e.orderId}</p>
</td>
<td>{e.tourDetails[0].name}</td>
<td>{e.Childquantity}</td>
<td>{e.Adultquantity}</td>
<td>₹{e.overAllTotal}</td>
<td>
<span className="text-primary">
{e.bookedFor}
</span>
</td>
<td>{e.createdAt.slice(0, 10)}</td>
<td>
{e.orderStatus === "Success" && (
<span className="badge bg-success">
{e.orderStatus}
</span>
)}
{e.orderStatus === "Bank" && (
<span className="badge bg-dark">
{e.orderStatus}
</span>
)}
{e.orderStatus === "Bank-Paid" && (
<span className="badge bg-secondary">
{e.orderStatus}
</span>
)}
{e.orderStatus === "Unpaid" && (
<span className="badge bg-danger">
{e.orderStatus}
</span>
)}
{e.orderStatus === "Pending" && (
<span className="badge bg-warning">
{e.orderStatus}
</span>
)}
</td>
<td>
<button
className="btnx btn-primary"
disabled={didsubmit}
onClick={(event) => {
onSubmit(
event,
e._id,
e.tourDetails[0].email,
e.orderStatus
);
}}
>
{didsubmit
? "loading.."
: "Change Status"}
</button>
</td>
</tr>
))}
</>
)}
</tbody>
{/* */}
</table>
</>
)}
</div>
</div>
</div>
</div>
</div>
{/* */}
</div>
</section>
</main>
{/* */}
<div style={{ display: didsubmit ? "none" : "block" }}>
<ReactPaginate
previousLabel={"previous"}
nextLabel={"next"}
breakLabel={"..."}
pageCount={allTotalPages}
marginPagesDisplayed={2}
pageRangeDisplayed={3}
onPageChange={handlePageClick}
containerClassName={"pagination justify-content-center"}
pageClassName={"page-item"}
pageLinkClassName={"page-link"}
previousClassName={"page-item"}
previousLinkClassName={"page-link"}
nextClassName={"page-item"}
nextLinkClassName={"page-link"}
breakClassName={"page-item"}
breakLinkClassName={"page-link"}
activeClassName={"active"}
/>
</div>
</>
);
};
export default Body;
this is the whole code, here most of the time my get response works fine. sometimes it doesn't hit the route.
sometimes Get request doesn't hit after post request
POST "http://127.0.0.1:4000/api/changeorder".
GET "http://127.0.0.1:4000/api/allorders?page=1".
I guess my Get request is loading before post request so the virtual dom isn't updating.

How to maintain state and scroll position in React

I'm trying to build a CURD operation component that GET the data from API. When a user clicks on the EDIT, it renders the component showing the details of the line item to be edited. But when the user hits the back button in the browser, the previous component with the post list re-renders and it loses the previous state and scroll position. Is there a way that I can bring the selected row to the first position if I scroll up it displays the previous data and if I scroll down it shows the next coming data?
import React, { useState, useEffect } from "react";
import axios from "axios";
import { Link } from "react-router-dom";
import "bootstrap/dist/css/bootstrap.min.css";
import { CSVLink, CSVDownload } from "react-csv";
import "./Home.css";
const Home = () => {
const [loading, setLoading] = useState(false);
const [users, setUsers] = useState([]);
const [searchTitle, setSearchTitle] = useState("");
const [prime, setPrime] = useState([]);
const [primeid, setPrimeid] = useState("");
const [category, setCategory] = useState([]);
const [categoryid, setCategoryid] = useState("");
const [subcategory, setSubcategory] = useState([]);
const [subcategoryid, setSubcategoryid] = useState("");
const usersList = users.length;
useEffect(() => {
loadUsers();
}, []);
// the below command is used to send the load data from the database
const loadUsers = async () => {
const result = await axios.get(`http://localhost:4000/api/email/`);
// setUsers(result.data);
setUsers(result.data);
// console.log(result)
};
useEffect(() => {
const getprime = async () => {
const resprime = await axios.get(
`http://localhost:4000/api/primewise${primeid}`
);
setPrime(resprime.data.reverse());
};
getprime();
}, []);
const handleprime = (event) => {
const getprimeid = event.target.value;
setPrimeid(getprimeid);
};
useEffect(() => {
const getcategory = async () => {
const rescategory = await axios.get(
"http://localhost:4000/api/categorywise"
);
setCategory(rescategory.data.reverse());
};
getcategory();
}, []);
const handlecategory = (event) => {
const getcategoryid = event.target.value;
setCategoryid(getcategoryid);
};
useEffect(() => {
const getsubcategory = async () => {
const ressubcategory = await axios.get(
"http://localhost:4000/api/subcategorywise"
);
setSubcategory(ressubcategory.data.reverse());
};
getsubcategory();
}, []);
const handleSubcategory = (event) => {
const getSubcategoryid = event.target.value;
setSubcategoryid(getSubcategoryid);
};
useEffect(() => {
if (users.length) {
const scrollPosition = sessionStorage.getItem("scrollPosition");
if (scrollPosition) {
window.scrollTo(0, parseInt(scrollPosition, 10));
sessionStorage.removeItem("scrollPosition");
}
}
}, [users]);
useEffect(() => {
if (users.length) {
const scrollPosition = sessionStorage.getItem("scrollPosition");
if (scrollPosition) {
window.scrollTo(0, parseInt(scrollPosition, 10));
sessionStorage.removeItem("scrollPosition");
}
}
}, [users]);
return (
<div className="App">
<div className="header-1">
<nav className="navbar">
<div className="container-fluid">
<div className="navbar-brand">Supplier Contact Information</div>
{/* <form className="d-flex">
<Link className="btn btn-outline-light" to="/users/statics">
Statics
</Link>
</form> */}
</div>
</nav>
<hr class="solid"></hr>
</div>
<div className="header">
<h4>CATEGORYWISE SUPPLIER INFORMATION</h4>
<div className="col-md-0">
<div class="row">
<div class="col-sm-3">
<div class="card">
<div class="card-body text-center ">
<input
type="text"
placeholder="Power Search..."
className="form-control"
onChange={(e) => setSearchTitle(e.target.value)}
/>
<br />
<select
name="prime"
className="form-control"
onChange={(e) => handleprime(e)}
>
<option value="">--Select Prime--</option>
{prime.map((resprime, index) => (
<option key={index} value={resprime.Prime_Descr}>
{resprime.Prime_Descr}{" "}
</option>
))}
</select>{" "}
</div>
</div>
</div>
<div class="col-sm-3">
<div class="card">
<div class="card-body">
<select
name="category"
className="form-control"
onChange={(e) => handlecategory(e)}
>
<option value="">--Select Category--</option>
{category.map((rescategory, index) => (
<option key={index} value={rescategory.CATEGORY}>
{rescategory.CATEGORY}{" "}
</option>
))}
</select>{" "}
<br />
<select
name="country"
className="form-control"
onChange={(e) => handlecategory(e)}
>
<option value="">--Select Category--</option>
{subcategory.map((ressubcategory, index) => (
<option key={index} value={ressubcategory.SUB_CATEGORY}>
{ressubcategory.SUB_CATEGORY}{" "}
</option>
))}
</select>{" "}
</div>
</div>
</div>
<div class="col-sm-6">
<div class="card-1">
<div class="card-body text-center ">
<CSVLink
filename="supplier contact info."
data={users}
class="btn btn-outline-light"
>
Export to csv
</CSVLink>
<br />
<br />
<div className="container-fluid">
<Link className="btn btn-outline-light" to="/users/add">
Add Supplier
</Link>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div className="outer-wrapper">
<div className="tabel-wrapper">
<table>
<thead>
<th scope="col">S.No</th>
<th scope="col">Prime</th>
<th scope="col">Category</th>
<th scope="col">Sub-Category</th>
<th scope="col">Supplier</th>
<th scope="col">Country</th>
<th scope="col">Region</th>
<th scope="col">Title/Designation</th>
<th scope="col">Representative</th>
<th scope="col">Department</th>
<th scope="col">Primary Contact No</th>
<th scope="col">Secondary Contact No</th>
<th scope="col">EmailId</th>
<th scope="col">Address</th>
<th>Action</th>
</thead>
<tbody>
{/* {usersList ? (
<h4>Loading ...</h4> */}
{loading ? (
<h4>Loading ...</h4>
) : (
users
.filter((value) => {
if (searchTitle === "") {
return value;
} else if (
// (value.PRIME &&
// value.PRIME.toLowerCase().includes(
// searchTitle.toLowerCase()
// )) ||
(value.CATEGORY &&
value.CATEGORY.toLowerCase().includes(
searchTitle.toLowerCase()
)) ||
(value.SUB_CATEGORY &&
value.SUB_CATEGORY.toLowerCase().includes(
searchTitle.toLowerCase()
)) ||
(value.SUPPLIER &&
value.SUPPLIER.toLowerCase().includes(
searchTitle.toLowerCase()
)) ||
(value.COUNTRY &&
value.COUNTRY.toLowerCase().includes(
searchTitle.toLowerCase()
)) ||
(value.REGION &&
value.REGION.toLowerCase().includes(
searchTitle.toLowerCase()
)) ||
(value.DESIGNATION &&
value.DESIGNATION.toLowerCase().includes(
searchTitle.toLowerCase()
)) ||
(value.REPRESENTATIVE_NAME &&
value.REPRESENTATIVE_NAME.toLowerCase().includes(
searchTitle.toLowerCase()
)) ||
(value.DIVISION &&
value.DIVISION.toLowerCase().includes(
searchTitle.toLowerCase()
)) ||
(value.CONTACT_NO &&
value.CONTACT_NO.toLowerCase().includes(
searchTitle.toLowerCase()
)) ||
(value.ALTERNATE_CONTACT_NUMBER &&
value.ALTERNATE_CONTACT_NUMBER.toLowerCase().includes(
searchTitle.toLowerCase()
)) ||
(value.EMAIL_ID &&
value.EMAIL_ID.toLowerCase().includes(
searchTitle.toLowerCase()
)) ||
(value.ADDRESS &&
value.ADDRESS.toLowerCase().includes(
searchTitle.toLowerCase()
))
) {
return value;
}
})
.map((user, index) => (
<tr>
<td scope="row">{index + 1}</td>
<td>{user.PRIME}</td>
<td>{user.CATEGORY}</td>
<td>{user.SUB_CATEGORY}</td>
<td>{user.SUPPLIER}</td>
<td>{user.COUNTRY}</td>
<td>{user.REGION}</td>
<td>{user.DESIGNATION}</td>
<td>{user.REPRESENTATIVE_NAME}</td>
<td>{user.DIVISION}</td>
<td>{user.CONTACT_NO}</td>
<td>{user.ALTERNATE_CONTACT_NUMBER}</td>
<td>{user.EMAIL_ID}</td>
<td>{user.ADDRESS}</td>
<td>
<Link
class="btn btn-outline-primary mr-2"
to={`/users/edit/${user.ID}`}
>
Edit
</Link>
</td>
</tr>
))
)}
</tbody>
</table>
</div>
</div>
</div>
);
};
export default Home;

How to get the pokemon stock dynamically from homepage to detailpage?

I'm developing an app that can track pokemon stocks in the store. I fetch the name of data from pokeAPI. Each pokemon is supposed to have its own stock (my pokemon stock is still static) that can be updated in the next page when i click the pokemon's name.
This is the second page:
All in this page is still static. the only dinamic is the pokemons name that I get from params.
How can I update stock of each pokemon and save it? and show it in certain page? Using params (but i think it's not the best practice)? I read I can save the stock to localStorage and accessit later but where should I start from my code?
This is the modal that i will use to update my stock and pass the value to the second page.
first page:
export default function Homepage() {
const [pokemons, setPokemons] = useState([])
const [query, setQuery] = useState("")
const [search, setSearch] = useState("")
let navigate = useNavigate();
const getPokemons = async () => {
try {
let response = await axios.get(`${baseUrl}`)
let pokemons = await response.data.results
setPokemons(pokemons)
} catch (err) {
console.log(err.message)
}
}
const searchPokemon = async (pokemon, e) => {
console.log("masuk seacrh")
try {
if (e.key === 'Enter') {
let response = await axios.get(`${baseUrl} ${pokemon}`)
let data = await response.json()
setSearch(search)
}
} catch (err) {
console.log(err.message)
}
}
useEffect(() => {
getPokemons()
}, [])
// useEffect(() => {
// searchPokemon()
// }, [])
return (
<div className="app-container">
<h1 className="title">Stok Pokémon</h1>
<div className="">
<img src={searchIcon} className="search-icon" />
<input type="text"
className="search-box"
placeholder="Cari Pokémon"
onChange={(e) => setQuery(e.target.value)}
onKeyUp={searchPokemon} />
</div>
<div className="row">
<div className="col">
<Table className="table d-flex row">
<thead>
<tr className="d-flex justify-content-between th-border">
<th scope="col">Nama</th>
<th scope="col" className="d-flex text-right">Stok</th>
</tr>
</thead>
<tbody>
{
pokemons.filter(pokemon => pokemon.name.toLowerCase().includes(query)).map((pokemon, i) => {
console.log(pokemon)
return (
<tr className="d-flex justify-content-between">
<td key={i + 1} className="table-link" onClick={() => {
navigate(`/pokemon/${pokemon.name}`)
}} style={{ textTransform: 'capitalize' }}>{pokemon.name}</td>
<td className="pokemon-stock">10 pcs</td>
</tr>
)
})
}
</tbody>
</Table>
</div>
</div>
</div >
)
}
second page:
function UpdateStockModal(props) {
const [input, setInput] = useState({
pcs: 0,
lusin: 0
})
let navigate = useNavigate();
const [pcs, setPcs] = useState("")
const handleChange = e => {
let newValue = {
...input,
[e.target.name]: e.target.value,
};
setInput(newValue);
};
return (
<Modal
{...props}
size="lg"
aria-labelledby="contained-modal-title-vcenter"
className="modal"
centered
>
<Modal.Header closeButton>
<Modal.Title className="modal-title">
Update stock
</Modal.Title>
</Modal.Header>
<Modal.Body>
<h4>Masukkan jumlah stok yang tersedia di rak saat ini.</h4>
<Container>
<Row>
<Col>Kemasan</Col>
<Col>Jumlah</Col>
<Col>Stok</Col>
</Row>
<Row className="modal-table-body">
<Col >Pcs</Col>
<Col className="d-flex align-items-center">1 x <Form.Control className="modal-input pcs" type="text" name="pcs" value={input.pcs} onChange={handleChange} /> = </Col>
<Col>{input.pcs}</Col>
</Row>
<Row className="modal-table-body">
<Col>Lusin</Col>
<Col className="d-flex align-items-center">12 x <Form.Control name="lusin" className="modal-input lusin" type="text" value={input.lusin} onChange={handleChange} /> = </Col>
<Col>{12 * input.lusin}</Col>
</Row>
<Row className="modal-table-body">
<Col>Total Stok <span>(dalam pcs)</span></Col>
<Col>Lusin</Col>
<Col>{parseInt(12 * input.lusin) + parseInt(input.pcs)}</Col>
</Row>
</Container>
</Modal.Body>
<Modal.Footer>
<Button
variant="primary"
onClick={() => {
navigate(`/update-stock/`)
}} >
Simpan
</Button>
<Button
variant="secondary"
onClick={props.onHide}>
Batal
</Button>
</Modal.Footer>
</Modal>
);
}
export default function PokemonDetail() {
let navigate = useNavigate();
let { name } = useParams()
const [modalShow, setModalShow] = React.useState(false);
return (
<div className="pokemon-detail-page">
<div className="pokemon-detail_button-group">
<Button variant="outline-light" className="prev-button" onClick={() => {
navigate('/')
}}><img src={prevPageIcon}></img>Stok Pokémon</Button>
<Button className="update-stock-button" onClick={() => setModalShow(true)}>Update Stok</Button>
</div>
<p className="pokemon-detail-title" style={{ textTransform: 'capitalize' }}>{name}</p>
<div className="pokemon-detail-subtitle">
<p className="pokemon-detail-sub1">Sisa Stok</p>
<p className="pokemon-detail-sub2">10 pcs</p>
</div>
<div className="pokemon-detail-history">
<p className="pokemon-detail-history1">Riwayat Stok</p>
<p className="pokemon-detail-history2">Satuan stok dalam pcs</p>
</div>
<div>
<Table className='col-xs-12 mt-4' responsive>
<thead>
<tr className="th-border ">
<th scope="col">Waktu</th>
<th scope="col">Kegiatan</th>
<th scope="col">Catatan</th>
<th scope="col">Jumlah</th>
<th scope="col">Stok</th>
</tr>
</thead>
<tbody>
<tr className="align-items-center">
<td className="">2 Apr 2021, 08:00</td>
<td className="table-link">Update Stok</td>
<td className="">"Stok Awal"</td>
<td className="table-count-stock">+10</td>
<td className="table-bold">10</td>
</tr>
</tbody>
</Table>
</div>
<UpdateStockModal
show={modalShow}
onHide={() => setModalShow(false)}
/>
</div>
)
}
Sounds like a shopping cart. I'm assuming you'd like to update the stock for each pokemon. Then on another page, check all the updates before sending an update to the backend. For this I recommend redux saga or rtk query. The state will be globally accessible via the store so you can create your shopping cart securely without using local storage. You can google "redux saga shopping cart" for more examples but these are a couple I've found.
Redux saga
https://github.com/franklsm1/redux-saga-shopping-cart
RTK query
https://codesandbox.io/s/xed9r?file=/README.md

React-table global filter Regex

Having trouble getting my GlobalFilter to update the table when using Regex to search for multiple results in a column.
export const Table = ({ data, columns }) => {
const filterTypes = useMemo(
() => ({
// Override the default text filter to use
// "startWith"
text: (rows, id, filterValue) => {
return rows.filter((row) => {
const rowValue = row.values[id];
const isRegexMatch = () => {
try {
return RegExp(filterValue).test(String(rowValue));
} catch (err) {
return false;
}
};
return rowValue !== undefined
? String(rowValue)
.toLowerCase()
.startsWith(String(filterValue).toLowerCase()) || isRegexMatch()
: true;
});
},
}),
[]
);
const {
getTableProps,
getTableBodyProps,
headerGroups,
prepareRow,
page,
canPreviousPage,
canNextPage,
pageOptions,
pageCount,
gotoPage,
nextPage,
previousPage,
setPageSize,
preGlobalFilteredRows,
setGlobalFilter,
state,
state: { pageIndex, pageSize },
} = useTable(
{
columns,
data,
filterTypes,
},
useFilters,
useGlobalFilter,
useSortBy,
usePagination
);
return (
<div className="col-12">
<div className="table-responsive mb-5">
<GlobalFilter
preGlobalFilteredRows={preGlobalFilteredRows}
globalFilter={state.globalFilter}
setGlobalFilter={setGlobalFilter}
/>
<table {...getTableProps()} className="table">
<thead>
{headerGroups.map((headerGroup) => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column) => (
<th {...column.getHeaderProps(column.getSortByToggleProps())}>
{column.render('Header')}
<span>
{column.isSorted ? (
column.isSortedDesc ? (
<ChevronDown baseLayer="icon" />
) : (
<ChevronUp baseLayer="icon" />
)
) : (
''
)}
</span>
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{page.map((row, i) => {
prepareRow(row);
return (
<tr {...row.getRowProps()} key={i}>
{row.cells.map((cell) => {
return (
<td {...cell.getCellProps()}>{cell.render('Cell')}</td>
);
})}
</tr>
);
})}
</tbody>
</table>
<div className="pagination mt-3">
<button
onClick={() => gotoPage(0)}
disabled={!canPreviousPage}
className="btn btn-sm btn-link"
>
{'<<'}
</button>{' '}
<button
onClick={() => previousPage()}
disabled={!canPreviousPage}
className="btn btn-sm btn-link"
>
{'<'}
</button>{' '}
<button
onClick={() => nextPage()}
disabled={!canNextPage}
className="btn btn-sm btn-link"
>
{'>'}
</button>{' '}
<button
onClick={() => gotoPage(pageCount - 1)}
disabled={!canNextPage}
className="btn btn-sm btn-link"
>
{'>'}
</button>{' '}
<span className="mt-2 text-muted">
<small>
Page {pageIndex + 1} of {pageOptions.length}{' '}
</small>
</span>
<span className="mt-2 ms-1 me-1 text-muted">
<small> | Go to page:</small>
</span>
<span className="me-1">
<input
type="number"
className="form-control"
defaultValue={pageIndex + 1}
onChange={(e) => {
const page = e.target.value ? Number(e.target.value) - 1 : 0;
gotoPage(page);
}}
style={{ width: '80px' }}
/>
</span>
<select
value={pageSize}
style={{ width: '190px' }}
className="form-control"
onChange={(e) => {
setPageSize(Number(e.target.value));
}}
>
{[10, 20, 30, 40, 50].map((pageSize) => (
<option key={pageSize} value={pageSize}>
Show {pageSize} per page
</option>
))}
<option key={data.length} value={data.length}>
Show All
</option>
</select>
</div>
</div>
</div>
);
};
I only had success so far in the console with this function being able to filter the results, but so far no luck with the react-table package.
function regexFilter(rows, ids, filterValue) {
rows = rows.filter((row) => {
return ids.some((id) => {
const rowValue = row.values[id];
const isRegexMatch = () => {
try {
return RegExp(filterValue).test(String(rowValue));
} catch (err) {
return false;
}
};
return (
String(rowValue)
.toLowerCase()
.includes(String(filterValue).toLowerCase()) || isRegexMatch()
);
});
});
return rows;
}
What am I not doing correctly or mis-interpreting from the documentation on filterTypes?

Word is not getting added until the page is refreshed in TableItem component in React

TableItem component added without any data in UI. Could somebody help on this. On refereshing the UI, added data is shown with details in TableItem component.
Table Component Code
import TableItem from "./TableItem";
function Table({ searchWord }) {
const dispatch = useDispatch();
const dictData = useSelector((state) => state.dictionary);
useEffect(() => {
dispatch(getDictionaryAsync());
}, [dispatch]);
return (
<table className="table table-striped">
<thead>
<tr>
<th scope="col">Word</th>
<th scope="col">Description</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
{dictData &&
dictData
.filter((e) =>
searchWord === ""
? e
: e.word &&
e.word.toLowerCase().includes(searchWord.toLowerCase())
)
.map((item) => (
<TableItem item={item} key={item.id} searchWord={searchWord} />
))}
</tbody>
</table>
);
}
export default Table;
Below is the TableItem Component Code which i am trying to update,
When i add a word to dictionary it will fetch the details from the server and display it in the React app.
function TableItem({ item }) {
const [modal, setModal] = useState(false);
const openModal = () => {
setModal(true);
};
return (
<>
<tr key={item.id}>
<td style={{ textTransform: "capitalize" }}>{item.word}</td>
<td>
<b style={{ textTransform: "capitalize" }}>
{item.items && item.items[0].category} -{" "}
</b>
{item.items && truncate(item.items[0].definitions[0])}
</td>
<td>
<button className="btn btn-danger btn-sm " onClick={openModal}>
View
</button>
</td>
</tr>
<Modal isOpen={modal} ariaHideApp={true}>
<div className="modal-header">
<h3 className="modal-word-header">
{item.word && item.word.toUpperCase()}
</h3>
<button
className="btn btn-danger btn-sm"
onClick={() => setModal(false)}
>
<i class="fa fa-times" aria-hidden="true"></i>
</button>
</div>
<div className="model-content">
<p>
{item.items &&
item.items.map((e) => {
return (
<>
<i>{e.category}</i>
<ul>
{e.definitions.map((def) => {
return <li>{def}</li>;
})}
</ul>
</>
);
})}
</p>
</div>
</Modal>
</>
);
}
Better add your TableItem component code!
Below code works fine and updated the UI on change in the Data in TableItem,
useEffect(() => {
dispatch(getDictionaryAsync());
}, [dispatch, dictData]); *<--updated code*

Resources