I’m building a feature in my React app where users can select time slots based on the day of the week (e.g., Monday, Tuesday, etc.). This is displayed in a table made with MUI – Grid, where the columns are the days of the week and the rows are the time slots.
- Is this the most efficient way to handle adding/removing time slots?
- How can I ensure the state updates properly for both removing and adding time slots when clicking?
- Is there a better approach using react-hook-form for managing such selections?
I have already tried a lot of things, but this isn’t working properly. It’s only saving the latest selected by row., but if I select another item from the same column, it will “reset” the state and only save the latest one.
I have tried with useReducer and useState, but none of it seems to be working.
I am expecting to receive an object with the weekday name and an array with the hours:
Parent:
export const AvailabilityHours = ({
register,
setValue,
}: IAvailabilityHours) => {
const { userDetails } = useUserDetails();
const latestSessionId =
userDetails?.availability?.[userDetails?.availability?.length - 1];
const { data: sessionData, isLoading } = useQuery({
queryKey: ['availabilitySession', latestSessionId],
queryFn: () => getAvailabilitySession(latestSessionId),
enabled: !!latestSessionId,
retry: 3,
retryDelay: 2000,
});
if (isLoading) {
return <Loader />;
}
if (!sessionData) {
return <Box p={5}>Nenhuma sessão disponível</Box>;
}
const { consultationDuration, weekdays } = sessionData;
const dayHours = generateTimeSlots(consultationDuration || 60);
return (
<StyledIAvailabilityHoursBoxWrapper>
<Box display='flex' justifyContent='flex-end' pb={2}>
<Tooltip title='You can select a intire row by clicking on the first slot and dragging until the last one, but only horizontally'>
<Help />
</Tooltip>
</Box>
<StyledIAvailabilityGrid container spacing={2}>
<WeekDaysHeader isSimple />
<Grid container spacing={1} columns={8}>
{dayHours.map((hour, index) => (
<TimeSlotsRow
key={`hour-${index}`}
hour={hour}
register={register}
setValue={setValue}
availableWeekdays={weekdays}
dayHours={dayHours}
isSimple
/>
))}
</Grid>
</StyledIAvailabilityGrid>
</StyledIAvailabilityHoursBoxWrapper>
);
};
Children:
export const TimeSlotsRow = ({
hour,
register,
availableWeekdays,
isSimple,
setValue,
}: ITimeSlotsRow) => {
const [selectedSlots, setSelectedSlots] = useState<SlotState[]>([]);
useEffect(() => {
register('selectedSlots');
}, [register]);
const weekDays = generateWeekDays();
const isDayAvailable = (day: Date) => {
const dayName = format(day, 'EEEE');
return availableWeekdays.includes(dayName);
};
const slotIdFormat = (day: Date, time: string) => {
const dayName = format(day, 'EEEE');
return { dayName, time };
};
const isSlotSelected = (dayName: string, time: string) => {
const day = [].find((d) => d.weekday === dayName);
return day ? day.slots.includes(time) : false;
};
const handleSlotClick = (dayName: string, time: string) => {
const updatedSlots = [...selectedSlots];
const daySlotIndex = updatedSlots.findIndex(
(slot) => slot.dayName === dayName
);
if (daySlotIndex > -1) {
const daySlot = updatedSlots[daySlotIndex];
if (daySlot.slots.includes(time)) {
daySlot.slots = daySlot.slots.filter(
(slotTime: string) => slotTime !== time
);
} else {
daySlot.slots.push(time);
}
updatedSlots[daySlotIndex] = daySlot;
} else {
updatedSlots.push({ dayName, slots: [time] });
}
if (updatedSlots[daySlotIndex]?.slots.length === 0) {
updatedSlots.splice(daySlotIndex, 1);
}
setSelectedSlots(updatedSlots);
setValue('selectedSlots', updatedSlots);
};
return (
<>
<StyledHourColl item xs={1}>
<HourCollWrapper>
<Text variant='caption'>{hour}</Text>
</HourCollWrapper>
</StyledHourColl>
{weekDays.map((day, index) => {
const { dayName, time } = slotIdFormat(day, hour);
const isCurrentDay = isToday(day);
const dayAvailable = isDayAvailable(day);
const isSelected = isSlotSelected(dayName, time);
return (
<StyledDaySlots key={`day-${index}`} item xs={1}>
<SlotBox
isSelected={isSelected}
disabled={!dayAvailable}
isCurrentDay={!isSimple && isCurrentDay}
onClick={() => handleSlotClick(dayName, time)}
/>
</StyledDaySlots>
);
})}
</>
);
};
Image_
Can you help me?
{ Monday: ['08:00', '09:00', ...], Wednesday: ['10:00'] }
1