new-modal #4
@ -18,74 +18,69 @@ export function BookingModal({
|
||||
const booking = useBookingContext();
|
||||
const { getCurrentUser, getDefaultBookingTitle } = useSettingsContext();
|
||||
|
||||
// Initialize with pre-selected booking length if available, or auto-select if only 30 min available
|
||||
const initialLength = booking.selectedBookingLength > 0 ? booking.selectedBookingLength :
|
||||
(hoursAvailable === 1 ? 1 : null); // Auto-select 30 min if that's all that's available
|
||||
const [selectedLength, setSelectedLength] = useState(null);
|
||||
const [calculatedEndTime, setCalculatedEndTime] = useState(startTimeIndex);
|
||||
// Initialize with pre-selected end time if available, or auto-select if only 30 min available
|
||||
const initialEndTimeIndex = booking.selectedBookingLength > 0 ? startTimeIndex + booking.selectedBookingLength :
|
||||
(hoursAvailable === 1 ? startTimeIndex + 1 : null); // Auto-select 30 min if that's all that's available
|
||||
const [selectedEndTimeIndex, setSelectedEndTimeIndex] = useState(null);
|
||||
const hasInitialized = useRef(false);
|
||||
|
||||
// Effect to handle initial setup only once when modal opens
|
||||
useEffect(() => {
|
||||
if (initialLength && !hasInitialized.current) {
|
||||
setSelectedLength(initialLength);
|
||||
const newEndTime = startTimeIndex + initialLength;
|
||||
setCalculatedEndTime(newEndTime);
|
||||
setEndTimeIndex(newEndTime);
|
||||
booking.setSelectedEndIndex(newEndTime);
|
||||
if (initialEndTimeIndex && !hasInitialized.current) {
|
||||
setSelectedEndTimeIndex(initialEndTimeIndex);
|
||||
setEndTimeIndex(initialEndTimeIndex);
|
||||
booking.setSelectedEndIndex(initialEndTimeIndex);
|
||||
hasInitialized.current = true;
|
||||
}
|
||||
}, [initialLength, startTimeIndex, setEndTimeIndex, booking]);
|
||||
}, [initialEndTimeIndex, setEndTimeIndex, booking]);
|
||||
|
||||
const bookingLengths = [
|
||||
{ value: 1, label: "30 min" },
|
||||
{ value: 2, label: "1 h" },
|
||||
{ value: 3, label: "1.5 h" },
|
||||
{ value: 4, label: "2 h" },
|
||||
{ value: 5, label: "2.5 h" },
|
||||
{ value: 6, label: "3 h" },
|
||||
{ value: 7, label: "3.5 h" },
|
||||
{ value: 8, label: "4 h" },
|
||||
];
|
||||
|
||||
function getLabelFromAvailableHours(availableHours) {
|
||||
return bookingLengths.find(option => option.value === availableHours)?.label || "Välj längd";
|
||||
// Generate end time options based on available hours
|
||||
const endTimeOptions = [];
|
||||
const disabledOptions = {};
|
||||
|
||||
for (let i = 1; i <= Math.min(hoursAvailable, 8); i++) {
|
||||
const endTimeIndex = startTimeIndex + i;
|
||||
const endTime = getTimeFromIndex(endTimeIndex);
|
||||
const durationLabel = i === 1 ? "30 min" :
|
||||
i === 2 ? "1 h" :
|
||||
i === 3 ? "1.5 h" :
|
||||
i === 4 ? "2 h" :
|
||||
i === 5 ? "2.5 h" :
|
||||
i === 6 ? "3 h" :
|
||||
i === 7 ? "3.5 h" :
|
||||
i === 8 ? "4 h" : `${i * 0.5} h`;
|
||||
|
||||
endTimeOptions.push({
|
||||
value: endTimeIndex,
|
||||
label: `${endTime} (${durationLabel})`
|
||||
});
|
||||
|
||||
disabledOptions[endTimeIndex] = false; // All available options are enabled
|
||||
}
|
||||
|
||||
const disabledOptions = {
|
||||
1: !(hoursAvailable > 0),
|
||||
2: !(hoursAvailable > 1),
|
||||
3: !(hoursAvailable > 2),
|
||||
4: !(hoursAvailable > 3),
|
||||
5: !(hoursAvailable > 4),
|
||||
6: !(hoursAvailable > 5),
|
||||
7: !(hoursAvailable > 6),
|
||||
8: !(hoursAvailable > 7),
|
||||
};
|
||||
|
||||
function handleChange(event) {
|
||||
const lengthValue = event.target.value === "" ? null : parseInt(event.target.value);
|
||||
const endTimeValue = event.target.value === "" ? null : parseInt(event.target.value);
|
||||
console.log(event.target.value);
|
||||
setSelectedLength(lengthValue);
|
||||
setSelectedEndTimeIndex(endTimeValue);
|
||||
|
||||
if (lengthValue !== null) {
|
||||
const newEndTime = startTimeIndex + lengthValue;
|
||||
setCalculatedEndTime(newEndTime);
|
||||
setEndTimeIndex(newEndTime);
|
||||
booking.setSelectedEndIndex(newEndTime);
|
||||
if (endTimeValue !== null) {
|
||||
setEndTimeIndex(endTimeValue);
|
||||
booking.setSelectedEndIndex(endTimeValue);
|
||||
} else {
|
||||
// Reset to default state when placeholder is selected
|
||||
setCalculatedEndTime(startTimeIndex);
|
||||
setEndTimeIndex(startTimeIndex);
|
||||
booking.setSelectedEndIndex(null);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if user has selected a booking length (including pre-selected)
|
||||
const hasSelectedLength = selectedLength !== null;
|
||||
// Check if user has selected an end time (including pre-selected)
|
||||
const hasSelectedEndTime = selectedEndTimeIndex !== null;
|
||||
|
||||
// Display time range - show calculated end time if length is selected
|
||||
const displayEndTime = hasSelectedLength ? calculatedEndTime : startTimeIndex;
|
||||
// Calculate duration in hours for display
|
||||
const calculateDuration = (endIndex) => {
|
||||
const durationSlots = endIndex - startTimeIndex;
|
||||
return durationSlots * 0.5; // Each slot is 30 minutes
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
@ -102,34 +97,28 @@ export function BookingModal({
|
||||
<p>{convertDateObjectToString(booking.selectedDate)}</p>
|
||||
<div className={styles.timeDisplay}>
|
||||
<div className={styles.timeRange}>
|
||||
<div className={styles.startTime}>
|
||||
<div className={styles.startTimeSection}>
|
||||
<label>Starttid</label>
|
||||
<span className={styles.timeValue}>{getTimeFromIndex(startTimeIndex)}</span>
|
||||
<div className={styles.startTimeValue}>{getTimeFromIndex(startTimeIndex)}</div>
|
||||
</div>
|
||||
<div className={styles.timeSeparator}>–</div>
|
||||
<div className={styles.endTime}>
|
||||
<div className={styles.endTimeSection}>
|
||||
<label>Sluttid</label>
|
||||
<span className={`${styles.timeValue} ${!hasSelectedLength ? styles.placeholder : ''}`}>
|
||||
{hasSelectedLength ? getTimeFromIndex(displayEndTime) : "Välj längd"}
|
||||
</span>
|
||||
<Dropdown
|
||||
options={endTimeOptions}
|
||||
disabledOptions={disabledOptions}
|
||||
onChange={handleChange}
|
||||
value={selectedEndTimeIndex || ""}
|
||||
placeholder={!initialEndTimeIndex ? {
|
||||
value: "",
|
||||
label: "Välj sluttid"
|
||||
} : null}
|
||||
className={styles.endTimeDropdown}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.sectionWithTitle}>
|
||||
<label>Längd</label>
|
||||
<Dropdown
|
||||
options={bookingLengths}
|
||||
disabledOptions={disabledOptions}
|
||||
onChange={handleChange}
|
||||
value={selectedLength || ""}
|
||||
placeholder={!initialLength ? {
|
||||
value: "",
|
||||
label: "Välj bokningslängd"
|
||||
} : null}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.sectionWithTitle}>
|
||||
<label>{booking.selectedRoom !== "allRooms" ? "Rum" : "Tilldelat rum"}</label>
|
||||
<p>{booking.selectedRoom !== "allRooms" ? booking.selectedRoom : (booking.assignedRoom || 'Inget rum tilldelat')}</p>
|
||||
@ -150,11 +139,11 @@ export function BookingModal({
|
||||
Avbryt
|
||||
</Button>
|
||||
<Button
|
||||
className={`${styles.saveButton} ${!hasSelectedLength ? styles.disabledButton : ''}`}
|
||||
onClick={hasSelectedLength ? booking.handleSave : undefined}
|
||||
isDisabled={!hasSelectedLength}
|
||||
className={`${styles.saveButton} ${!hasSelectedEndTime ? styles.disabledButton : ''}`}
|
||||
onClick={hasSelectedEndTime ? booking.handleSave : undefined}
|
||||
isDisabled={!hasSelectedEndTime}
|
||||
>
|
||||
{hasSelectedLength ? 'Boka' : 'Välj längd först'}
|
||||
{hasSelectedEndTime ? 'Boka' : 'Välj sluttid först'}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@ -150,43 +150,83 @@
|
||||
.timeRange {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.startTime, .endTime {
|
||||
.startTimeSection {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.startTime label, .endTime label {
|
||||
.endTimeSection {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.startTimeSection label, .endTimeSection label {
|
||||
font-size: 0.75rem;
|
||||
color: var(--text-secondary);
|
||||
font-weight: 500;
|
||||
margin-bottom: 0.25rem;
|
||||
margin-bottom: 0.5rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.timeValue {
|
||||
font-size: 1.5rem;
|
||||
.startTimeValue {
|
||||
font-size: 2.5rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.timeValue.placeholder {
|
||||
color: var(--text-muted);
|
||||
font-style: italic;
|
||||
font-size: 1rem;
|
||||
.timeSeparator {
|
||||
font-size: 2.5rem;
|
||||
font-weight: 300;
|
||||
color: var(--text-secondary);
|
||||
margin: 0 0.75rem;
|
||||
padding-top: 1.5rem;
|
||||
}
|
||||
|
||||
.timeSeparator {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 400;
|
||||
color: var(--text-secondary);
|
||||
margin: 0 0.5rem;
|
||||
padding-top: 1.3rem;
|
||||
.endTimeDropdown {
|
||||
max-width: none;
|
||||
min-width: 140px;
|
||||
}
|
||||
|
||||
.endTimeDropdown .dropdownWrapper {
|
||||
background: var(--bg-primary);
|
||||
border: 2px solid var(--border-light);
|
||||
border-radius: 12px;
|
||||
transition: all var(--transition-medium);
|
||||
}
|
||||
|
||||
.endTimeDropdown .dropdownWrapper:hover {
|
||||
border-color: var(--color-primary);
|
||||
background: var(--bg-secondary);
|
||||
}
|
||||
|
||||
.endTimeDropdown .dropdownWrapper:focus-within {
|
||||
border-color: var(--color-primary);
|
||||
box-shadow: 0 0 0 2px var(--color-primary-light);
|
||||
}
|
||||
|
||||
.endTimeDropdown .select {
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
padding: 0.75rem 2.5rem 0.75rem 1rem;
|
||||
font-size: 2.5rem;
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
min-width: 140px;
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
}
|
||||
|
||||
.endTimeDropdown .select:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Disabled button styles */
|
||||
|
||||
@ -3,9 +3,9 @@ import styles from "./Dropdown.module.css";
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
import { faChevronDown } from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
const Dropdown = ({ options, value, onChange, placeholder = {value: "", label: "Select an option"}, disabledOptions = false }) => {
|
||||
const Dropdown = ({ options, value, onChange, placeholder = {value: "", label: "Select an option"}, disabledOptions = false, className }) => {
|
||||
return (
|
||||
<div className={styles.dropdownWrapper}>
|
||||
<div className={`${styles.dropdownWrapper} ${className || ''}`}>
|
||||
<select
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user