tweaks for seat-chooser
This commit is contained in:
parent
b0cc5b5278
commit
2451ab45cb
4 changed files with 174 additions and 29 deletions
|
@ -47,15 +47,9 @@ public function seatMatrix($showing_id = null)
|
|||
{
|
||||
$seats = $this->seats;
|
||||
$matrix = [];
|
||||
// first, create an empty matrix
|
||||
for ($i = 0; $i < $this->room_rows-1; $i++) {
|
||||
$matrix[$i] = [];
|
||||
for ($j = 0; $j < $this->room_columns-1; $j++) {
|
||||
$matrix[$i][$j] = null;
|
||||
}
|
||||
}
|
||||
// then, fill it with the seats
|
||||
foreach ($seats as $seat) {
|
||||
if (!isset($matrix[$seat->seat_row - 1])) $matrix[$seat->seat_row - 1] = [];
|
||||
$matrix[$seat->seat_row-1][$seat->seat_column-1] = [
|
||||
'seat_id' => $seat->seat_id,
|
||||
'seat_row' => $seat->seat_row,
|
||||
|
@ -65,7 +59,24 @@ public function seatMatrix($showing_id = null)
|
|||
'reserved' => $showing_id ? $seat->isReserved($showing_id) : false,
|
||||
];
|
||||
}
|
||||
return $matrix;
|
||||
return fix_matrix($matrix, $this->room_columns-1, $this->room_rows-1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function fix_matrix($m, $h, $w) {
|
||||
$_nm = [];
|
||||
// write the matrix into _nm and fill the empty spaces with null
|
||||
for ($i = 0; $i <= $h; $i++) {
|
||||
$_nm[$i] = [];
|
||||
for ($j = 0; $j <= $w; $j++) {
|
||||
if (isset($m[$i][$j])) {
|
||||
$_nm[$i][$j] = $m[$i][$j];
|
||||
} else {
|
||||
$_nm[$i][$j] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $_nm;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,12 @@ #seat-chooser {
|
|||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
--seat-width: 2.5rem;
|
||||
--seat-height: var(--seat-width);
|
||||
--seat-gap: 0.5rem;
|
||||
--seat-border-size: 0.1rem;
|
||||
--seat-border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
#seat-chooser .row {
|
||||
|
@ -29,12 +35,12 @@ #seat-chooser .row .seat {
|
|||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin: 5px;
|
||||
border: 1px solid #000;
|
||||
border-radius: 5px;
|
||||
background-color: #fff;
|
||||
width: var(--seat-width);
|
||||
height: var(--seat-height);
|
||||
margin: var(--seat-gap);
|
||||
border: var(--seat-border-size) solid var(--primary-color);
|
||||
border-radius: var(--seat-border-radius);
|
||||
background-color: var(--second-bg);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
@ -50,22 +56,39 @@ #seat-chooser .row .seat.linked-right {
|
|||
border-left: 0;
|
||||
}
|
||||
|
||||
#seat-chooser .row .seat.loveseat {
|
||||
background-color: #ff3fe5;
|
||||
}
|
||||
|
||||
#seat-chooser .row .no-seat {
|
||||
/* this seat DOES NOT EXISTS it's a filler for layout*/
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
cursor: default;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin: 5px;
|
||||
|
||||
width: var(--seat-width);
|
||||
height: var(--seat-height);
|
||||
margin: calc(var(--seat-border-size) + var(--seat-gap));
|
||||
}
|
||||
|
||||
#seat-chooser .row .seat.selected {
|
||||
background-color: #55f;
|
||||
border: calc(var(--seat-gap) - 0.1rem) solid var(--primary-color);
|
||||
margin: 0.1rem;
|
||||
filter: brightness(1.2);
|
||||
}
|
||||
|
||||
#seat-chooser .row .seat.reserved {
|
||||
background-color: #f00;
|
||||
background-color: var(--highlight-bg);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
#seat-chooser .row .seat.disabled {
|
||||
background-color: var(--default-bg);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
#seat-chooser .row .seat.wheelchair {
|
||||
background-color: #3498db;
|
||||
}
|
||||
|
||||
#seat-chooser .row .seat:hover {
|
||||
|
|
|
@ -4,22 +4,38 @@
|
|||
// the input is a matrix with null OR a seat object
|
||||
|
||||
class Seat {
|
||||
constructor(id, row, col, linked, reserved) {
|
||||
constructor(id, row, col, linked, reserved, type) {
|
||||
this.id = id; // database id
|
||||
this.row = row;
|
||||
this.col = col;
|
||||
this.linked = linked; // linked seat
|
||||
this.reserved = reserved;
|
||||
this.type = type; // seat type
|
||||
}
|
||||
}
|
||||
|
||||
class SeatChooser {
|
||||
constructor(showingId, container) {
|
||||
if (container.innerText === '') {
|
||||
container.innerText = 'Loading...';
|
||||
setLoadingStatus(msg) {
|
||||
// if no status element exists, create one
|
||||
if (!this.container.querySelector('#seat-chooser-status')) {
|
||||
let status = document.createElement('div');
|
||||
// h2 for "Loading..."
|
||||
// span for message
|
||||
status.innerHTML = `<h2>Loading...</h2><span id="seat-chooser-status-message"></span>`;
|
||||
status.id = 'seat-chooser-status';
|
||||
status.style.textAlign = 'center';
|
||||
this.container.appendChild(status);
|
||||
}
|
||||
// set the message
|
||||
this.container.querySelector('#seat-chooser-status-message').innerText = msg;
|
||||
}
|
||||
|
||||
constructor(showingId, container, submitCallback) {
|
||||
this.showingId = showingId; // id of the showing
|
||||
this.container = container; // the container to render the seat chooser in
|
||||
this.submitCallback = submitCallback; // callback function to call when the user submits the form
|
||||
|
||||
this.setLoadingStatus("Initializing...");
|
||||
|
||||
this.seats = []; // array of nulls and Seat objects
|
||||
|
||||
|
@ -29,34 +45,55 @@ class SeatChooser {
|
|||
}
|
||||
|
||||
async init() {
|
||||
this.setLoadingStatus("Fetching showing data...");
|
||||
let showingJson = await (await fetch(`/api/showings/${this.showingId}`)).json();
|
||||
this.setLoadingStatus("Fetching seats...");
|
||||
let roomMatrix = await (await fetch(`/api/showings/${this.showingId}/seatMatrix`)).json();
|
||||
// Matrix<json | null> -> Matrix<Seat | null>
|
||||
this.setLoadingStatus("Processing seats...");
|
||||
console.log("Matrix<json | null> -> Matrix<Seat | null>");
|
||||
this.seats = roomMatrix.map((row, rowIndex) => {
|
||||
return row.map((seat, colIndex) => {
|
||||
if (seat === null) {
|
||||
return null;
|
||||
}
|
||||
this.setLoadingStatus("Processing seats... " + Math.round((rowIndex * row.length + colIndex) / (row.length * row.length) * 100) + "%");
|
||||
return new Seat(
|
||||
seat['seat_id'],
|
||||
seat['seat_row'],
|
||||
seat['seat_column'],
|
||||
seat['seat_linked_id'],
|
||||
seat['reserved']
|
||||
seat['reserved'],
|
||||
seat['seat_type']
|
||||
);
|
||||
});
|
||||
});
|
||||
console.log(this.seats);
|
||||
await this.fixCoronaSeating();
|
||||
this.render();
|
||||
}
|
||||
|
||||
async fixCoronaSeating() {
|
||||
// the seat left or right of a set of reserved seats are not available
|
||||
this.seats.forEach((row, rowIndex) => {
|
||||
row.forEach((seat, colIndex) => {
|
||||
if (seat === null) return;
|
||||
if (seat.reserved) {
|
||||
if (row[colIndex - 1] && !row[colIndex - 1].reserved)
|
||||
row[colIndex - 1].type = 'not_available';
|
||||
if (row[colIndex + 1] && !row[colIndex + 1].reserved)
|
||||
row[colIndex + 1].type = 'not_available';
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
console.log("rendering");
|
||||
this.setLoadingStatus("Rendering...");
|
||||
let linkedCache = false;
|
||||
// render the seat chooser
|
||||
this.container.innerHTML = '';
|
||||
// this -> row -> seat
|
||||
this.container.innerHTML = '';
|
||||
this.seats.forEach((row, rowIndex) => {
|
||||
let rowDiv = document.createElement('div');
|
||||
rowDiv.classList.add('row');
|
||||
|
@ -64,7 +101,10 @@ class SeatChooser {
|
|||
let seatDiv = document.createElement('div');
|
||||
if (seat) {
|
||||
seatDiv.classList.add('seat');
|
||||
seatDiv.classList.add(seat.reserved ? 'reserved' : 'available');
|
||||
if (seat.reserved) {
|
||||
seatDiv.classList.add('reserved');
|
||||
seatDiv.title = 'This seat is reserved';
|
||||
}
|
||||
|
||||
if (seat.linked) {
|
||||
// if cache is false, then this is the first seat in the linked pair
|
||||
|
@ -81,6 +121,27 @@ class SeatChooser {
|
|||
|
||||
seatDiv.innerText = `${seat.row}-${seat.col}`;
|
||||
|
||||
switch (seat.type) {
|
||||
case 'not_available':
|
||||
seatDiv.title = 'This seat is not available';
|
||||
seatDiv.classList.add('disabled');
|
||||
break;
|
||||
|
||||
case 'wheelchair':
|
||||
seatDiv.title = 'This seat is wheelchair accessible';
|
||||
seatDiv.classList.add('wheelchair');
|
||||
break;
|
||||
|
||||
case 'loveseat':
|
||||
seatDiv.title = 'This seat is a loveseat';
|
||||
seatDiv.classList.add('loveseat');
|
||||
break;
|
||||
|
||||
case 'standard':
|
||||
seatDiv.title = 'This is a standard seat';
|
||||
break;
|
||||
}
|
||||
|
||||
seatDiv.dataset.id = seat.id;
|
||||
seatDiv.dataset.row = seat.row;
|
||||
seatDiv.dataset.col = seat.col;
|
||||
|
@ -95,12 +156,37 @@ class SeatChooser {
|
|||
});
|
||||
this.container.appendChild(rowDiv);
|
||||
});
|
||||
|
||||
// button container
|
||||
let buttonContainer = document.createElement('div');
|
||||
buttonContainer.style.display = 'flex';
|
||||
|
||||
// clear button
|
||||
let clearButton = document.createElement('button');
|
||||
clearButton.classList.add('button');
|
||||
clearButton.style.margin = '1rem';
|
||||
clearButton.innerText = 'Clear';
|
||||
clearButton.addEventListener('click', () => {
|
||||
this.clearSelection();
|
||||
});
|
||||
buttonContainer.appendChild(clearButton);
|
||||
|
||||
// submit button
|
||||
let submitButton = document.createElement('button');
|
||||
submitButton.classList.add('button');
|
||||
submitButton.style.margin = '1rem';
|
||||
submitButton.innerText = 'Submit';
|
||||
submitButton.addEventListener('click', () => {
|
||||
this.submitCallback(this);
|
||||
});
|
||||
buttonContainer.appendChild(submitButton);
|
||||
this.container.appendChild(buttonContainer);
|
||||
}
|
||||
|
||||
toggleSeat(seat, e) {
|
||||
// toggle the seat
|
||||
// because of linked seats, we need to toggle both seats
|
||||
if (seat.reserved) return;
|
||||
if (seat.reserved || seat.type == 'not_available') return;
|
||||
e.target.classList.toggle('selected');
|
||||
if (seat.linked) {
|
||||
// beware that you can click on the left or right seat
|
||||
|
@ -124,6 +210,30 @@ class SeatChooser {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
clearSelection() {
|
||||
this.selectedSeats.forEach(seat => {
|
||||
let seatDiv = this.container.querySelector(`[data-id="${seat.id}"]`);
|
||||
seatDiv.classList.remove('selected');
|
||||
});
|
||||
this.selectedSeats = [];
|
||||
}
|
||||
}
|
||||
|
||||
let seatChooser = new SeatChooser(1, document.getElementById('seat-chooser'));
|
||||
let seatChooser = new SeatChooser(1, document.getElementById('seat-chooser'), (sc) => {
|
||||
// gray overlay and show selected seats
|
||||
let overlay = document.createElement('div');
|
||||
overlay.style.position = 'fixed';
|
||||
overlay.style.top = '0';
|
||||
overlay.style.left = '0';
|
||||
overlay.style.width = '100vw';
|
||||
overlay.style.height = '100vh';
|
||||
overlay.style.backgroundColor = 'rgba(0,0,0,0.5)';
|
||||
overlay.style.display = 'flex';
|
||||
overlay.style.justifyContent = 'center';
|
||||
overlay.innerText = 'You selected the following seats: ' + sc.selectedSeats.map(seat => `${seat.row}-${seat.col}`).join(', ');
|
||||
overlay.addEventListener('click', () => {
|
||||
overlay.remove();
|
||||
});
|
||||
sc.container.appendChild(overlay);
|
||||
});
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
@extends('layout')
|
||||
|
||||
@push('head')
|
||||
<link rel="stylesheet" href="{{ asset('css/generic.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('css/seat-chooser.css') }}">
|
||||
<script src="{{ asset('js/seat-chooser.js') }}" defer></script>
|
||||
@endpush
|
||||
|
|
Loading…
Reference in a new issue