booking-flow-finalized-design kindaaaa #7
@@ -144,9 +144,12 @@ export function InlineModalExtendedBookingForm({
|
||||
|
||||
// Check if user has selected an end time (including pre-selected)
|
||||
const hasSelectedEndTime = selectedEndTimeIndex !== null;
|
||||
|
||||
// Check if user has added at least one additional participant (beyond themselves)
|
||||
const hasRequiredParticipants = booking.participants.length > 0;
|
||||
|
||||
const handleSave = () => {
|
||||
if (hasSelectedEndTime && addBooking) {
|
||||
if (hasSelectedEndTime && hasRequiredParticipants && addBooking) {
|
||||
console.log('Booking context state:', {
|
||||
title: booking.title,
|
||||
participants: booking.participants,
|
||||
@@ -306,6 +309,15 @@ export function InlineModalExtendedBookingForm({
|
||||
{/* Participants Field - Compact */}
|
||||
<div className={extendedStyles.section}>
|
||||
<ParticipantsSelector compact={true} />
|
||||
{/*!hasRequiredParticipants && (
|
||||
<div style={{
|
||||
fontSize: '0.8rem',
|
||||
color: '#6c757d',
|
||||
marginTop: '0.5rem'
|
||||
}}>
|
||||
💡 Lägg till minst en deltagare
|
||||
</div>
|
||||
)*/}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -317,11 +329,13 @@ export function InlineModalExtendedBookingForm({
|
||||
Avbryt
|
||||
</Button>
|
||||
<Button
|
||||
className={`${styles.saveButton} ${!hasSelectedEndTime ? styles.disabledButton : ''}`}
|
||||
onPress={hasSelectedEndTime ? handleSave : undefined}
|
||||
isDisabled={!hasSelectedEndTime}
|
||||
className={`${styles.saveButton} ${(!hasSelectedEndTime || !hasRequiredParticipants) ? styles.disabledButton : ''}`}
|
||||
onPress={(hasSelectedEndTime && hasRequiredParticipants) ? handleSave : undefined}
|
||||
isDisabled={!hasSelectedEndTime || !hasRequiredParticipants}
|
||||
>
|
||||
{hasSelectedEndTime ? 'Boka' : 'Välj sluttid först'}
|
||||
{!hasSelectedEndTime ? 'Välj sluttid först' :
|
||||
!hasRequiredParticipants ? 'Minst en till deltagare krävs' :
|
||||
'Boka'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
import React from 'react';
|
||||
import styles from './PageHeader.module.css';
|
||||
|
||||
const PageHeader = ({ title, subtitle, imageUrl }) => {
|
||||
const PageHeader = ({ title, subtitle, imageUrl, breadcrumbs }) => {
|
||||
const headerClass = `${styles.header} ${imageUrl ? styles.withImage : styles.withoutImage}`;
|
||||
|
||||
return (
|
||||
<div className={styles.header}>
|
||||
<div className={headerClass}>
|
||||
{imageUrl && (
|
||||
<div className={styles.imageContainer}>
|
||||
<img className={styles.image} src={imageUrl} alt={title} />
|
||||
</div>
|
||||
)}
|
||||
<div className={styles.textContent}>
|
||||
{breadcrumbs && (
|
||||
<div className={styles.breadcrumbsContainer}>
|
||||
{breadcrumbs}
|
||||
</div>
|
||||
)}
|
||||
<h1 className={styles.pageHeading}>{title}</h1>
|
||||
{subtitle && <div className={styles.subtitle}>{subtitle}</div>}
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.header {
|
||||
margin-bottom: var(--spacing-2xl);
|
||||
padding-bottom: var(--spacing-xl);
|
||||
/*margin-bottom: var(--spacing-xl);*/
|
||||
padding: var(--spacing-2xl);
|
||||
border-bottom: 1px solid var(--border-light);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -20,13 +20,16 @@
|
||||
|
||||
.textContent {
|
||||
flex: 1;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.breadcrumbsContainer {
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.pageHeading {
|
||||
color: var(--text-primary);
|
||||
margin: 0 0 var(--spacing-md) 0;
|
||||
font-size: 2.5rem;
|
||||
margin: 0;
|
||||
font-size: 2rem;
|
||||
font-weight: var(--font-weight-bold);
|
||||
line-height: 1.2;
|
||||
}
|
||||
@@ -35,4 +38,21 @@
|
||||
color: var(--text-secondary);
|
||||
font-size: 1.1rem;
|
||||
font-weight: var(--font-weight-medium);
|
||||
}
|
||||
|
||||
/* Variant with image */
|
||||
.withImage {
|
||||
/* Default styles for image variant */
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.withImage .textContent {
|
||||
padding: var(--spacing-2xl);
|
||||
padding-top: var(--spacing-md);
|
||||
}
|
||||
|
||||
@media (min-width: 750px) {
|
||||
.image {
|
||||
aspect-ratio: 11/3;
|
||||
}
|
||||
}
|
||||
32
my-app/src/components/ui/Breadcrumbs.jsx
Normal file
32
my-app/src/components/ui/Breadcrumbs.jsx
Normal file
@@ -0,0 +1,32 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import styles from './Breadcrumbs.module.css';
|
||||
|
||||
const Breadcrumbs = ({ items }) => {
|
||||
return (
|
||||
<nav className={styles.breadcrumbs} aria-label="Breadcrumb">
|
||||
<ol className={styles.breadcrumbList}>
|
||||
{items.map((item, index) => (
|
||||
<li key={index} className={styles.breadcrumbItem}>
|
||||
{index < items.length - 1 ? (
|
||||
<Link to={item.path} className={styles.breadcrumbLink}>
|
||||
{item.label}
|
||||
</Link>
|
||||
) : (
|
||||
<span className={styles.breadcrumbCurrent} aria-current="page">
|
||||
{item.label}
|
||||
</span>
|
||||
)}
|
||||
{index < items.length - 1 && (
|
||||
<span className={styles.breadcrumbSeparator} aria-hidden="true">
|
||||
›
|
||||
</span>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
|
||||
export default Breadcrumbs;
|
||||
40
my-app/src/components/ui/Breadcrumbs.module.css
Normal file
40
my-app/src/components/ui/Breadcrumbs.module.css
Normal file
@@ -0,0 +1,40 @@
|
||||
.breadcrumbs {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.breadcrumbList {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 0.875rem;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.breadcrumbItem {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.breadcrumbLink {
|
||||
color: var(--text-secondary);
|
||||
text-decoration: none;
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
.breadcrumbLink:hover {
|
||||
color: var(--text-primary);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.breadcrumbCurrent {
|
||||
color: var(--text-primary);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.breadcrumbSeparator {
|
||||
margin: 0 0.5rem;
|
||||
color: var(--text-tertiary);
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import modalStyles from '../booking/BookingModal.module.css';
|
||||
import { useBookingContext } from '../../context/BookingContext';
|
||||
import { useSettingsContext } from '../../context/SettingsContext';
|
||||
|
||||
export function TimeCardContainer({ addBooking }) {
|
||||
export function TimeCardContainer({ addBooking, forceOneColumn = false }) {
|
||||
const navigate = useNavigate();
|
||||
const booking = useBookingContext();
|
||||
const { settings } = useSettingsContext();
|
||||
@@ -79,6 +79,11 @@ export function TimeCardContainer({ addBooking }) {
|
||||
function slotIndiciesToColumns(originalArray) {
|
||||
const width = window.innerWidth;
|
||||
|
||||
// Force single column if forceOneColumn prop is true
|
||||
if (forceOneColumn) {
|
||||
return [originalArray];
|
||||
}
|
||||
|
||||
if (width >= 769 && width <= LARGE_BREAKPOINT) {
|
||||
// For medium screens: group in pairs first, then distribute pairs across 2 columns
|
||||
const pairs = [];
|
||||
@@ -109,7 +114,7 @@ export function TimeCardContainer({ addBooking }) {
|
||||
const renderColumn = (column, columnIndex) => {
|
||||
const width = window.innerWidth;
|
||||
|
||||
if (width >= 769 && width <= LARGE_BREAKPOINT) {
|
||||
if (width >= 769 && width <= LARGE_BREAKPOINT && !forceOneColumn) {
|
||||
// For medium screens: render pairs in rows
|
||||
const pairs = [];
|
||||
for (let i = 0; i < column.length; i += 2) {
|
||||
@@ -144,8 +149,8 @@ export function TimeCardContainer({ addBooking }) {
|
||||
}).flat()}
|
||||
</div>
|
||||
);
|
||||
} else if (width < 769) {
|
||||
// For mobile: render pairs with spacing between every 4 pairs
|
||||
} else if (width < 769 || forceOneColumn) {
|
||||
// For mobile or forced single column: render pairs with spacing between every 4 pairs
|
||||
const pairs = [];
|
||||
for (let i = 0; i < column.length; i += 2) {
|
||||
pairs.push([column[i], column[i + 1]]);
|
||||
|
||||
@@ -33,6 +33,7 @@ export const SettingsProvider = ({ children }) => {
|
||||
showBookingDeleteBanner: false,
|
||||
bookingFormType: 'inline', // 'modal' or 'inline'
|
||||
showFiltersAlways: false, // Show filter dropdowns always or behind toggle button
|
||||
newBookingLayoutVariant: false, // false = stacked, true = side-by-side
|
||||
// Then override with saved values
|
||||
...parsed,
|
||||
// Convert date strings back to DateValue objects
|
||||
@@ -70,6 +71,8 @@ export const SettingsProvider = ({ children }) => {
|
||||
bookingFormType: 'inline', // 'modal' or 'inline'
|
||||
// Filter display mode
|
||||
showFiltersAlways: false, // Show filter dropdowns always or behind toggle button
|
||||
// New booking page layout variant
|
||||
newBookingLayoutVariant: false, // false = stacked, true = side-by-side
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -196,6 +196,31 @@ export function BookingSettings() {
|
||||
<strong>Show Filter Button:</strong> Filters are hidden behind a collapsible button
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.setting}>
|
||||
<label htmlFor="newBookingLayoutVariant">
|
||||
<strong>New Booking Page Layout</strong>
|
||||
<span className={styles.description}>
|
||||
Choose between stacked layout or side-by-side layout on medium screens
|
||||
</span>
|
||||
</label>
|
||||
<div className={styles.toggleGroup}>
|
||||
<input
|
||||
id="newBookingLayoutVariant"
|
||||
type="checkbox"
|
||||
checked={settings.newBookingLayoutVariant}
|
||||
onChange={(e) => updateSettings({ newBookingLayoutVariant: e.target.checked })}
|
||||
className={styles.toggle}
|
||||
/>
|
||||
<span className={styles.toggleStatus}>
|
||||
{settings.newBookingLayoutVariant ? 'Side-by-Side' : 'Stacked'}
|
||||
</span>
|
||||
</div>
|
||||
<div className={styles.description} style={{marginTop: '0.5rem', fontSize: '0.85rem'}}>
|
||||
<strong>Stacked:</strong> Image and header at top, booking times below<br/>
|
||||
<strong>Side-by-Side:</strong> Image/header on left, booking times on right (medium screens)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.section}>
|
||||
|
||||
@@ -9,6 +9,7 @@ import { BookingProvider } from '../context/BookingContext';
|
||||
import { useSettingsContext } from '../context/SettingsContext';
|
||||
import PageHeader from '../components/layout/PageHeader';
|
||||
import PageContainer from '../components/layout/PageContainer';
|
||||
import Breadcrumbs from '../components/ui/Breadcrumbs';
|
||||
|
||||
export function NewBooking({ addBooking }) {
|
||||
const { getEffectiveToday, settings } = useSettingsContext();
|
||||
@@ -58,75 +59,167 @@ export function NewBooking({ addBooking }) {
|
||||
setShowFilters(false);
|
||||
};
|
||||
|
||||
const breadcrumbItems = [
|
||||
{ label: 'Lokalbokning', path: '/' },
|
||||
{ label: 'Ny bokning', path: '/new-booking' }
|
||||
];
|
||||
|
||||
return (
|
||||
<BookingProvider value={booking}>
|
||||
<PageHeader title="Litet grupprum" subtitle="Plats för 5 personer" imageUrl="./grupprum.jpg" />
|
||||
<PageContainer>
|
||||
{/* <img src="./grupprum.jpg" alt="Litet grupprum" className={styles.roomImage} /> */}
|
||||
<div className={styles.formContainer}>
|
||||
<main style={{ flex: 1 }}>
|
||||
|
||||
<div className={styles.bookingTimesContainer}>
|
||||
<BookingDatePicker />
|
||||
|
||||
{/* Filter Section */}
|
||||
<div className={styles.headerAndFilter}>
|
||||
<div className={styles.filtersSection}>
|
||||
{settings.showFiltersAlways ? (
|
||||
/* Always-visible filters */
|
||||
<div className={styles.filtersContent}>
|
||||
<div className={styles.filtersRow}>
|
||||
<RoomSelectionField />
|
||||
<BookingLengthField />
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
/* Toggle button with collapsible filters */
|
||||
<>
|
||||
<button
|
||||
className={`${styles.filterButton} ${hasActiveFilters ? styles.activeFilter : ''}`}
|
||||
onClick={() => setShowFilters(!showFilters)}
|
||||
>
|
||||
<span>{getFilterText()}</span>
|
||||
<span className={`${styles.chevron} ${showFilters ? styles.chevronUp : styles.chevronDown}`}>
|
||||
{showFilters ? '▲' : '▼'}
|
||||
</span>
|
||||
</button>
|
||||
<div className={`${styles.newBookingPageContainer} ${settings.newBookingLayoutVariant ? styles.sideBySide : ''}`}>
|
||||
{settings.newBookingLayoutVariant ? (
|
||||
/* Side-by-side layout */
|
||||
<>
|
||||
<div className={styles.headerSection}>
|
||||
<PageHeader
|
||||
title="Litet grupprum"
|
||||
subtitle="Plats för 5 personer"
|
||||
imageUrl="./grupprum.jpg"
|
||||
breadcrumbs={<Breadcrumbs items={breadcrumbItems} />}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.contentSection}>
|
||||
<PageContainer>
|
||||
<div className={styles.formContainer}>
|
||||
<main style={{ flex: 1 }}>
|
||||
<div className={styles.bookingTimesContainer}>
|
||||
<BookingDatePicker />
|
||||
|
||||
{/* Collapsible Filter Content */}
|
||||
{showFilters && (
|
||||
<div className={styles.filtersContent}>
|
||||
<div className={styles.filtersRow}>
|
||||
<RoomSelectionField />
|
||||
<BookingLengthField />
|
||||
</div>
|
||||
{hasActiveFilters && (
|
||||
<div className={styles.resetSection}>
|
||||
<button
|
||||
className={styles.resetButton}
|
||||
onClick={handleResetFilters}
|
||||
>
|
||||
Rensa filter
|
||||
</button>
|
||||
{/* Filter Section */}
|
||||
<div className={styles.headerAndFilter}>
|
||||
<div className={styles.filtersSection}>
|
||||
{settings.showFiltersAlways ? (
|
||||
/* Always-visible filters */
|
||||
<div className={styles.filtersContent}>
|
||||
<div className={styles.filtersRow}>
|
||||
<RoomSelectionField />
|
||||
<BookingLengthField />
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
/* Toggle button with collapsible filters */
|
||||
<>
|
||||
<button
|
||||
className={`${styles.filterButton} ${hasActiveFilters ? styles.activeFilter : ''}`}
|
||||
onClick={() => setShowFilters(!showFilters)}
|
||||
>
|
||||
<span>{getFilterText()}</span>
|
||||
<span className={`${styles.chevron} ${showFilters ? styles.chevronUp : styles.chevronDown}`}>
|
||||
{showFilters ? '▲' : '▼'}
|
||||
</span>
|
||||
</button>
|
||||
|
||||
{/* Collapsible Filter Content */}
|
||||
{showFilters && (
|
||||
<div className={styles.filtersContent}>
|
||||
<div className={styles.filtersRow}>
|
||||
<RoomSelectionField />
|
||||
<BookingLengthField />
|
||||
</div>
|
||||
{hasActiveFilters && (
|
||||
<div className={styles.resetSection}>
|
||||
<button
|
||||
className={styles.resetButton}
|
||||
onClick={handleResetFilters}
|
||||
>
|
||||
Rensa filter
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<h3 className={styles.elementHeading} style={{ padding: "0 0.5rem" }}>
|
||||
Välj starttid
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<TimeCardContainer addBooking={addBooking} forceOneColumn={settings.newBookingLayoutVariant} />
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<h3 className={styles.elementHeading} style={{ padding: "0 0.5rem" }}>
|
||||
Välj starttid
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<TimeCardContainer addBooking={addBooking} />
|
||||
</div>
|
||||
</PageContainer>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</PageContainer>
|
||||
</>
|
||||
) : (
|
||||
/* Stacked layout (original) */
|
||||
<>
|
||||
<PageHeader
|
||||
title="Litet grupprum"
|
||||
subtitle="Plats för 5 personer"
|
||||
imageUrl="./grupprum.jpg"
|
||||
breadcrumbs={<Breadcrumbs items={breadcrumbItems} />}
|
||||
/>
|
||||
<div className={styles.formContainer}>
|
||||
<main style={{ flex: 1 }}>
|
||||
|
||||
<div className={styles.bookingTimesContainer}>
|
||||
<BookingDatePicker />
|
||||
|
||||
{/* Filter Section */}
|
||||
<div className={styles.headerAndFilter}>
|
||||
<div className={styles.filtersSection}>
|
||||
{settings.showFiltersAlways ? (
|
||||
/* Always-visible filters */
|
||||
<div className={styles.filtersContent}>
|
||||
<div className={styles.filtersRow}>
|
||||
<RoomSelectionField />
|
||||
<BookingLengthField />
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
/* Toggle button with collapsible filters */
|
||||
<>
|
||||
<button
|
||||
className={`${styles.filterButton} ${hasActiveFilters ? styles.activeFilter : ''}`}
|
||||
onClick={() => setShowFilters(!showFilters)}
|
||||
>
|
||||
<span>{getFilterText()}</span>
|
||||
<span className={`${styles.chevron} ${showFilters ? styles.chevronUp : styles.chevronDown}`}>
|
||||
{showFilters ? '▲' : '▼'}
|
||||
</span>
|
||||
</button>
|
||||
|
||||
{/* Collapsible Filter Content */}
|
||||
{showFilters && (
|
||||
<div className={styles.filtersContent}>
|
||||
<div className={styles.filtersRow}>
|
||||
<RoomSelectionField />
|
||||
<BookingLengthField />
|
||||
</div>
|
||||
{hasActiveFilters && (
|
||||
<div className={styles.resetSection}>
|
||||
<button
|
||||
className={styles.resetButton}
|
||||
onClick={handleResetFilters}
|
||||
>
|
||||
Rensa filter
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<h3 className={styles.elementHeading} style={{ padding: "0 0.5rem" }}>
|
||||
Välj starttid
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<TimeCardContainer addBooking={addBooking} forceOneColumn={false} />
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</BookingProvider>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
.pageContainer {
|
||||
padding: var(--container-padding);
|
||||
/*padding: var(--container-padding);*/
|
||||
background-color: var(--bg-primary);
|
||||
color: var(--text-primary);
|
||||
min-height: 100vh;
|
||||
@@ -39,7 +40,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
background-color: var(--bg-secondary);
|
||||
background-color: var(--bg-primary);
|
||||
padding-bottom: 2rem;
|
||||
}
|
||||
|
||||
@@ -300,4 +301,37 @@
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Side-by-side layout variant */
|
||||
.newBookingPageContainer {
|
||||
/*padding: var(--spacing-lg);*/
|
||||
}
|
||||
|
||||
.newBookingPageContainer.sideBySide {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
@media (min-width: 769px) and (max-width: 1400px) {
|
||||
.newBookingPageContainer.sideBySide {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 2rem;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.newBookingPageContainer.sideBySide .headerSection {
|
||||
flex: 0 0 400px;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.newBookingPageContainer.sideBySide .contentSection {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.newBookingPageContainer.sideBySide .bookingTimesContainer {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import Card from '../components/ui/Card';
|
||||
import { useSettingsContext } from '../context/SettingsContext';
|
||||
import { USER } from '../constants/bookingConstants';
|
||||
import PageHeader from '../components/layout/PageHeader';
|
||||
import PageContainer from '../components/layout/PageContainer';
|
||||
|
||||
export function RoomBooking({ bookings, showSuccessBanner, lastCreatedBooking, onDismissBanner, onBookingUpdate, onBookingDelete, showDeleteBanner, lastDeletedBooking, onDismissDeleteBanner }) {
|
||||
const { settings } = useSettingsContext();
|
||||
@@ -24,7 +25,7 @@ export function RoomBooking({ bookings, showSuccessBanner, lastCreatedBooking, o
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.pageContainer}>
|
||||
<>
|
||||
{isTestSessionActive && (
|
||||
<div className={styles.welcomeSection}>
|
||||
<div className={styles.welcomeContent}>
|
||||
@@ -34,37 +35,38 @@ export function RoomBooking({ bookings, showSuccessBanner, lastCreatedBooking, o
|
||||
</div>
|
||||
)}
|
||||
<PageHeader title="Lokalbokning" subtitle="Reservera lokaler för möten och studier" />
|
||||
|
||||
<h2 className={styles.sectionHeading}>Ny bokning</h2>
|
||||
<PageContainer>
|
||||
<h2 className={styles.sectionHeading}>Ny bokning</h2>
|
||||
|
||||
<div className={styles.roomCategoryCards}>
|
||||
<Link to='/new-booking'>
|
||||
<Card imageUrl="./grupprum.jpg" header="Litet grupprum" subheader="Plats för 5 personer" />
|
||||
</Link>
|
||||
<Link to='/new-booking'>
|
||||
<Card imageUrl="./stort-grupprum.jpg" header="Stort grupprum" subheader="Plats för 10 personer" />
|
||||
</Link>
|
||||
</div>
|
||||
<hr className={styles.sectionDivider} />
|
||||
<div className={styles.roomCategoryCards}>
|
||||
<Link to='/new-booking'>
|
||||
<Card imageUrl="./grupprum.jpg" header="Litet grupprum" subheader="Plats för 5 personer" />
|
||||
</Link>
|
||||
<Link to='/new-booking'>
|
||||
<Card imageUrl="./stort-grupprum.jpg" header="Stort grupprum" subheader="Plats för 10 personer" />
|
||||
</Link>
|
||||
</div>
|
||||
<hr className={styles.sectionDivider} />
|
||||
|
||||
<section id="bookings">
|
||||
<h2 className={styles.sectionHeading}>Mina bokingar</h2>
|
||||
<BookingsList
|
||||
bookings={bookings}
|
||||
handleEditBooking={handleEditBooking}
|
||||
onBookingUpdate={onBookingUpdate}
|
||||
onBookingDelete={onBookingDelete}
|
||||
showSuccessBanner={showSuccessBanner}
|
||||
lastCreatedBooking={lastCreatedBooking}
|
||||
onDismissBanner={onDismissBanner}
|
||||
showDeleteBanner={showDeleteBanner}
|
||||
lastDeletedBooking={lastDeletedBooking}
|
||||
onDismissDeleteBanner={onDismissDeleteBanner}
|
||||
showDevelopmentBanner={settings.showDevelopmentBanner}
|
||||
showBookingConfirmationBanner={settings.showBookingConfirmationBanner}
|
||||
showBookingDeleteBanner={settings.showBookingDeleteBanner}
|
||||
/>
|
||||
</section>
|
||||
</div>
|
||||
<section id="bookings">
|
||||
<h2 className={styles.sectionHeading}>Mina bokingar</h2>
|
||||
<BookingsList
|
||||
bookings={bookings}
|
||||
handleEditBooking={handleEditBooking}
|
||||
onBookingUpdate={onBookingUpdate}
|
||||
onBookingDelete={onBookingDelete}
|
||||
showSuccessBanner={showSuccessBanner}
|
||||
lastCreatedBooking={lastCreatedBooking}
|
||||
onDismissBanner={onDismissBanner}
|
||||
showDeleteBanner={showDeleteBanner}
|
||||
lastDeletedBooking={lastDeletedBooking}
|
||||
onDismissDeleteBanner={onDismissDeleteBanner}
|
||||
showDevelopmentBanner={settings.showDevelopmentBanner}
|
||||
showBookingConfirmationBanner={settings.showBookingConfirmationBanner}
|
||||
showBookingDeleteBanner={settings.showBookingDeleteBanner}
|
||||
/>
|
||||
</section>
|
||||
</PageContainer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
color: var(--text-primary);
|
||||
background-color: var(--bg-secondary);
|
||||
padding: var(--spacing-md);
|
||||
border: 1px solid var(--border-light);
|
||||
border-bottom: 1px solid var(--border-light);
|
||||
position: sticky;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
|
||||
@@ -298,7 +298,7 @@
|
||||
|
||||
/* Button disabled states */
|
||||
--button-disabled-bg: #f8f9fa;
|
||||
--button-disabled-text: #adb5bd;
|
||||
--button-disabled-text: #797e83;
|
||||
--button-disabled-border: #dee2e6;
|
||||
|
||||
/* Additional color variants */
|
||||
|
||||
Reference in New Issue
Block a user