I want to dynamically show my buttons when i get to the lastSlide, but it dies not seems to work.
I'm trying to use FindIndex to find someText that is actually on the lastSlide and nothing happens
The console prints out 4 because i have 5 items in the Array which is correct, but i can't render something to the dom
if there's any other options in the IonSlides Component itself, i will appreciate, because onSlideReachEnd event that ionic provides does not work.
const lastIndex = slideContent.findIndex((element) => {
if (element.slideTitle === "Safe & Secure") {
return true;
}
return false;
});
console.log(lastIndex); // 4
return (
<IonPage>
<div className="content">
<IonSlides pager={true} options={slideOpts}>
{slideContent.map((slide, idx) => (
<IonSlide key={idx}>
<div>
<img
src={slide.slideImage}
alt={slide.slideAltText}
className={slide.slideClassName}
/>
<IonText>
<h5 className="mb-1 fw-bold">{slide.slideTitle}</h5>
</IonText>
<IonText color="primary" className="fw-bold">
<h4 className="mt-0 bold h4"> {slide.slidePrimaryText} </h4>
</IonText>
<div className="pt-0 px-5 pb-4">
<IonText>
<h6 className="fs-md mb-6 line-h fw-sm fw-reg tet-color">
{slide.slideText}
{slide.slideSecoundaryText && (
<IonText color="primary" className="fw-bold ">
<h6 className="mt-0 fs-md bold mt-3">
{slide.slideSecondaryText}
</h6>
</IonText>
)}
</h6>
</IonText>
{slide.slideBtn && (
<IonButton
shape="round"
fill="clear"
className="btn f-inherit"
size="small"
>
Stuff
</IonButton>
)}
{idx}
</div>
</div>
</IonSlide>
))}
</IonSlides>
</div>
{lastIndex && (
<div className="ion-padding">
<IonGrid>
<IonRow>
<IonCol size="6">
<IonButton
expand="block"
className="btn"
size="small"
onClick={() => navigate("/login", "forward")}
>
Login
</IonButton>
</IonCol>
<IonCol size="6">
<IonButton
expand="block"
fill="outline"
onClick={() => navigate("/get-started", "forward")}
className="btn"
size="small"
>
Get Started
</IonButton>
</IonCol>
</IonRow>
</IonGrid>
</div>
)}
</IonPage>
);
const SlidePage = () => {
const [isLastSlide, setIsLastSlide] = useState();
const slideChanged = async e => {
const r = await e.target.isEnd();
setIsLastSlide(r);
console.log("isEnd", r);
};
return (
<IonPage>
<IonContent>
<IonSlides pager={true} onIonSlideDidChange={slideChanged}>
<IonSlide>
<h1>Slide 1</h1>
</IonSlide>
<IonSlide>
<h1>Slide 2</h1>
</IonSlide>
<IonSlide>
<h1>Slide 3</h1>
</IonSlide>
</IonSlides>
{isLastSlide && <h1 style={{ textAlign: "center" }}>IS LAST SLIDE</h1>}
</IonContent>
</IonPage>
);
listen for slide change event and update the state if it is the last slide.
onIonSlideDidChange
working example here on stackblitz - https://stackblitz.com/edit/react-w5gawb?file=src%2FApp.js
Related
when i click on the description button, all the mapped containers are showing their descriptions, but i only want the one thats pressed to show its description. so how can i make it so that the container that is pressed will show its id's description?
`import { useState } from "react";
export default function ServiciosCard({ profile }) {
const [normal, setNormal] = useState(true);
const [showDescripcion, setShowDescripcion] = useState(false);
const showDescripcionChangeHandler = () => {
setShowDescripcion(true);
setNormal(false);
};
return (
<>
<div
className=" space-y-4 mt-3 md:mt-0 h-[450px] md:h-[550px] overflow-y-auto
md:scrollbar scrollbar-track-[#d0e7d5] scrollbar-thumb-[#ef8eb2]
text-center "
>
{profile.servicios.map((servicio) => (
<>
{normal && (
<div
key={servicio._id}
className="bg-[#f7ede2] rounded-md w-[300px] h-[75px] "
>
<div>{servicio.unServicio}</div>
<div>1 Hr {servicio.costo}</div>
<div className=" space-x-4">
<button className="text-[#f77f00] hover:headerButton">
Reserva ahora
</button>
<button
onClick={showDescripcionChangeHandler(servicio._id)}
className="text-[#f77f00] hover:headerButton"
>
Descripcion
</button>
</div>
</div>
)}
{showDescripcion && (
<div
key={servicio._id}
className="bg-[#f7ede2] rounded-md w-[300px] h-[75px] "
>
{servicio.description}
</div>
)}
</>
))}
</div>
</>
);
}`
showDescription will show description for all item
you can create a new component Like below an pass srvicio to it.
import { useState } from "react";
export default function ServiciosCard({ profile }) {
return (
<>
<div
className=" space-y-4 mt-3 md:mt-0 h-[450px] md:h-[550px] overflow-y-auto
md:scrollbar scrollbar-track-[#d0e7d5] scrollbar-thumb-[#ef8eb2]
text-center "
>
{profile.servicios.map((servicio) => (
<ServicIo servicio={servicio} />
))}
</div>
</>
);
}
function ServicIo({servicio}){
const [normal, setNormal] = useState(true);
const [showDescripcion, setShowDescripcion] = useState(false);
const showDescripcionChangeHandler = () => {
setShowDescripcion(true);
setNormal(false);
};
return (<>
{normal && (
<div
key={servicio._id}
className="bg-[#f7ede2] rounded-md w-[300px] h-[75px] "
>
<div>{servicio.unServicio}</div>
<div>1 Hr {servicio.costo}</div>
<div className=" space-x-4">
<button className="text-[#f77f00] hover:headerButton">
Reserva ahora
</button>
<button
onClick={showDescripcionChangeHandler(servicio._id)}
className="text-[#f77f00] hover:headerButton"
>
Descripcion
</button>
</div>
</div>
)}
{showDescripcion && (
<div
key={servicio._id}
className="bg-[#f7ede2] rounded-md w-[300px] h-[75px] "
>
{servicio.description}
</div>
)}
</>)
}
in this code showDescription do each item that selected by user.
How can I loop data that will have different styles such as colors and icons in a better way than the code below? The code below works but I want to have more categories to loop through and the code is getting long. Is there a better way to do this without changing the backend?
I'm using Next.js and Firebase for backend, map looping "Food" collection with product documents and categories in fields. Only one id in the food group can be true for each item.
{food.map((item, index) => (
<div key={index}>
{/* Fruits category*/}
{Object.keys(item.fruitsCategory).length > 0 && (
<div>
{/* Apples */}
{item.fruitsCategory.category.id === 1 && (
<div className="flex gap-2">
<AppleIcon />
<p className="text-[#1BAB33]">Apples</p>
</div>
)}
{/* Bananas */}
{item.fruitsCategory.category.id === 2 && (
<div className="flex gap-2">
<BananaIcon />
<p className="text-[#C6B027]">Bananas</p>
</div>
)}
{/* Oranges */}
{item.fruitsCategory.category.id === 3 && (
<div className="flex gap-2">
<OrangeIcon />
<p className="text-[#FAB71A]">Oranges</p>
</div>
)}
{/* Strawberries */}
{item.fruitsCategory.category.id === 4 && (
<div className="flex gap-2">
<StrawberryIcon />
<p className="text-[#D13131]">Strawberries</p>
</div>
)}
{/* Meat category */}
{Object.keys(item.meatCategory).length > 0 && (
<div>
{/* Cow meat */}
{item.meatCategory.category.id === 1 && (
<div className="flex gap-2">
<CowIcon />
<p className="text-[#006989]">Cow meat</p>
</div>
)}
{/* Chicken meat */}
{item.meatCategory.category.id === 2 && (
<div className="flex gap-2">
<ChickenIcon />
<p className="text-[#01A7C2]">Chicken meat</p>
</div>
)}
{/* Pig meat */}
{item.meatCategory.category.id === 3 && (
<div className="flex gap-2">
<PigIcon />
<p className="text-[#18AFC8]">Pig meat</p>
</div>
)}
</div>
)}
</div>
)}
How can I call "useSate(false)" in React from a nested component?
I would like to close the sidebar when one of the sidebar items is clicked. For that I need to call the onclick function setOpen(true) from the parent component.
function SearchDropdown() {
const [open, setOpen] = useState(false);
return (
<>
<div className="searchIcon" onClick={() => setOpen(!open)}><img src="./assets/img/SearchN.jpg" alt=" " /><p>Search</p></div>
{open && <>
<div className="searchBarDropdown"><SearchBar></SearchBar></div>
<div onClick={() => setOpen(!open)} className="searchBarDropdownX"></div>
</>}
</>
);
}
function MenuSidebar() {
const [open, setOpen] = useState(false);
return (
<>
<div className="logo" onClick={() => setOpen(true)}><p>LOgo</p><img className="dropdown" src="./assets/img/Dropdown.png" alt=">" /></div>
{open && <>
<div className="menuSidebar">
<h3 className="backwardsSection" onClick={() => setOpen(false)}>🠔 Go Back</h3>
<MenuSidebarItems />
<h3 className="sidebarTopics">Topics</h3>
<TopicItems />
</div>
<div className="menuSidebarSpacing" onClick={() => setOpen(false)}></div>
</>}
</>
);
}
function MenuSidebarItems() {
return (
<>
<MenuSidebarItem leftIcon={ <HomeIcon /> } rightIcon={ <HomeIcon></HomeIcon> }>Home</MenuSidebarItem>
<MenuSidebarItem leftIcon={ <HomeIcon /> }>Dashboard</MenuSidebarItem>
<MenuSidebarItem leftIcon={ <HomeIcon /> }>Shop</MenuSidebarItem>
<MenuSidebarItem leftIcon={ <HomeIcon /> } rightIcon={ <HomeIcon></HomeIcon> }>Projects</MenuSidebarItem>
<MenuSidebarItem leftIcon={ <HomeIcon /> }>About</MenuSidebarItem>
</>
);
}
function MenuSidebarItem(props) {
const navigate = useNavigate();
return (
<button className="menuItem" onClick={() => {
navigate("/" + props.children.toString().toLowerCase());
}}>
<span className="leftIcon">{props.leftIcon}</span>
{props.children}
<span className="rightIcon">{props.rightIcon}</span>
</button>
);
}
Thanks, Martin
You need to pass the setState that close the navbar as props to the component that display the menu.
function SearchDropdown() {
const [open, setOpen] = useState(false);
return (
<>
<div className="searchIcon" onClick={() => setOpen(!open)}><img src="./assets/img/SearchN.jpg" alt=" " /><p>Search</p></div>
{open && <>
<div className="searchBarDropdown"><SearchBar></SearchBar></div>
<div onClick={() => setOpen(!open)} className="searchBarDropdownX"></div>
</>}
</>
);
}
function MenuSidebar() {
const [open, setOpen] = useState(false);
return (
<>
<div className="logo" onClick={() => setOpen(true)}><p>LOgo</p><img className="dropdown" src="./assets/img/Dropdown.png" alt=">" /></div>
{open && <>
<div className="menuSidebar">
<h3 className="backwardsSection" onClick={() => setOpen(false)}>🠔 Go Back</h3>
<MenuSidebarItems setOpen={setOpen}/>
<h3 className="sidebarTopics">Topics</h3>
<TopicItems />
</div>
<div className="menuSidebarSpacing" onClick={() => setOpen(false)}></div>
</>}
</>
);
}
function MenuSidebarItems(props) {
const {setOpen} = props
return (
<>
<MenuSidebarItem setOpen={setOpen} leftIcon={ <HomeIcon /> } rightIcon={ <HomeIcon></HomeIcon> }>Home</MenuSidebarItem>
<MenuSidebarItem setOpen={setOpen} leftIcon={ <HomeIcon /> }>Dashboard</MenuSidebarItem>
<MenuSidebarItem setOpen={setOpen} leftIcon={ <HomeIcon /> }>Shop</MenuSidebarItem>
<MenuSidebarItem setOpen={setOpen} leftIcon={ <HomeIcon /> } rightIcon={ <HomeIcon></HomeIcon> }>Projects</MenuSidebarItem>
<MenuSidebarItem setOpen={setOpen} leftIcon={ <HomeIcon /> }>About</MenuSidebarItem>
</>
);
}
function MenuSidebarItem(props) {
const navigate = useNavigate();
const {setOpen} = props
return (
<button className="menuItem" onClick={() => {
setOpen={flase}
navigate("/" + props.children.toString().toLowerCase());
}}>
<span className="leftIcon">{props.leftIcon}</span>
{props.children}
<span className="rightIcon">{props.rightIcon}</span>
</button>
);
}
Ant modal appears few times, but if i remove map function inside the modal then its works fine its appears only one time.
what may be the issue? please help me to solve this issue (Modal triggering/appears few times)
Ant modal code follows:
const [visibleVoucherModal, setVisibleVoucherModal] = useState(false);
const showVoucherModal = () => {
setVisibleVoucherModal(true)
}
const closeVoucherModal = () => {
setVisibleVoucherModal(false);
};
const SavedVoucherModal = () => {
return (
<Modal title="Select Any Voucher" visible={visibleVoucherModal} onCancel={closeVoucherModal} footer={null} >
{savedVoucherList.length >= 1 ?
<div>
<Checkbox.Group className="w-100" onChange={checkBox} value={voucherVal} >
{savedVoucherList.map((item, i) => {
return (
<div key={i}>
<Checkbox value={item.Id} className="w-100" onChange={e => { handleCheckBox(e, i) }}
checked={checked[i] || true} disabled={!checked[i] && disabled} >
<div className="pl-4">
<List.Item style={{ marginTop: "-35px" }} className="py-0">
<List.Item.Meta
// avatar={<img src={item.Photo == '' ? 'd' : item.Photo} alt="" width="72" />}
title={<span style={{ fontSize: "12px" }}>{item.Name}</span>}
description={<div className="small">Expiry Date: <br />{item.ExpireDate.slice(0, 10)}</div>}
/>
<div className="pt-1">
<p className="font-weight-bold text-primary mb-0">{numberFormat(item.Price)}</p>
<small><del>{numberFormat(item.OldPrice)}</del></small>
</div>
</List.Item>
</div>
</Checkbox>
<Divider className="m-0 p-0 mb-4" />
</div>)
})}
</Checkbox.Group>
</div> :
<p className="mb-4">Oops, there is no voucher applicable to this order</p>
}
<Button type="primary" className="font-weight-bold btn-round" onClick={closeVoucherModal}>Close</Button>
</Modal>
)
}
Button:
<Button type="default" className="text-primary border-right-0 border-left-0" size="large" onClick={showVoucherModal}>Redeem Voucher</Button>
I am stuck in this problem. I want to add/remove the class on a header element on scroll, but somehow I can not manage it.
I tried to mount and unmount (found few solutions here on Stack) but does not work in my case. Simply because in most of those cases the code relates to component but I have a little bit different set-up.
Here the full code:
https://codesandbox.io/s/angry-villani-lduor?fontsize=14
I want to add the new class on store_details_header
const handleChangeIndex = index => {
setValue(index);
};
if (!selectedStore) {
return null;
}
return (
<div className="store-details">
<div className="store-details__header" style={{ backgroundImage: `url(${selectedStore.headerBackgroundImgUrl})` }}>
<img className="store-details__header__exit" src={exit} alt="exit" onClick={backToNearYou} />
<img className="store-details__header__logo" src={selectedStore.headerLogoUrl} alt="logo" />
</div>
<div className="store-details__content" style={{ backgroundImage: `url(${selectedStore.contentBackgroundImgUrl})` }}>
<div>
<AppBar className={props.classes.root} position="static" color="default">
<Tabs value={value} classes={{ indicator: props.classes.indicator }} onChange={setSelectedNavigationItem} variant="fullWidth">
<StyledTab label="Products" />
<StyledTab label="Items" />
</Tabs>
</AppBar>
<SwipeableViews axis={'x'} index={value} onChangeIndex={handleChangeIndex}>
<TabContainer>
{' '}
<div className="store-details__content__items">{renderSliderItems()}</div>
</TabContainer>
<TabContainer>
{' '}
<div className="store-details__content__items">{renderSliderItems()}</div>
</TabContainer>
</SwipeableViews>
</div>
</div>
{guestMode && renderGuestModeBox()}
{selectedStore.loyaltyCard && renderLoyaltyCard()}
</div>
);
};
const handleChangeIndex = index => {
setValue(index);
};
if (!selectedStore) {
return null;
}
return (
<div className="store-details">
<div className="store-details__header" style={{ backgroundImage: `url(${selectedStore.headerBackgroundImgUrl})` }}>
<img className="store-details__header__exit" src={exit} alt="exit" onClick={backToNearYou} />
<img className="store-details__header__logo" src={selectedStore.headerLogoUrl} alt="logo" />
</div>
<div className="store-details__content" style={{ backgroundImage: `url(${selectedStore.contentBackgroundImgUrl})` }}>
<div>
<AppBar className={props.classes.root} position="static" color="default">
<Tabs value={value} classes={{ indicator: props.classes.indicator }} onChange={setSelectedNavigationItem} variant="fullWidth">
<StyledTab label="Products" />
<StyledTab label="Items" />
</Tabs>
</AppBar>
<SwipeableViews axis={'x'} index={value} onChangeIndex={handleChangeIndex}>
<TabContainer>
{' '}
<div className="store-details__content__items">{renderSliderItems()}</div>
</TabContainer>
<TabContainer>
{' '}
<div className="store-details__content__items">{renderSliderItems()}</div>
</TabContainer>
</SwipeableViews>
</div>
</div>
{guestMode && renderGuestModeBox()}
{selectedStore.loyaltyCard && renderLoyaltyCard()}
</div>
);
};