booking-flow-finalized-design kindaaaa #7

Merged
jare2473 merged 20 commits from booking-flow-finalized-design into main 2025-09-30 10:50:54 +02:00
7 changed files with 214 additions and 161 deletions
Showing only changes of commit a24b525170 - Show all commits

View File

@@ -6,6 +6,7 @@ import Dropdown from '../ui/Dropdown';
import { BookingTitleField } from '../forms/BookingTitleField';
import { ParticipantsSelector } from '../forms/ParticipantsSelector';
import { BookingProvider } from '../../context/BookingContext';
import { Label } from '../ui/Label';
import { PEOPLE, USER } from '../../constants/bookingConstants';
function BookingCard({ booking, onClick, isExpanded, onBookingUpdate, onBookingDelete }) {
@@ -176,173 +177,176 @@ function BookingCard({ booking, onClick, isExpanded, onBookingUpdate, onBookingD
}
return (
<div className={`${styles.card} ${isExpanded ? styles.expanded : ''}`}>
<div className={styles.header} onClick={!isExpanded ? onClick : undefined}>
<div className={styles.topSection}>
<div className={styles.titleRow}>
<h3 className={styles.title}>{booking.title}</h3>
</div>
<div className={styles.time}>
{getTimeFromIndex(booking.startTime)} {getTimeFromIndex(calculatedEndTime || booking.endTime)}
</div>
</div>
<div className={styles.bottomSection}>
{isParticipantBooking && booking.createdBy && (
<div className={styles.createdBy}>
Tillagd av {booking.createdBy.name}
<div className={`${styles.cardWrapper} ${isExpanded ? styles.expanded : ''}`}>
<div className={styles.card}>
<div className={styles.header} onClick={!isExpanded ? onClick : undefined}>
<div className={styles.topSection}>
<div className={styles.titleRow}>
<h3 className={styles.title}>{booking.title}</h3>
</div>
<div className={styles.time}>
{getTimeFromIndex(booking.startTime)} {getTimeFromIndex(calculatedEndTime || booking.endTime)}
</div>
</div>
<div className={styles.bottomSection}>
{booking.participants && booking.participants.length > 0 && (
<div className={styles.participants}>{formatParticipants(booking.participants)}</div>
)}
<div className={styles.roomBadge}>
{booking.room}
</div>
)}
{!isParticipantBooking && booking.participants && booking.participants.length > 0 && (
<div className={styles.participants}>{formatParticipants(booking.participants)}</div>
)}
<div className={styles.roomBadge}>
{booking.room}
</div>
</div>
</div>
{isExpanded && (
<BookingProvider value={localBookingContext}>
{isExpanded && (
<div className={styles.expandedContent}>
{isParticipantBooking ? (
// Participant booking view - read-only with remove self option
<>
<div className={styles.readOnlySection}>
<div className={styles.readOnlyField}>
<label className={styles.label}>Bokning skapad av</label>
<p className={styles.createdByText}>{booking.createdBy?.name}</p>
</div>
<div className={styles.readOnlyField}>
<label className={styles.label}>Deltagare</label>
<p className={styles.participantsText}>
{booking.participants
?.filter(p => p.id !== booking.createdBy?.id)
?.map(p => p.name)
?.join(', ')}
</p>
</div>
</div>
{!showDeleteConfirm ? (
<div className={styles.buttonSection}>
<Button
className={styles.deleteButton}
onPress={() => setShowDeleteConfirm(true)}
>
Lämna bokning
</Button>
<Button
className={styles.cancelButton}
onPress={handleCancel}
>
Stäng
</Button>
</div>
) : (
<div className={styles.confirmationSection}>
<div className={styles.confirmationMessage}>
<span className={styles.warningIcon}></span>
<p>Är du säker att du vill lämna denna bokning?</p>
<p className={styles.bookingDetails}>
Du kommer inte längre att vara med "{booking.title}" den {booking.date.day}/{booking.date.month}
<BookingProvider value={localBookingContext}>
{isParticipantBooking ? (
// Participant booking view - read-only with remove self option
<>
<div className={styles.readOnlySection}>
<div className={styles.readOnlyField}>
<Label>Bokning skapad av</Label>
<p className={styles.createdByText}>{booking.createdBy?.name}</p>
</div>
<div className={styles.readOnlyField}>
<Label>Deltagare</Label>
<p className={styles.participantsText}>
{booking.participants
?.filter(p => p.id !== booking.createdBy?.id)
?.map(p => p.name)
?.join(', ')}
</p>
</div>
<div className={styles.confirmationButtons}>
</div>
{!showDeleteConfirm ? (
<div className={styles.buttonSection}>
<Button
className={styles.confirmDeleteButton}
onPress={handleRemoveSelf}
className={styles.deleteButton}
onPress={() => setShowDeleteConfirm(true)}
>
Ja, lämna bokning
Lämna bokning
</Button>
<Button
className={styles.cancelDeleteButton}
onPress={cancelDelete}
className={styles.cancelButton}
onPress={handleCancel}
>
Stäng
</Button>
</div>
) : (
<div className={styles.confirmationSection}>
<div className={styles.confirmationMessage}>
<span className={styles.warningIcon}></span>
<p>Är du säker att du vill lämna denna bokning?</p>
<p className={styles.bookingDetails}>
Du kommer inte längre att vara med "{booking.title}" den {booking.date.day}/{booking.date.month}
</p>
</div>
<div className={styles.confirmationButtons}>
<Button
className={styles.confirmDeleteButton}
onPress={handleRemoveSelf}
>
Ja, lämna bokning
</Button>
<Button
className={styles.cancelDeleteButton}
onPress={cancelDelete}
>
Avbryt
</Button>
</div>
</div>
)}
</>
) : (
// Regular booking view - editable
<>
<div className={styles.formSection}>
<BookingTitleField compact={true} />
</div>
<div className={styles.formSection}>
<ParticipantsSelector compact={true} />
</div>
<div className={styles.editSection}>
<Label>Ändra längd</Label>
<Dropdown
options={bookingLengths}
disabledOptions={disabledOptions}
onChange={handleLengthChange}
value={selectedLength || ""}
placeholder={{
value: "",
label: "Välj bokningslängd"
}}
/>
</div>
{!showDeleteConfirm ? (
<div className={styles.buttonSection}>
<Button
className={styles.deleteButton}
onPress={handleDelete}
>
Radera
</Button>
<Button
className={styles.cancelButton}
onPress={handleCancel}
>
Avbryt
</Button>
</div>
</div>
)}
</>
) : (
// Regular booking view - editable
<>
<div className={styles.formSection}>
<BookingTitleField compact={true} />
</div>
<div className={styles.formSection}>
<ParticipantsSelector compact={true} />
</div>
<div className={styles.editSection}>
<label className={styles.label}>Ändra längd</label>
<Dropdown
options={bookingLengths}
disabledOptions={disabledOptions}
onChange={handleLengthChange}
value={selectedLength || ""}
placeholder={{
value: "",
label: "Välj bokningslängd"
}}
/>
</div>
{!showDeleteConfirm ? (
<div className={styles.buttonSection}>
<Button
className={styles.deleteButton}
onPress={handleDelete}
>
Radera
</Button>
<Button
className={styles.cancelButton}
onPress={handleCancel}
>
Avbryt
</Button>
<Button
className={`${styles.saveButton} ${selectedLength === null ? styles.disabledButton : ''}`}
onPress={handleSave}
isDisabled={selectedLength === null}
>
{selectedLength !== null ? 'Spara ändringar' : 'Välj längd först'}
</Button>
</div>
) : (
<div className={styles.confirmationSection}>
<div className={styles.confirmationMessage}>
<span className={styles.warningIcon}></span>
<p>Är du säker att du vill radera denna bokning?</p>
<p className={styles.bookingDetails}>
"{booking.title}" den {booking.date.day}/{booking.date.month} kl. {getTimeFromIndex(booking.startTime)}
</p>
</div>
<div className={styles.confirmationButtons}>
<Button
className={styles.confirmDeleteButton}
onPress={confirmDelete}
className={`${styles.saveButton} ${selectedLength === null ? styles.disabledButton : ''}`}
onPress={handleSave}
isDisabled={selectedLength === null}
>
Ja, radera
</Button>
<Button
className={styles.cancelDeleteButton}
onPress={cancelDelete}
>
Avbryt
{selectedLength !== null ? 'Spara ändringar' : 'Välj längd först'}
</Button>
</div>
</div>
)}
</>
)}
) : (
<div className={styles.confirmationSection}>
<div className={styles.confirmationMessage}>
<span className={styles.warningIcon}></span>
<p>Är du säker att du vill radera denna bokning?</p>
<p className={styles.bookingDetails}>
"{booking.title}" den {booking.date.day}/{booking.date.month} kl. {getTimeFromIndex(booking.startTime)}
</p>
</div>
<div className={styles.confirmationButtons}>
<Button
className={styles.confirmDeleteButton}
onPress={confirmDelete}
>
Ja, radera
</Button>
<Button
className={styles.cancelDeleteButton}
onPress={cancelDelete}
>
Avbryt
</Button>
</div>
</div>
)}
</>
)}
</BookingProvider>
</div>
</BookingProvider>
)}
)}
</div>
{isParticipantBooking && booking.createdBy && !isExpanded && (
<div className={styles.banner}>
Tillagd av {booking.createdBy.name}
</div>
)}
</div>
);
}

View File

@@ -1,3 +1,8 @@
.cardWrapper {
width: 100%;
transition: var(--transition-medium);
}
.card {
border: var(--border-width-thin) solid var(--border-light);
padding: 0.8rem 1rem;
@@ -7,7 +12,7 @@
}
@media (hover: hover) {
.card:hover {
.cardWrapper:hover .card {
cursor: pointer;
border-color: var(--color-primary);
box-shadow: var(--shadow-xl);
@@ -15,11 +20,22 @@
}
}
.banner {
background-color: #f3f4f6;
color: #6b7280;
font-size: 0.8rem;
padding: 0.25rem 1rem;
border-left: var(--border-width-thin) solid var(--border-light);
border-right: var(--border-width-thin) solid var(--border-light);
border-bottom: var(--border-width-thin) solid var(--border-light);
/*border-bottom-left-radius: var(--border-radius-md);
border-bottom-right-radius: var(--border-radius-md);*/
}
.header {
display: flex;
flex-direction: column;
gap: 0.2rem;
width: 100%;
}
@@ -62,12 +78,8 @@
white-space: nowrap;
}
.participants,
.createdBy {
font-size: 0.875rem;
color: #6b7280;
}
.participants {
margin: 0;
font-size: 1rem;
color: #6b7280;
@@ -117,8 +129,8 @@
}
.expandedContent {
margin-top: 1.5rem;
padding-top: 1.5rem;
padding-top:1rem;
margin-top:1rem;
border-top: 1px solid #E5E5E5;
}
@@ -156,7 +168,17 @@
font-size: 0.8rem;
color: #717171;
font-weight: 500;
margin-bottom: 0.5rem;
/*margin-bottom: 0.5rem;*/
text-transform: uppercase;
letter-spacing: 0.5px;
}
.compactElementHeading {
font-size: 0.75rem;
color: var(--text-tertiary);
font-weight: 500;
margin-bottom: 0.4rem;
margin-top: 0;
text-transform: uppercase;
letter-spacing: 0.5px;
}

