here we create bookings(Project 2, Project 7, Project 6..) as events and show holiday name (New Year's..) as summary text.
enter image description here
I'm trying to remove the space between summary text and bookings by using eventItemLineHeight that removes the space but overlap the other bookings.
enter image description here
Showing holiday name using getSummaryFunc.
Also if there is no holiday eg, Tue 1/3, how to remove the above booking space.
Here's the code that shows users, bookings and holiday text on calendar.
/* shows users list in calendar */
useEffect(() => {
requestAllUsers("get", `plan/users/all?userId=${userId}&today=${today}`);
getAll();
}, []);
useEffect(() => {
if (responseAllUsers && responseAllUsers.status && responseAllUsers.data) {
let sd = new SchedulerData(
new Date(),
ViewTypes.Custom1,
false,
false,
{
schedulerWidth: "100%",
besidesWidth: 20,
schedulerMaxHeight: height - 270,
agendaResourceTableWidth: 160,
agendaMaxEventWidth: 100,
eventItemHeight: 5,
eventItemLineHeight: 75,
nonWorkingTimeHeadBgColor: "#f7f7f7",
nonWorkingTimeBodyBgColor: "#f7f7f7",
resourceName: "People",
weekCellWidth: 180,
monthCellWidth: 180,
yearCellWidth: 180,
quarterCellWidth: 180,
nonAgendaSlotMinHeight: 90,
dayResourceTableWidth: 200,
weekResourceTableWidth: 200,
monthResourceTableWidth: 200,
quarterResourceTableWidth: 200,
yearResourceTableWidth: 240,
customResourceTableWidth: 200,
views: [],
},
{
isNonWorkingTimeFunc: isNonWorkingTime,
getCustomDateFunc: getCustomDate,
getSummaryFunc: getSummary,
getScrollSpecialMomentFunc: getScrollSpecialMoment,
}
);
let resources = [];
if (responseAllUsers.data && responseAllUsers.data.length > 0) {
let allUser = [];
for (var k = 0; k < responseAllUsers.data.length; k++) {
const option = {
value: responseAllUsers.data[k].id,
label: responseAllUsers.data[k].name,
};
const resource = {
id: "r" + k,
userId: responseAllUsers.data[k].id? responseAllUsers.data[k].id: "",
name: "Resource" + k,
username: responseAllUsers.data[k].name? responseAllUsers.data[k].name: "",
access_role: responseAllUsers.data[k].access_role? responseAllUsers.data[k].access_role: "",
department: responseAllUsers.data[k].department? responseAllUsers.data[k].department: "",
job_role: responseAllUsers.data[k].job_role? responseAllUsers.data[k].job_role: "",
avatar: responseAllUsers.data[k].avatar? responseAllUsers.data[k].avatar: "",
email: responseAllUsers.data[k].email? responseAllUsers.data[k].email: "",
holidays: responseAllUsers.data[k].holidays? responseAllUsers.data[k].holidays : [],
daysOff: responseAllUsers.data[k].workDays,
can_edit_all_bookings: responseAllUsers.data[k].can_edit_all_bookings? responseAllUsers.data[k].can_edit_all_bookings: 0,
can_edit_project_bookings: responseAllUsers.data[k].can_edit_project_bookings? responseAllUsers.data[k].can_edit_project_bookings: 0,
can_edit_department_bookings: responseAllUsers.data[k].can_edit_department_bookings? responseAllUsers.data[k].can_edit_department_bookings: 0,
can_edit_own_bookings: responseAllUsers.data[k].can_edit_own_bookings? responseAllUsers.data[k].can_edit_own_bookings: 0,
holidayLanguage: responseAllUsers.data[k].holidayLanguage? responseAllUsers.data[k].holidayLanguage: "",
};
allUser.push(option);
resources.push(resource);
}
setBySearchPerson(allUser);
let filteredData = [];
if (searchBy == "People" && searchValue != "" && searchValue != null) {
if (allUser && allUser.length > 0) {
filteredData = allUser.filter(
(person) =>
person.label.toLowerCase() == searchValue.toLowerCase()
);
let pSearch = [];
if (filteredData && filteredData.length > 0) {
for (var i = 0; i < filteredData.length; i++) {
pSearch.push(filteredData[i].value);
}
}
setPersonSearch(pSearch);
setSelectedSearchPersonOption(filteredData);
getFilteredData("","","","","","","",pSearch,"","","","","","");
}
} else {
setPersonSearch();
setSelectedSearchPersonOption([]);
}
}
sd.setResources(resources);
setSchedulerData(sd);
setViewModel(sd);
}
}, [responseAllUsers, searchBy, searchValue]);
/* holiday text in calendar */
const getSummary = (
schedulerData,
headerEvents,
slotId,
slotName,
headerStart,
headerEnd
) => {
const date = moment(headerStart).format("YYYY-MM-DD");
const data = schedulerData.getSlotById(slotId);
schedulerData.config.summaryPos = 2;
if (eventHolidayContentRef && eventHolidayContentRef.current && eventHolidayContentRef.current[date]) {
const isHoliday = eventHolidayContentRef.current[date].find((i) => i.id == data.id);
if (isHoliday && isHoliday.name) {
return {
text: (
<>
<div
title={
data.holidayLanguage == "english"
? isHoliday.name + " (" + isHoliday.types + " holiday)"
: isHoliday.localName + " (" + isHoliday.types + " holiday)"
}
className="planHolidayName"
>
{data.holidayLanguage == "english"
? stringLimit2(isHoliday.name)
: stringLimit2(isHoliday.localName)}
</div>
</>
),
fontSize: "10px",
marginRight: "200px",
};
} else {
return {};
}
} else {
return {};
}
};
/* Bookings on calendar */
const eventItemTemplateResolver = (
schedulerData,
event,
bgColor,
isStart,
isEnd,
mustAddCssClass,
mustBeHeight,
agendaMaxEventWidth
) => {
let divStyle = {
backgroundColor: bgColor,
height: 70,
};
if (
["Tentative", "Needs Approval"].includes(event.bookingStatus) ||
event.leaveType
) {
divStyle.background = `repeating-linear-gradient(135deg,
${bgColor},
white 1px)`;
}
if (!!agendaMaxEventWidth)
divStyle = {
...divStyle,
maxWidth: agendaMaxEventWidth,
};
return (
<div
key={event.id}
id={event.id}
className={mustAddCssClass}
style={divStyle}
>
{event.type == "booking" ? (
<div className="cellbox">
<div className="cellbox-header">
<span className="cellbox-proname">{event.project}</span>
<span className="cellbox-cusname">{event.customer}</span>
</div>
<div className="cellbox-footer">
<div className="row g-1 align-items-center">
<div className="col-auto">
<span className="cellbox-hour">
{convertHoursToComma(event.bookingHours) + "h"}
</span>
</div>
{event.bookingType == "Billable" ? (
<div className="col-auto">
<i
className="bi bi-currency-dollar text-black fs-6"
data-bs-custom-class="tooltip-dark"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="Billable"
></i>
</div>
) : event.bookingType == "Non-billable" ? (
<div className="col-auto">
<i
className="bi bi-currency-dollar fs-6 text-danger"
data-bs-custom-class="tooltip-dark"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="Non-billable"
></i>
</div>
) : event.bookingType == "Internal" ? (
<div className="col-auto">
<i
className="bi bi-info fs-7 fs-6 text-white"
data-bs-custom-class="tooltip-dark"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="Internal"
></i>
</div>
) : (
""
)}
{event.bookingStatus == "Confirmed" ? (
<div className="col-auto">
<i
className="bi bi-check-circle fs-7 text-white"
data-bs-custom-class="tooltip-dark"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="Confirmed"
></i>
</div>
) : event.bookingStatus == "Needs Approval" ? (
<div className="col-auto">
<i class="bi_icons" title="Needs Approval">
<svg
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M5.26303 7.05528L7.19613 8.98838L10.418 5.12218"
stroke="#ffffff"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M9.375 17C13.5862 17 17 13.5862 17 9.375C17 5.16383 13.5862 1.75 9.375 1.75C5.16383 1.75 1.75 5.16383 1.75 9.375C1.75 13.5862 5.16383 17 9.375 17Z"
stroke="#ffffff"
stroke-width="2"
/>
<path
d="M13 13L10 10M13 10L10 13"
stroke="#ffffff"
stroke-width="2"
stroke-linecap="round"
/>
</svg>
</i>
</div>
) : event.bookingStatus == "Tentative" ? (
<div className="col-auto">
<i
className="bi bi-question-circle fs-7 text-white"
data-bs-custom-class="tooltip-dark"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="Tentative"
></i>
</div>
) : (
""
)}
{event.isRepeatable == 1 && (
<div className="col-auto">
<i
className="bi bi-arrow-repeat fs-4 text-white"
data-bs-custom-class="tooltip-dark"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="Repeated Booking"
></i>
</div>
)}
</div>
</div>
</div>
) : event.type == "timeOff" ? (
<div className="cellbox">
<div className="cellbox-header">
<span className="cellbox-proname">{event.leaveType}</span>
</div>
<div className="cellbox-footer">
<div className="row g-1 align-items-center">
<div className="col-auto">
<span className="cellbox-hour">
{convertHoursToComma(event.timeOffHour) + "h"}
</span>
</div>
</div>
</div>
</div>
) : (
""
)}
</div>
);
};
If anyone has any input it would be helpful.
Trying to remove space between summary text and event item in react-big-scheduler
Related
I'm trying to change the className of each component Card i have by clicking on them. If one is selected, the others one will not be and have their default className.
How my component Card is called :
const UserBookingData = ({ bookings }: any) => {
return (
<div className="col-span-6 py-2">
{bookings?.map((booking: any) => (
<Card key={`cardKey${nanoid()}`} booking={booking} />
))}
</div>
)
}
component Card :
const Card = ({ booking} : any) => {
const bookingDate = moment(booking?.startAt);
const [selected, setSelected] = useState(false);
const getBookingRef = (ref: string) => {
setSelected(false);
zusContext.setState({
bookingRef: ref,
bookingLoaded: true
})
setSelected(true);
};
return <div onClick={() => getBookingRef(booking?.ref)} className={`my-1 py-3 px-3 flex items-center rounded-lg ${selected ? 'cursor-default bg-white-dark' : 'bg-white group hover:bg-white-dark cursor-pointer'}`}>
<div><svg className="w-14 fill-current text-white-dark4" viewBox="0 0 150 150"><path d="M 75, 75 m -75, 0 a 75,75 0 1,0 150,0 a 75,75 0 1,0 -150,0"/></svg></div>
<div className="flex items-center justify-between w-full">
<div className={`ml-3 ${selected ? '' : 'flex flex-col'}`}>
<div className="flex">
<div className={`text-blue text-xs px-2 py-[3px] rounded-md ${selected ? 'bg-white' : 'bg-blue-light group-hover:bg-white' }`}>{bookingDate.utc().format('DD MMM YYYY')}</div>
</div>
<div className='truncate text-sm font-medium pt-1 max-w-[160px]'>{booking?.space?.title}</div>
<div className="text-sm text-dark text-[13px]">{booking?.space?.host?.firstname}</div>
</div>
<div><svg className="ml-3 mr-1 w-2 fill-current text-blue" viewBox="0 0 150 150"><path d="M 75, 75 m -75, 0 a 75,75 0 1,0 150,0 a 75,75 0 1,0 -150,0"/></svg></div>
</div>
</div>
}
I tried with the hook selected, but the problem is, if i clic on one, it doesn't go back to his default className when i select another one.
I think it might be because it's not re rendered ?
the best approach here is to manage the state at the parent component(UserBookingData) and use booking.ref to know which card is selected:
// UserBookingData
const UserBookingData = ({ bookings }: any) => {
const [selected, setSelected] = useState("");
return (
<div className="col-span-6 py-2">
{bookings?.map((booking: any) => (
<Card
key={`cardKey${nanoid()}`}
booking={booking}
selected={selected}
setSelected={setSelected}
/>
))}
</div>
)
}
// Card component from codesandbox
const Card = ({ booking, selected, setSelected }: any) => {
const color = selected === booking.ref ? "green" : "red";
const getBookingRef = (event: any) => {
setSelected(booking.ref);
console.log(event.currentTarget.className);
};
return (
<div
style={{ marginTop: "10px", backgroundColor: `${color}` }}
onClick={getBookingRef}
className={`default ${selected ? "green" : "red"}`}
>
{booking.space.host.firstname}
</div>
);
};
export default Card;
you can see a working example here
I would like to change the background color from the DIV when I click without affecting other buttons in the same line. I hope you could help me.. THank you!
For example when I click on the first DIV Developers, the background color change, however, it affects the other buttons, I want to affect only the button I click to change the background color.
import React, { useState } from 'react';
import './navbar.css';
import Logo from '../../assets/img/ubuntu.jpg'
import { Dropdown } from '../ui/dropdown/Dropdown';
export const Navbar = () => {
const [isOpen, setIsOpen] = useState(false);
const [style, setStyle] = useState(true);
const [styleIcon, setStyleIcon] = useState(true);
const [isActive, setIsActive] = useState(false);
const handleClick = () => {
setIsActive(current => !current);
setIsOpen(!isOpen);
};
const toggling = () => {
setIsOpen(!isOpen);
changeStyle();
changeStyleIcon();
};
const changeStyle = () => {
setStyle(!style);
};
const changeStyleIcon = () => {
setStyleIcon(!styleIcon);
};
return (
<>
<div className="div_main_navbar">
<div className="div_main_title">
<div className="div_main_button">
<img className="img_logo" src={Logo} alt="logo" />
</div>
<div
style={{
backgroundColor: isActive ? 'salmon' : '',
color: isActive ? 'white' : '',
}}
onClick={handleClick}
>
<strong className="label_strong">Enterprise</strong>
<div className="div_icon">
<i className={styleIcon ? "fa-solid fa-angle-down" : "fa-solid fa-angle-up"} ></i>
</div>
</div>
<div
style={{
backgroundColor: isActive ? 'salmon' : '',
color: isActive ? 'white' : '',
}}
onClick={handleClick}
>
<strong className="label_strong">Developer</strong>
<div className="div_icon">
<i className={styleIcon ? "fa-solid fa-angle-down" : "fa-solid fa-angle-up"} ></i>
</div>
</div>
<div className={style ? 'div_main_button' : 'div_main_button_change_color'} onClick={toggling}>
<strong className="label_strong">Community</strong>
<div className="div_icon">
<i className={styleIcon ? "fa-solid fa-angle-down" : "fa-solid fa-angle-up"} ></i>
</div>
</div>
<div className={style ? 'div_main_button' : 'div_main_button_change_color'} onClick={toggling}>
<strong className="label_strong">Download</strong>
<div className="div_icon">
<i className={styleIcon ? "fa-solid fa-angle-down" : "fa-solid fa-angle-up"} ></i>
</div>
</div>
</div>
<div className="div_main_search_signin">
<div className="div_main_se_in">
<strong className="label_strong">Search</strong>
</div>
<div className="div_main_se_in">
<strong className="label_strong">Sign in</strong>
</div>
</div>
</div>
{
isOpen && (
<Dropdown/>
)
}
</>
)
}
You should have a number state instead of a boolean state for isActive
const [isActive, setIsActive] = useState(); //leave it empty as no active buttons initially
And then you should have another constant variable for restrict button state values
const BUTTONS = {
enterprise: 1,
developer: 2,
}
Modify handleClick accordingly
const handleClick = (buttonId) => {
setIsActive(buttonId);
setIsOpen(!isOpen);
};
The last part is integrating button ids with your div elements and adding conditional renderings based on isActive value
<div
style={{
backgroundColor: isActive === BUTTONS.enterprise ? 'salmon' : '',
color: isActive === BUTTONS.enterprise ? 'white' : '',
}}
onClick={() => handleClick(BUTTONS.enterprise)}
>
<strong className="label_strong">Enterprise</strong>
<div className="div_icon">
<i className={styleIcon ? "fa-solid fa-angle-down" : "fa-solid fa-angle-up"} ></i>
</div>
</div>
<div
style={{
backgroundColor: isActive === BUTTONS.developer ? 'salmon' : '',
color: isActive === BUTTONS.developer ? 'white' : '',
}}
onClick={() => handleClick(BUTTONS.developer)}
>
<strong className="label_strong">Developer</strong>
<div className="div_icon">
<i className={styleIcon ? "fa-solid fa-angle-down" : "fa-solid fa-angle-up"} ></i>
</div>
</div>
The full possible modification
import React, { useState } from 'react';
import './navbar.css';
import Logo from '../../assets/img/ubuntu.jpg'
import { Dropdown } from '../ui/dropdown/Dropdown';
const BUTTONS = {
enterprise: 1,
developer: 2,
}
export const Navbar = () => {
const [isOpen, setIsOpen] = useState(false);
const [style, setStyle] = useState(true);
const [styleIcon, setStyleIcon] = useState(true);
const [isActive, setIsActive] = useState(); //leave it empty as no active buttons initially
const handleClick = (buttonId) => {
setIsActive(buttonId);
setIsOpen(!isOpen);
};
const toggling = () => {
setIsOpen(!isOpen);
changeStyle();
changeStyleIcon();
};
const changeStyle = () => {
setStyle(!style);
};
const changeStyleIcon = () => {
setStyleIcon(!styleIcon);
};
return (
<>
<div className="div_main_navbar">
<div className="div_main_title">
<div className="div_main_button">
<img className="img_logo" src={Logo} alt="logo" />
</div>
<div
style={{
backgroundColor: isActive === BUTTONS.enterprise ? 'salmon' : '',
color: isActive === BUTTONS.enterprise ? 'white' : '',
}}
onClick={() => handleClick(BUTTONS.enterprise)}
>
<strong className="label_strong">Enterprise</strong>
<div className="div_icon">
<i className={styleIcon ? "fa-solid fa-angle-down" : "fa-solid fa-angle-up"} ></i>
</div>
</div>
<div
style={{
backgroundColor: isActive === BUTTONS.developer ? 'salmon' : '',
color: isActive === BUTTONS.developer ? 'white' : '',
}}
onClick={() => handleClick(BUTTONS.developer)}
>
<strong className="label_strong">Developer</strong>
<div className="div_icon">
<i className={styleIcon ? "fa-solid fa-angle-down" : "fa-solid fa-angle-up"} ></i>
</div>
</div>
<div className={style ? 'div_main_button' : 'div_main_button_change_color'} onClick={toggling}>
<strong className="label_strong">Community</strong>
<div className="div_icon">
<i className={styleIcon ? "fa-solid fa-angle-down" : "fa-solid fa-angle-up"} ></i>
</div>
</div>
<div className={style ? 'div_main_button' : 'div_main_button_change_color'} onClick={toggling}>
<strong className="label_strong">Download</strong>
<div className="div_icon">
<i className={styleIcon ? "fa-solid fa-angle-down" : "fa-solid fa-angle-up"} ></i>
</div>
</div>
</div>
<div className="div_main_search_signin">
<div className="div_main_se_in">
<strong className="label_strong">Search</strong>
</div>
<div className="div_main_se_in">
<strong className="label_strong">Sign in</strong>
</div>
</div>
</div>
{
isOpen && (
<Dropdown/>
)
}
</>
)
}
So what I have done is isolate the clicked state of the div within a separate functional component. This way one click would not affect the other.
You can define this component as
// please provide appropriate component name
const HandleClickDiv = ({ heading, styleIcon, isOpen, setIsOpen }) => {
const [clicked, setClicked] = useState(false);
const onClick = () => {
setClicked(!clicked);
setIsOpen(!isOpen);
};
return (
<div
style={{
backgroundColor: clicked ? 'salmon' : '',
color: clicked ? 'white' : '',
}}
onClick={onClick}
>
<strong className="label_strong">{heading}</strong>
<div className="div_icon">
<i
className={
styleIcon ? 'fa-solid fa-angle-down' : 'fa-solid fa-angle-up'
}
></i>
</div>
</div>
);
};
The component is called as :
{
handleClickHeadings.map((heading) => {
return (
<HandleClickDiv
heading={heading}
styleIcon={styleIcon}
isOpen={isOpen}
setIsOpen={setIsOpen}
/>
);
});
}
Following is the rest of your code
import React, { useState } from 'react';
import './navbar.css';
import Logo from '../../assets/img/ubuntu.jpg';
import { Dropdown } from '../ui/dropdown/Dropdown';
export const Navbar = () => {
const [isOpen, setIsOpen] = useState(false);
const [style, setStyle] = useState(true);
const [styleIcon, setStyleIcon] = useState(true);
const toggling = () => {
setIsOpen(!isOpen);
changeStyle();
changeStyleIcon();
};
const changeStyle = () => {
setStyle(!style);
};
const changeStyleIcon = () => {
setStyleIcon(!styleIcon);
};
const handleClickHeadings = ['Enterprise', 'Developer'];
return (
<>
<div className="div_main_navbar">
<div className="div_main_title">
<div className="div_main_button">
<img className="img_logo" src={Logo} alt="logo" />
</div>
{handleClickHeadings.map((heading) => {
return (
<HandleClickDiv
heading={heading}
styleIcon={styleIcon}
isOpen={isOpen}
setIsOpen={setIsOpen}
/>
);
})}
<div
className={
style ? 'div_main_button' : 'div_main_button_change_color'
}
onClick={toggling}
>
<strong className="label_strong">Community</strong>
<div className="div_icon">
<i
className={
styleIcon ? 'fa-solid fa-angle-down' : 'fa-solid fa-angle-up'
}
></i>
</div>
</div>
<div
className={
style ? 'div_main_button' : 'div_main_button_change_color'
}
onClick={toggling}
>
<strong className="label_strong">Download</strong>
<div className="div_icon">
<i
className={
styleIcon ? 'fa-solid fa-angle-down' : 'fa-solid fa-angle-up'
}
></i>
</div>
</div>
</div>
<div className="div_main_search_signin">
<div className="div_main_se_in">
<strong className="label_strong">Search</strong>
</div>
<div className="div_main_se_in">
<strong className="label_strong">Sign in</strong>
</div>
</div>
</div>
{isOpen && <Dropdown />}
</>
);
};
Note: the array of headings const handleClickHeadings = ['Enterprise', 'Developer']; allows you to loop through them and render the same div with different heading. This is possible for these 2 divs since everything else in them was exactly the same
this is the hole component
import React ,{useState} from 'react';
import useSWR from 'swr'
import Axios from "axios"
import Nav from '../home/nav';
import './mission.css';
import '../home/Cards.css';
import CardItem from '../home/CardItem';
import SweetAlert from 'sweetalert2-react';
const PostuleMission=(props)=>{
const [show,setShow]=useState(false);
const [donnee,setDonnee]=useState({ missions: [] });
const [acceper,setEstaccepe]=useState(0);
const handelAccept =(mission)=>{
//alert("http://localhost:8080/BricoAccept/"+props.user.id+"/"+mission+"/1")
Axios.put("http://localhost:8080/BricoAccept/"+props.user.id+"/"+mission+"/1")
.then(res=>{
setShow(true)
})
.catch(err =>{
alert(err)
})
}
const fetcher = (url) => fetch(url).then(res =>{return res.json()} )
const { data, error } = useSWR('http://localhost:8080/bricoleurs/'+props.user.id, fetcher)
if (error) return (
<div className="d-flex flex-column">
<img alt="..." src="/assets/logo.png" style={{height:"100px",width:"100px"}} className="logo" />
<p className="text-danger">failed to load</p>
</div>);
if (!data) {return (
<div>
<img alt="..." src="/assets/logo.png" className="logo" />
<div className="d-flex flex-row" style={{position:"absolute",left:"50%",right:"50%",top:"45%" }}>
<div className="spinner-grow text-primary" role="status">
<span className="visually-hidden">Loading...</span>
</div>
<div className="spinner-grow text-secondary" role="status">
<span className="visually-hidden">Loading...</span>
</div>
<div className="spinner-grow text-success" role="status">
<span className="visually-hidden">Loading...</span>
</div>
<div className="spinner-grow text-danger" role="status">
<span className="visually-hidden">Loading...</span>
</div>
<div className="spinner-grow text-warning" role="status">
<span className="visually-hidden">Loading...</span>
</div>
<div className="spinner-grow text-info" role="status">
<span className="visually-hidden">Loading...</span>
</div>
<div className="spinner-grow text-light" role="status">
<span className="visually-hidden">Loading...</span>
</div>
<div className="spinner-grow text-dark" role="status">
<span className="visually-hidden">Loading...</span>
</div>
</div>
</div>);}
//les cartes
setDonnee(data.missions)
//const Missionss = (data.missions)?((data.missions[0].accepterBrico)?data.missions: []):[];
const Missions= data.missions.map((item)=>{
console.log("hello"+ item.id);
// setEstaccepe(0)
/* Axios.get("http://localhost:8080/accepterbrico/"+props.user.id+"/"+item.id)
.then(res=>{
*/
// alert(item.accepterBrico[0].bricoId)
/*
if(item.accepterBrico) {
for( let i=0;i < item.accepterBrico.length;i++){
if(item.accepterBrico[i].bricoId==props.user.id && item.accepterBrico[i].missionId ==item.id){
if(item.accepterBrico[i].clientAccept==1 && item.accepterBrico[i].bricoAccept==1 ){
setEstaccepe(1) ;
}
else if( item.accepterBrico[i].clientAccept==1 && item.accepterBrico[i].bricoAccept==0 ){
setEstaccepe(2) ;
}
else{
setEstaccepe(0) ;
}
}
}}
*/
const id=item.id;
return(
<div className='cards'>
<div className='cards__container'>
<CardItem
key={item.id}
src={item.images}
text={item.mission_description}
label={item.titre_mission}
path='/comment'
/>
{(acceper==2)? <div className="d-flex flex-row align-items-around p-3">
<button onClick={()=>handelAccept(item.id)} className="btn btn-outline-success">Accepter</button>
<button className="btn btn-outline-danger">Refuser</button>
</div>:((acceper==1)?<div style={{color:"green",fontSize:"2em"}} ><p>Vous l'avais accepté</p></div>:<div style={{color:"red",fontSize:"2em"}} >Pas de réponse</div>)}
</div>
</div>
)
/* })
.catch(err =>{
alert(" inside "+err)
})*/
}
);
return(
<div >
<div id="postulemission"></div>
<Nav data={props.user} />
<div id="postulebox">
<h1>MinuteBlog</h1>
<SweetAlert
show={show}
title="Success"
icon='warning'
text="Congratulations vous avez bien obtenu la mission"
onConfirm={() => {
setShow(false)
}}
/>
{Missions}
</div>
</div>
);
}
export default PostuleMission;
i have a problem in my react code
when i use a loop function( so i can get the data from a list of object that i gave to the map) the map method doesn't read the data that i send to it anymore
this's the map :
enter code
const Missions = data.missions.map((item) => {
if (item.accepterBrico.length > 0) {
for (let i=0; i < item.accepterBrico.length; i++) {
if (item.accepterBrico[i].bricoId == props.user.id && item.accepterBrico[i].missionId == item.id) {
if (item.accepterBrico[i].clientAccept == 1 && item.accepterBrico[i].bricoAccept == 1) {
dosomething;
}
}
}
}
return (<div>..... </div>)
});
here is what the data sent to the map :
{
"id": 591,
"descriptionProfil": null,
"adresse": "harchi",
"phone": "",
"missions": [
{
"id": 586,
"titre_mission": "client#gmail.com",
"state": "Urgent",
"
"bricoleur_choisi": 0,
"idmission": 0,
"accepterBrico": [{
"id": 603,
"bricoId": 591,
"missionId": 597,
"clientAccept": 0,
"bricoAccept": 0
}]
},
details detailsdetailsdetailsdetailsdetailsdetailsdetailsdetails
Issue
All the error is saying is that on at least one of your component renders is that data.missions is not defined. I suspect it is on the initial render because you've not defined accurate enough initial state.
Solution(s)
You can define better initial state that matches what you are attempting to render on the initial render cycle. { missions: [] } as initial data state value would be sufficient in ensuring data.missions is defined and mappable on the initial render cycle.
const [data, setData] = useState({ missions: [] });
You can use a guard clause or Optional Chaining (otherwise known as null-checks) to guard against accessing into potentially null or undefined objects.
const Missions = data.missions && data.missions.map((item) => { .... });
or
const Missions = data.missions?.map((item) => { .... });
or provide a fallback value
const Missions = (data.missions || []).map((item) => { .... });
I am designing a responsive mega navigation bar using reactjs. It's working for desktop device but on mobile view, I could not able to show or hide sub menu when its associated parent menu is clicked. This is what I am trying to do
const menus = [
{ id: 1, name: "Home", link: "/" },
{
id: 3,
name: "New",
children: [{ id: 1, name: "New Arrival", link: "/new" }]
},
{
id: 2,
name: "Shop",
children: [
{
id: 1,
name: "Men's Fashion",
children: [
{
id: 1,
name: "Polo",
link: "/polo"
},
{ id: 2, name: "Tees", link: "/tees" }
]
},
{
id: 2,
name: "Women Fashion",
children: [
{
id: 1,
name: "Shorts",
link: "/shorts"
},
{
id: 2,
name: "Tees",
link: "/women/tees"
}
]
}
]
}
];
const MegaMenu = () => {
const [active, setActive] = React.useState(false);
const [toggle, setToggle] = React.useState(false);
const [activeMenuName, setActiveMenuName] = React.useState("");
const handleMainMenuClick = () => {
setActive(!active);
};
const toggleDrawer = () => {
setToggle(!toggle);
};
const hideSubMenu = () => {
setActive(!active);
};
const handleMenuName = (menuName) => {
setActiveMenuName(menuName);
};
return (
<>
<header className="header">
<div className="container">
<div className="row v-center">
<div className="header-item item-left">
<div className="logo">
Brand
</div>
</div>
{/* menu start here */}
<div className="header-item item-center">
<div
className={`menu-overlay ${toggle ? "active" : ""}`}
onClick={toggleDrawer}
></div>
<nav className={`menu ${toggle ? "active" : ""}`}>
<div className={`mobile-menu-head ${toggle ? "active" : ""}`}>
<div className="go-back" onClick={hideSubMenu}>
Back
</div>
<div className="current-menu-title">{activeMenuName}</div>
<div className="mobile-menu-close" onClick={toggleDrawer}>
×
</div>
</div>
<ul className="menu-main" onClick={handleMainMenuClick}>
{menus.map((menu) => {
return (
<li
key={menu.id}
className={
menu.children ? "menu-item-has-children" : ""
}
onClick={() => handleMenuName(menu.name)}
>
{menu.link ? (
<a href={menu.link}>
{menu.name} <i class="fa fa-angle-down"></i>
</a>
) : (
{menu.name}
)}
{menu.children && (
<div
className={`sub-menu mega-menu mega-menu-column-4 ${
active ? "active" : ""
}`}
>
{menu.children.map((child) => {
return (
<div
className="list-item text-center"
key={child.id}
>
<a href="#">
<img src="img/p1.jpg" alt="new Product" />
<h4 className="title">{child.name}</h4>
</a>
</div>
);
})}
</div>
)}
</li>
);
})}
</ul>
</nav>
</div>
<div className="header-item item-right">
<a href="#">
<i className="fas fa-search"></i>
</a>
<a href="#">
<i className="far fa-heart"></i>
</a>
<a href="#">
<i className="fas fa-shopping-cart"></i>
</a>
{/* mobile menu trigger */}
<div className="mobile-menu-trigger" onClick={toggleDrawer}>
<span></span>
</div>
</div>
</div>
</div>
</header>
</>
);
};
export default MegaMenu;
I have a code on sandbox as well and here it is
https://codesandbox.io/s/weathered-resonance-9n2hr?file=/src/mega-menu/index.js:50-4734
You should set active only to the activeMenuName that is clicked. Also when click go back you should reset activeMenuName to the default state. Also, I check if toggle is enabled so only onClick events are enabled and vice versa.
Check my code it's tested.
const MegaMenu = () => {
const [active, setActive] = React.useState(false);
const [toggle, setToggle] = React.useState(false);
const [activeMenuName, setActiveMenuName] = React.useState("");
const handleMainMenuClick = () => {
setActive(!active);
};
const toggleDrawer = () => {
setActiveMenuName("");
setToggle(!toggle);
};
const hideSubMenu = () => {
setActiveMenuName("");
};
const handleMenuName = (menuName) => {
setActiveMenuName(menuName);
};
const renderLiComp = (menu) =>{
if(toggle){
return <li
key={menu.id}
className={ menu.children ? "menu-item-has-children" : "" }
onClick={() =>handleMenuName(menu.name)}
>
{menu.link
? (</i>)
: ({menu.name})}
{activeMenuName && getSelectedChildren()}
</li>;
}else{
return <li
key={menu.id}
className={ menu.children ? "menu-item-has-children" : "" }
onMouseEnter={()=>handleMenuName(menu.name)}
>
{menu.link
? (</i>)
: ({menu.name})}
{activeMenuName && getSelectedChildren()}
</li>;
}
}
const renderListElements = () =>{
return menus.map(renderLiComp);
}
const renderChildren = (childs) =>{
const children = childs.map(x =>
<div className="list-item text-center" key={x.id}>
<a href="#"><img src="img/p1.jpg" alt="new Product" />
<h4 className="title">{x.name}</h4>
</a>
</div>
);
return children;
}
const getSelectedChildren = () =>{
return menus.map(x => {
let selected;
if(x.name === activeMenuName){
if(x.children){
selected = <div key={x.id} className='sub-menu mega-menu mega-menu-column-4 active'>{renderChildren(x.children)}</div>;
}else{
selected = <div key={x.id} className='sub-menu mega-menu mega-menu-column-4 active'></div>;
}
}
return selected;
});
}
return (
<>
<header className="header">
<div className="container">
<div className="row v-center">
<div className="header-item item-left">
<div className="logo">
Brand
</div>
</div>
{/* menu start here */}
<div className="header-item item-center">
<div
className={`menu-overlay ${toggle ? "active" : ""}`}
onClick={toggleDrawer}
></div>
<nav className={`menu ${toggle ? "active" : ""}`}>
<div className={`mobile-menu-head ${toggle ? "active" : ""}`}>
<div className="go-back" onClick={hideSubMenu}>
Back
</div>
<div className="current-menu-title">{activeMenuName}</div>
<div className="mobile-menu-close" onClick={toggleDrawer}>
×
</div>
</div>
<ul className="menu-main" onClick={handleMainMenuClick}>
{renderListElements()}
</ul>
</nav>
</div>
The sandbox Link https://codesandbox.io/s/nifty-cloud-kuryf?file=/src/mega-menu/index.js
I am mapping items in react, each item has a text area underneath for a comment, when I type in one box the text appears in all the boxes. I know it's because the values are the same this.state.comment but I not sure how to fix it. I have tried changing the value but i haven't figured out a way that would work since the the number of item can be 1 or 1000 depending on how many items are added.
class Content extends React.Component {
state = {
allUserItems: [],
image: null,
url: "",
video: "",
isActive: false,
isActive2: false,
comment: "",
checkInputID: null,
whichComment: null,
optionId: "",
edit_id: "",
editContent: "",
editPicture: "",
comment_id: "",
comOption_id: "",
postComment_id: "",
editComment: "",
isNotiOpen:false,
componentDidMount() {
console.log(this.props)
this.listFriendsItems()
}
listFriendsItems = () => {
API.getFriendsItems({ friends: this.props.userInfo.friends, })
.then(res => {
this.setState({ allUserItems: res.data })
console.log(res.data)
})
.catch(err => console.log(err));
}
handleChange = e => {
this.setState({
[e.target.name]: e.target.value
});
};
submitComment = (id,posters_id) => {
API.saveComment(id, {
comment: this.state.comment,
user_id: this.props.userInfo.user_ID,
user: this.props.userInfo.firstname + " " +
this.props.userInfo.lastname,
picUrl: this.state.url,
})
.then(res => console.log(res))
.catch(err => console.log(err));
let data ={
comment: this.state.comment,
user_id: this.props.userInfo.user_ID,
name: this.props.userInfo.firstname + " " +
this.props.userInfo.lastname,
userPic: this.state.url,
}
if(this.props.userInfo.user_ID !== posters_id){
this.props.saveNotification(posters_id,data,id)
}
this.setState({ comment: "", checkInputID: null }, () =>
this.listFriendItems());
}
<section className="feed ">
{this.state.allUserItems.length ? (
<div>
{this.state.allUserItems.map(content => {
return (
<div className="feed_Container" key={content._id} >
<div className="info">
<div className="uploadedInfo">
{(content.picUrl === "" ) ? <div
className="story"> </div> :
<div className="miniUpImage"><img
className={`${(content.picUrl === "") ? "story" : "miniUpImage"}`} src=
{content.picUrl} alt="uploaded pic" /></div>
}
<div className={(content.videoUrl ===
"") ? "noVideo" : "uploadedVideo"}> <VideoPost video={content.videoUrl} />
</div>
</div>
<div className="colorBackground">
<div className="updateInfo">
<div className="timenOptions">
<div className="time">{moment(content.dateCreated).calendar()}</div>
<div className=
{(this.state.optionId === content._id) ? "optionsContainer active" :
"optionsContainer"} onClick={() => this.optionsClicked(content._id)} >
<div className=
{(content.user_ID === this.props.userInfo.user_ID) ? "options" :
"noOptions"}> ...</div>
<div
className="optionsDropdown">
<ul
className="optionsList">
<div
className="edit" onClick={() => this.editPostClicked(content._id,
content.content, content.picUrl)}> Edit</div>
<div
className="delete" onClick={() => this.removePost(content._id)}>Delete</div>
</ul>
</div>
</div>
</div>
<p>{content.content}
</p>
</div>
</div>
<div className="mapComments">{content.comments.map((comment, picUrl) =>
<div key={picUrl} className="commentList"><div className="timeStamp">
{moment(comment.dateCreated).calendar()}<div>
<div className={(this.state.comOption_id ===
comment._id"comOptionsContainer active" : "comOptionsContainer"}
onClick={() => this.commentOptions(comment._id)} >
<button type="button" className={(comment.user_id ===
this.props.userInfo.user_ID) ? "commentOptions" : "noOptions"} ><i
class="far fa-comment-dots"></i></button>
<div className="comOptionsDropdown">
<ul className="optionsList">
<div className="edit" onClick={() =>
this.editCommentClicked(content._id,
comment._id, content.content, comment.comment, content.picUrl)}>
Edit</div>
<div className="delete" onClick={() => this.removeComment(content._id,
comment._id)}>Delete</div>
</ul>
</div>
</div>
</div> </div><span> <strong>{comment.user} </strong>
</span>
{comment.comment}
<div className=
{(comment.picUrl !== "") ? "commentPic" : "nocommentPic"}><img
className="commentUrl" src={comment.picUrl} alt="comment pic" /></div>
</div>
)}
<div className="responseComments">
<textarea name="comment" value={this.state.comment} onChange=
{this.handleChange} className="commentArea" placeholder="Comment"
rows="8"
cols="80" />
<div className="commentPhoto">
<button type="button" className="button photo" onClick={() => {
this.fileInput2.click(); this.getID(content._id); }}> <i className="far
fa-images"></i></button>
</div>
</div>
<div>
<input type="file" style={{ display: "none" }} onChange=
{this.handleImageSelected2} ref={fileInput => this.fileInput2 = fileInput}
/>
<img className=
{(this.state.checkInputID === content._id) ? "uploadReady active" :
"uploadReady"} src={this.state.url} alt="preview" height="40" width="50" />
<progress className= {(this.state.checkInputID === content._id) ?
"uploadReady
active" : "uploadReady"} value={this.state.progress} max="100" />
<button className= {(this.state.checkInputID === content._id) ?
"uploadReady
active" : "uploadReady"} onClick={this.handleUpload}>Upload</button>
<span
className={(this.state.checkInputID === content._id) ? "uploadReady active"
:
"uploadReady"}>File </span>
</div>
<div className="commentButtons">
<div className="replyButton" onClick={this.state.comment === "" &&
this.state.url === "" ? null : () =>
this.submitComment(content._id,content.user_ID)} ><i className="fas fa-
share">
<div className="likessection">
{(content.likes.findIndex(i => i.user_id === this.props.userInfo.user_ID) >
-1) ?
<div className="likeButton" onClick={() =>
this.removeLikes(content._id)}>Unlike</div>
: <div className="likeButton" onClick={() =>
this.handleLikes(content._id)}>
<i
className="far fa-thumbs-up"></i></div>}
</div>
</div>
</div>
</div>
</div>
);
})
}
</div>
You have to initialize state comments with the number of comments you have.
In your constructor create your comments like this, an array of comments:
this.state= {
comments: new Array(n) //n is your number of comments
}
In the handleChange function, you will have to pass the index of comment to be updated.
handleChange = (commentIndex, e) => {
const commentsUpdated = this.state.comments.map((comment, i) => {
if (i == commentIndex) return e.target.value;
else return comment;
});
this.setState({ comments: commentsUpdated });
};
And you have to update the JSX, you will need to render a collection of comments, and every comment connect with its comment state.
<div className="responseComments">
{this.state.comments.map((comment, i) => (
<textarea
name="comment"
value={comment}
onChange={e => this.handleChange(i, e)}
className="commentArea"
placeholder="Comment"
rows="8"
cols="80"
/>
))}
</div>;