new-modal #4

Merged
jare2473 merged 18 commits from new-modal into main 2025-09-10 10:01:30 +02:00
3 changed files with 119 additions and 90 deletions
Showing only changes of commit a8a3859559 - Show all commits

View File

@ -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>

View File

@ -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 */

View File

@ -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}