How to use button collapse with material ui accordion? - reactjs

I'm using material UI for the collapse button, and the accordion.
I want people to be able to click the today button, and have that open the first accordion section (the one that says Saturday on it). The today button is inside a material UI toolbar. I'm also using react hooks for the project.
I'm just using the default accordion settings as shown on the material UI website. Each accordion has its own id (ex: panel1, panel2, etc.).
I'm using the sample layout from material ui controlled accordion
Example of Open Accordions:
Example of Closed Accordions:
Any help you could give me would be great! Thanks.

Using the expanded property of the Accordion along with state will give you what you are looking for.
Be aware that once you set the expanded property, the default behavior of the accordion will be overridden and you will need to control the behavior directly.
Here's a code sandbox example of how I would solve it.
edit - code example:
import {
Accordion,
AccordionDetails,
AccordionSummary,
Button
} from "#material-ui/core";
import React, { useState } from "react";
import "./styles.css";
const week = [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday"
];
const d = new Date();
const currentDay = week[d.getDay()];
export default function App() {
const [openDay, setOpenDay] = useState("");
function handleAccordClick(day) {
if(openDay === day) setOpenDay("")
if(openDay !== day) setOpenDay(day)
}
function generateWeekAccordion(day) {
return (
<Accordion
expanded={day === openDay}
onClick={() => handleAccordClick(day)}
>
<AccordionSummary>{day}</AccordionSummary>
<AccordionDetails>{`${day} details...`}</AccordionDetails>
</Accordion>
);
}
return (
<div className="App">
<Button
style={{ marginBottom: "20px" }}
variant="outlined"
onClick={() => setOpenDay(currentDay)}
>
Open Today
</Button>
{week.map((day) => generateWeekAccordion(day))}
</div>
);
}

Related

How to create a new product component through onClick of a button in React?

Goal: Create a new product component through onClick of a button where it would display a modal containing textfields to be filled up with the new product's name and price. We then pass the value of those textfields to the data.jsx (data source for rendering the product components) after clicking the Add button inside the modal in order to create a new instance of data info of the new product.
Problem: I am having trouble on passing the values of the textfields from the modal going to data.jsx since I literally have no clue how to properly pass those values into a plain database file. I think props, hooks, etc. might not work on passing the values.
Modal appearance (after clicking Add New Product button):
Modal appearance (with textfield values):
Modal source code (ModalAddProduct.jsx):
import React from "react";
import { Typography } from "#mui/material";
import {
BrowserRouter as Router,
Routes,
Route,
useNavigate
} from "react-router-dom";
import { TextField } from "#mui/material";
import { useState } from "react";
import "./ModalStyleAddProduct.css";
function ModalAddProduct({ setOpenModalAddProduct }) {
const navigate = useNavigate();
const [itemName, setItemName] = useState("");
const [itemPrice, setItemPrice] = useState("");
const navigateToDraftsPage = () => {
navigate("/draftspage");
};
return (
<div className="modalBackground3">
<div className="modalContainer3">
<div className="titleCloseBtn3">
<button
onClick={() => {
setOpenModalAddProduct(false);
}}
>
<Typography sx={{ color: "white" }}>X</Typography>
</button>
</div>
<div className="title">
<h1 className="modalTitleUp">Add New Item Product</h1>
</div>
<div className="body">
<TextField
onChange={(g1) => setItemName(g1.target.value)}
className="inputRounded"
placeholder="Item Name"
variant="outlined"
size="small"
/>
<TextField
onChange={(g2) => setItemPrice(g2.target.value)}
className="inputRounded"
placeholder="Item Price"
variant="outlined"
size="small"
sx={{ width: 100 }}
/>
</div>
<div className="footer">
<button
onClick={() => {
setOpenModalAddProduct(false);
}}
id="noBtn3"
>
Cancel
</button>
<button>Add</button>
</div>
</div>
</div>
);
}
export default ModalAddProduct;
Database source code (data.jsx):
const data = {
products: [
{
id: "1",
name: "MacBook",
price: 1400,
image: "https://picsum.photos/id/180/2400/1600"
},
{
id: "2",
name: "Old Car",
price: 2400,
image: "https://picsum.photos/id/111/4400/2656"
},
{
id: "3",
name: "W Shoes",
price: 1000,
image: "https://picsum.photos/id/21/3008/2008"
}
]
};
export default data;
Full functioning app in CodeSandbox:
https://codesandbox.io/s/addnewproductitem-button-6mtb1o?file=/src/components/modals/ModalAddProduct.jsx
App inspired and based from YT: https://www.youtube.com/watch?v=AmIdY1Eb8tY
It would indeed help a lot to gather tips and guides on how to handle data passing when it comes to plain database files which only contains a const array of objects.
Thank you very much!
All right... I think the best would be to use useContext or Redux, but you can also pass the props back to the parent (Main.js) from ModalAddProduct.
Where you have your "Add" button:
<button onClick={sendDataToParent}>Add</button>
now add sendDataToParent function in this file.
const sendDataToParent = () => {
props.sendData(itemName, itemPrice);
};
We are passing all the information we want back to the parent. We could also pass it as an object.
Now back in our main.js file:
const [updatedProductsList, addProd] = useState(products);
And we will use updatedProductsList in our map function at the bottom. On the first render, it will display your 3 products you have.
And last but not least... Remember the sendData we send (props.sendData)? Let's update our updatedProductsList that we declared using the useState hook.
const sendData = (name, price) => {
addProd([...updatedProductList, { name, price }]);
};
Let's "listen" for sendData from the child. As soon as it is triggered the sendData in the parent will be triggered.
<ModalAddProduct
sendData={sendData}
setOpenModalAddProduct={setModalOpenAddProduct}
/>
Now you need to add an image field for consistency. Ideally, as mentioned before redux could be a good tool to use so you could pass your dummy data there and update them as you go along.
Please note if you try to add the new item to the cart it will show an error. It is because the price on your form is a string, not a number. BTW, there is a concept called props drilling in react, hence why redux or useContext are preferable. I hope this is all clear :)
https://codesandbox.io/s/addnewproductitem-button-forked-8qdx9f?file=/src/components/modals/ModalAddProduct.jsx