View File

@@ -1,6 +1,7 @@
import React from 'react';
import { useBookingContext } from '../../context/BookingContext';
import { useSettingsContext } from '../../context/SettingsContext';
import { Label } from '../ui/Label';
import styles from './BookingTitleField.module.css';
export function BookingTitleField({ compact = false, hideLabel = false }) {
@@ -10,7 +11,7 @@ export function BookingTitleField({ compact = false, hideLabel = false }) {
return (
<>
{!hideLabel && (
<h3 className={compact ? styles.compactElementHeading : styles.elementHeading}>Titel bokning</h3>
<Label>Titel bokning</Label>
)}
<input
type="text"

View File

@@ -2,6 +2,7 @@ import React, { useState, useRef, useEffect } from 'react';
import { PEOPLE, USER } from '../../constants/bookingConstants';
import { useBookingContext } from '../../context/BookingContext';
import { useSettingsContext } from '../../context/SettingsContext';
import { Label } from '../ui/Label';
import styles from './ParticipantsSelector.module.css';
export function ParticipantsSelector({ compact = false, hideLabel = false }) {
@@ -170,7 +171,7 @@ export function ParticipantsSelector({ compact = false, hideLabel = false }) {
return (
<div className={compact ? styles.compactContainer : styles.container}>
{!hideLabel && (
<h3 className={compact ? styles.compactElementHeading : styles.elementHeading}>Deltagare</h3>
<Label>Deltagare</Label>
)}
{/* Search Input */}

View File

@@ -3,4 +3,10 @@
margin: 0 auto;
padding: var(--spacing-2xl);
min-height: 100vh;
}
@media (max-width: 768px) {
.pageContainer {
padding: var(--spacing-lg);
}
}

View File

@@ -0,0 +1,10 @@
import React from 'react';
import styles from './Label.module.css';
export function Label({ children, className = '', ...props }) {
return (
<h3 className={`${styles.label} ${className}`} {...props}>
{children}
</h3>
);
}

View File

@@ -0,0 +1,9 @@
.label {
font-size: 0.75rem;
color: var(--text-tertiary);
font-weight: 500;
margin-bottom: 0.4rem;
margin-top: 0;
text-transform: uppercase;
letter-spacing: 0.5px;
}