How to properly display the object value to another separate page component after a button is clicked in React? (From object form to proper form)

I have created a functionality for my "menu item buttons" to display their assigned data through an object format into a separate page component called "SidePage" (gained help also here in StackOverflow). What I am not sure is that if this functionality that I have created is a formal or effective one since I am planning to implement a backend functionality into my full main app. The functionality involves useState, onClick, and onSelected.
I used props to hold the resulting data after the "menu item button" is clicked.
(Chicken Button should be clicked first in order to display the menu item buttons)
SidePage source code:
import * as React from "react";
import { Typography } from "#mui/material";
export default function SidePage(props) {
return (
<div>
<Typography sx={{ mt: 20 }}>Menu Item Details:</Typography>
<div>{props.menuItemDetails}</div>
</div>
);
}
HomeOrderPage (main page) source code:
import * as React from "react";
import { useState } from "react";
import { Stack } from "#mui/material";
import ButtonCategoryStyle from "./ButtonCategoryStyle";
import ChickenButtons from "./categoryButtons/ChickenButtons";
import SidePage from "./SidePage";
const categories = ["Chicken"];
export default function HomeOrderPage() {
const [myCategory, setMyCategory] = useState("");
const [food, setFood] = useState(null);
return (
<div>
<Stack spacing={0} direction="row">
{categories.map((category) => (
<ButtonCategoryStyle
title={category.toLocaleUpperCase()}
key={category}
onClick={() => setMyCategory(category)}
/>
))}
</Stack>
<div>
<p>
{myCategory === "Chicken" && <ChickenButtons onSelected={setFood} />}
</p>
{/* ------------------------------------------------------------------------------------------------ */}
</div>
{/* Displays object after menu item is clicked and renders the side page to show the menu item details:: */}
<div
style={{
backgroundColor: "blue"
}}
>
<SidePage
menuItemDetails={
food && <pre sx={{ ml: 120 }}>{JSON.stringify(food, null, 2)}</pre>
}
/>
</div>
</div>
);
}
Full source code (CodeSandbox): https://codesandbox.io/s/nice-stack-question-page-component-data-transfer-ejebxz?file=/src/HomeOrderPage.jsx
What I also want is to store the property values of the object into variables (in order to display the details of the selected menu item button properly but I am not sure how to do this since I am baffled with using this.state or still using props for this.
Hoping for all of your response as this would help me a lot with my first big React project that I am working on. Thank you very much everyone!
Since you already have props. Why copy it to state? Just keep single source of truth.

All accordions collapsed at the same time when I click on any one

I am creating accordions with reactstrap but when I wanna open one accordion all accordions collapsed
I wanna every accordion work separately
my code that I created 2 components in it
const SellerShipping = () => {
const [open, setOpen] = useState(null);
const [toggleChecked, setToggleChecked] = useState(false)
return (
<Wrapper>
<TagLine>Shipping and delivery</TagLine>
<SearchBar>
<SearchBox />
<SuggestButton>suggest a company</SuggestButton>
</SearchBar>
<AccordionWrapper className=''>
<CompanyAccordion toggleChecked={toggleChecked} setToggleChecked={setToggleChecked} open={open} setOpen={setOpen} toggleid={"1"} />
<CompanyAccordion toggleChecked={toggleChecked} setToggleChecked={setToggleChecked} open={open} setOpen={setOpen} toggleid={"2"} />
</AccordionWrapper>
</Wrapper>
)
}
and even if I write states inside the accordion file its the same result
the company accordion
import { Accordion, AccordionBody, AccordionHeader, AccordionItem } from 'reactstrap';
import styled from 'styled-components';
import ReactSwitch from 'react-switch';
import { ReactComponent as EmiratesPost } from 'assets/img/logos/emirates-post.svg'
const CompanyAccordion = ({open, setOpen, toggleid, toggleChecked, setToggleChecked}) => {
const toggle = (id) => {
open === id ? setOpen() : setOpen(id);
console.log(id,open);
};
return (
<Wrapper>
<SubWrapper>
<EmiratesPost style={{maxWidth:"100%"}} />
<SwitchComponent>
<ReactSwitch onChange={()=>setToggleChecked(!toggleChecked)} checked={toggleChecked}/>
</SwitchComponent>
</SubWrapper>
<AccordionWrapper>
<Accordion open={open} toggle={toggle}>
<AccordionItem style={{border:"0px"}} >
<AccordionHeader targetId={toggleid}>
Accordion Item 1
</AccordionHeader>
<AccordionBody accordionId={toggleid}>
<strong>This is the first item's accordion body.</strong>
You can modify any of this with custom CSS or overriding our default variables. It's also worth noting that just about any HTML can go within the <code>.accordion-body</code>, though the transition does limit overflow.
</AccordionBody>
</AccordionItem >
</Accordion>
</AccordionWrapper>
</Wrapper>
);
}
the result
the result
you have used the same state toggleChecked for all Accordions so they are behaving identically use different states of all the Accordions you wish to have separate behaviour

ReactJS + Ant Design: hook up two AntD components

I am a newbie and I have an issue that I need to connect two components(slider and radio buttons) from Ant design in React and make them collaborate together. So if I choose one of the options of the radio button, I want the slider to adjust the choice and conversely. For example, if I choose on the radio button year 2022 I want the to slider move to the right, and for example, if I choose 2022 on the slider I want to have checked radio button value 2022, and so on... I tried to put them into some conditions, but really don't know what to do with them. And also to have radio buttons in same width as slider.
import React from "react";
import { Radio, Slider } from "antd";
const App = () => {
const [currentValueRadio, setcurrentValueRadio] = React.useState(1);
const [currentValue, setCurrentValue] = React.useState();
return (
<>
<Radio.Group
onChange={(e) => {
console.log("radio checked", e.target.value);
setcurrentValueRadio(e.target.value);
}}
value={currentValueRadio}
>
<Radio value={1}>2021</Radio>
<Radio value={2}>2022</Radio>
</Radio.Group>
<Slider
defaultValue={2021}
min={2021}
max={2022}
style={{ width: 240 }}
onChange={(value) => {
console.log(currentValue);
setCurrentValue(value);
}}
/>
</>
);
};
https://codesandbox.io/embed/radio-group-antd-4-19-4-forked-134cps?fontsize=14&hidenavigation=1&theme=dark
You need to add the state being controlled as a 'value' prop to both components, to have them syncronised.
<Slider
value={currentValueRadio} // <- add a value prop
defaultValue={2021}
...
Adding the value prop in your example will have both components react to the same state value.
However, since the Radio components set the value to 1 or 2, and the range on the Slider is from 2021 to 2022, you may not see the result you're looking for. Perhaps change the Radio values to 2021 and 2022 respectively.

Modal does not hide FullCalendar elements

I'm using FullCalendar in React and need a modal to pop-up when a button is clicked.
The issue I'm experiencing is that certain elements of the calendar do not fade behind the overlay and are instead at full opacity and in front of the modal.
Specifically, in dayGridMonth view the elements are the internal grid that makes up the calendar, the date numbers in each cell, the events and the current day highlight (i.e. all internal calendar elements). However, the toolbar header, the day text and the external border are all hidden as desired.
When in listDay or listWeek views, only the active button in the toolbar is misbehaving.
I've tried implementing a plain JS modal and also using react-modal. The issue persists in both.
import { useState } from "react";
import TaskModal from './TaskModal';
function Calendar (props) {
const [modalOpen, setModalOpen] = useState(false);
function addEvent () {
setModalOpen(true);
}
return (
<div>
<FullCalendar
headerToolbar={{
start: "addEvent",
center: "foo",
end: "bar",
}}
customButtons={{
addEvent: {
text: "+",
click: addEvent,
}
}}
some other props...
>
<TaskModal modalOpen={modalOpen} setModalOpen={setModalOpen} />
</div>
);
}
import Modal from "react-modal";
export default function TaskModal (props) {
Modal.setAppElement("#root");
return (
<Modal
isOpen={props.taskModalVisible}
onRequestClose={false}
contentLabel="My dialog"
>
<div>My modal dialog.</div>
<button onClick={() => props.setTaskModalVisible(false)}>Close modal</button>
</Modal>
);
}
The issue was simply that the problematic elements had a very high CSS z-index (as high as 999). This was resolved by adding className and overlayClassName props to the Modal. Then giving these classes an even higher z-index so that everything else would be behind.

Resources