js map controllers created

This commit is contained in:
s416422 2019-12-07 19:49:42 +01:00
parent 1636111b64
commit 3d13bdb8bb
20 changed files with 1285 additions and 27 deletions

View File

@ -7,6 +7,6 @@ use Illuminate\Database\Eloquent\Model;
class Classes extends Model
{
protected $fillable = [
'subject_id', 'date'
'subject_id', 'date', 'classes_code'
];
}

View File

@ -52,31 +52,41 @@ class UserClassesController extends Controller
public function start_classes($classes_id)
{
$classes_code = generateRandomString(10);
session([
'CLASSES_CODE' => $classes_code,
'CLASSES_ID' => $classes_id
]);
$classes = Classes::find($classes_id);
return view('user.user_classes_start', ['verified' => false, 'classes_code' => $classes_code, 'classes' => $classes]);
$classes_code = $classes->classes_code;
if(!$classes_code){
$classes_code = generateRandomString(10);
$classes->classes_code = $classes_code;
$classes->save();
}
return view('map.start_map', ['classes_code' => $classes_code, 'classes' => $classes]);
}
public function start_classes_verified(Request $request)
{
$student_id_number = $request->input('student_id_number');
$student_name = $request->input('student_name');
$student_surname = $request->input('student_surname');
$classes = Classes::find($request->get('classes_id'));
$room = Room::find(Subject::find($classes->subject_id)->room_id)->name;
$attendances = Attendance::where('classes_id', $classes->id)->get();
$seat_numbers = $attendances->pluck('seat_number')->toArray();
return view('map.seat_map', ['student_name' => $student_name, 'student_surname' => $student_surname, 'student_id_number' => $student_id_number, 'classes_id' => $classes->id, 'seat_numbers' => $seat_numbers]);
}
public function save_classes_data(Request $request)
{
$classes_id = $request->input('classes_id');
$student_id_number = $request->input('student_id_number');
$student_name = $request->input('student_name');
$student_surname = $request->input('student_surname');
$seat_number = $request->input('seat_number');
Attendance::create([
'classes_id' => $classes->id,
'classes_id' => $classes_id,
'student_id_number' => $student_id_number,
'student_name' => $student_name,
'student_surname' => $student_surname,
'seat_number' => $seat_number,
]);
$attendances = Attendance::where('classes_id', $classes->id)->get();
return view('user.user_classes_start', ['verified' => true, 'room' => $room, 'attendances' => $attendances]);
return view('map.summary_map', ['student_name' => $student_name, 'student_surname' => $student_surname, 'seat_number' => $seat_number, 'student_id_number' => $student_id_number, 'classes_id' => $classes_id]);
}
}

View File

@ -20,19 +20,13 @@ class CheckClassesCode
public function handle($request, Closure $next)
{
$classes_code_from_request = $request->input('classes_code');
$classes_code_from_session = session()->get('CLASSES_CODE');
$classes_id = session()->get('CLASSES_ID');
$classes = Classes::find($classes_id);
$classes = Classes::where('classes_code', $classes_code_from_request)->first();
if(!$classes) {
return redirect('home');
} else {
if ($classes_code_from_request != $classes_code_from_session) {
$user_id = Subject::where('id', $classes->subject_id)->first()->user_id;
if (!$user_id || $user_id != Auth::id()) {
return redirect('home');
} else {
$user_id = Subject::where('id', $classes->subject_id)->first()->user_id;
if (!$user_id || $user_id != Auth::id()) {
return redirect('home');
}
}
}
$request->attributes->add(['classes_id' => $classes->id]);

View File

@ -19,6 +19,7 @@ class VerifyCsrfToken extends Middleware
* @var array
*/
protected $except = [
'user/classes/start'
'user/classes/start',
'user/classes/save'
];
}

View File

@ -17,6 +17,7 @@ class CreateClassesTable extends Migration
$table->bigIncrements('id')->unique();
$table->integer('subject_id');
$table->date('date');
$table->string('classes_code')->nullable();
$table->timestamps();
});
}

View File

@ -0,0 +1,71 @@
div.seatCharts-container {
/*min-width: 700px;*/
}
div.seatCharts-cell {
height: 16px;
width: 16px;
margin: 3px;
float: left;
text-align: center;
outline: none;
font-size: 13px;
line-height:16px;
color: blue;
}
div.seatCharts-seat {
background-color: green;
color: white;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
cursor: default;
}
div.seatCharts-seat:focus {
border: none;
}
/*
.seatCharts-seat:focus {
outline: none;
}
*/
div.seatCharts-space {
background-color: white;
}
div.seatCharts-row {
height: 50px;
}
div.seatCharts-row:after {
clear: both;
}
div.seatCharts-seat.selected {
background-color: aqua;
}
div.seatCharts-seat.focused {
background-color: #6db131;
}
div.seatCharts-seat.available {
background-color: green;
}
div.seatCharts-seat.unavailable {
background-color: red;
cursor: not-allowed;
}
ul.seatCharts-legendList {
list-style: none;
}
li.seatCharts-legendItem {
margin-top: 10px;
line-height: 2;
}
li.seatCharts-legendItem div {
cursor: default;
}

View File

@ -0,0 +1,55 @@
body {
font-family: monospace, sans-serif;
}
.wrapper {
text-align: center;
margin: 100px;
background-color: rgba(159, 183, 218, 0.856);
border-radius: 10px;
padding: 50px 0;
}
.wrapper h2 {
font-size: 38px;
padding: 15px 0;
}
.wrapper h3 {
font-size: 22px;
}
#selected-seats {
font-size: 30px;
text-shadow: 1px 1px 1px rgb(160, 160, 160);
margin-top: -15px;
margin-bottom: 100px;
}
button {
margin: auto 0;
font-size: 18px;
background-color: #5d7cd3;
border-radius: 2px;
border: 0;
min-width: 250px;
padding: 25px 60px;
text-align: center;
box-shadow:0px 4px 0px #1e3572;
font-family: monospace;
float: right;
}
button:hover {
box-shadow: 0 0 rgb(103, 88, 184);
background-color: #3654c9;
cursor: pointer;
}
button:active {
top: 4px;
box-shadow: 0 0 #b85a5b;
background-color: #3654ff;
}

View File

@ -0,0 +1,96 @@
body {
background: rgb(210, 218, 231);
}
.wrapper {
margin: 0 auto;
display: inline-block;
background-color: rgba(159, 183, 218, 0.856);
border-radius: 10px;
width: 70%;
height:60vh;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.czytnik {
display: inline-block;
text-align: center;
position: absolute;
left: 50%;
bottom: -20%;
transform: translate(-50%, -10%);
background-color: rgba(139, 152, 172, 0.856);
padding: 30px 80px;
font-family: monospace;
font-size: 30px;
}
.czytnik:hover {
box-shadow: 0 0 rgb(103, 88, 184);
background-color: #3654c9;
cursor: progress;
}
.code-p {
text-align: center;
}
.main-text {
font-family: "Oswald", Tahoma, sans-serif;
font-weight: bold;
text-transform: uppercase;
letter-spacing: .15em;
display: inline-block;
text-shadow: 0 0 80px rgba(255,255,255,.5);
color: #1C1C1C;
text-align: center;
line-height: 15vh;
font-size: 11vh;
height: 10%;
}
@media (max-width: 1300px) {
.main-text {
font-size: 7.5vh;
width: 100%;
}
}
@media (max-width: 900px) {
.wrapper {
height: 40%;
}
.main-text {
font-size: 3.3em;
line-height: 10vh;
width: 100%;
}
.czytnik {
bottom: -30%;
transform: translate(-50%, -10%);
padding: 30px 50px;
font-size: 25px;
}
}
@media (max-width: 650px) {
.wrapper {
height: 30%;
}
.main-text {
font-size: 2.1em;
line-height: 6vh;
width: 100%;
padding: 20px 0;
}
}

View File

@ -0,0 +1,153 @@
body {
font-family: 'Lato', sans-serif;
font-style: #b71a4c;
}
a {
color: #b71a4c;
}
.front-indicator {
width: 90%;
margin: 5px 32px 5px 32px;
background-color: #f6f6f6;
color: #adadad;
text-align: center;
padding: 15px;
border-radius: 5px;
}
.container {
margin: 0 auto;
text-align: left;
}
.seat-stat-wrapper {
display: inline;
}
#legend {
width: 49%;
margin: 0 auto;
float: left;
font-family: monospace;
font-size: 16px;
}
.booking-details {
display: inline-block;
text-align: right;
font-size: 12px;
width: 49%;
margin: 0 auto;
}
@media screen and (max-width: 550px) {
#legend {
width: 100%;
}
.booking-details {
width: 100%;
text-align: left;
}
}
.booking-details h2 {
margin: 25px 0 20px 0;
font-size: 35px;
color: #333333;
font-family: monospace;
letter-spacing: 0.15em;
font-weight: bold;
}
.booking-details h3 {
margin: 5px 5px 0 0;
font-size: 18px;
color: #333333;
font-family: monospace;
font-weight: bold;
}
div.seatCharts-cell {
color: #182C4E;
height: 90px;
width: 90px;
line-height: 90px;
}
div.seatCharts-seat {
color: #FFFFFF;
cursor: pointer;
}
div.seatCharts-row {
height: 100px;
width: 90%;
display: flex;
/*align-items: center;*/
justify-content: center;
}
div.seatCharts-seat.available {
background-color: #a8b9bd;
}
div.seatCharts-seat.available.student-class {
background-color: #a8b9bd;
}
div.seatCharts-seat.focused {
background-color: #758184;
}
div.seatCharts-seat.selected {
background-color: rgb(216, 196, 230);
}
div.seatCharts-seat.unavailable {
background-color: #caaa41;
}
div.seatCharts-container {
width: 80%;
padding: 20px 0;
margin: 0 auto;
text-align: center;
}
div.seatCharts-legend {
display: inline-block;
}
div.seatCharts-legend li {
text-align: left;
}
ul.seatCharts-legendList {
padding-left: 0px;
}
span.seatCharts-legendDescription {
margin-left: 5px;
line-height: 100px;
}
.checkout-button {
margin: 10px 0;
font-size: 14px;
background-color: #5d7cd3;
border-radius: 2px;
border: 0;
padding: 15px 40px;
display: inline-block;
text-align: center;
box-shadow:0px 4px 0px #1e3572;
font-family: monospace;
}
.checkout-button:hover {
box-shadow: 0 0 rgb(103, 88, 184);
background-color: #3654c9;
cursor: pointer;
}
.checkout-button:active {
top: 4px;
box-shadow: 0 0 #b85a5b;
background-color: #3654ff;
}
#selected-seats {
list-style-type: none;
font-size: 14px;
margin-left: 0;
padding-left: 0;
}

View File

@ -0,0 +1,627 @@
/*!
* jQuery-Seat-Charts v1.1.5
* https://github.com/mateuszmarkowski/jQuery-Seat-Charts
*
* Copyright 2013, 2016 Mateusz Markowski
* Released under the MIT license
*/
(function($) {
//'use strict';
$.fn.seatCharts = function (setup) {
//if there's seatCharts object associated with the current element, return it
if (this.data('seatCharts')) {
return this.data('seatCharts');
}
var fn = this,
seats = {},
seatIds = [],
legend,
settings = {
animate : false, //requires jQuery UI
naming : {
top : true,
left : true,
getId : function(character, row, column) {
return row + '_' + column;
},
getLabel : function (character, row, column) {
return column;
}
},
legend : {
node : null,
items : []
},
click : function() {
if (this.status() == 'available') {
return 'selected';
} else if (this.status() == 'selected') {
return 'available';
} else {
return this.style();
}
},
focus : function() {
if (this.status() == 'available') {
return 'focused';
} else {
return this.style();
}
},
blur : function() {
return this.status();
},
seats : {}
},
//seat will be basically a seat object which we'll when generating the map
seat = (function(seatCharts, seatChartsSettings) {
return function (setup) {
var fn = this;
fn.settings = $.extend({
status : 'available', //available, unavailable, selected
style : 'available',
//make sure there's an empty hash if user doesn't pass anything
data : seatChartsSettings.seats[setup.character] || {}
//anything goes here?
}, setup);
fn.settings.$node = $('<div></div>');
fn.settings.$node
.attr({
id : fn.settings.id,
role : 'checkbox',
'aria-checked' : false,
focusable : true,
tabIndex : -1 //manual focus
})
.text(fn.settings.label)
.addClass(['seatCharts-seat', 'seatCharts-cell', 'available'].concat(
//let's merge custom user defined classes with standard JSC ones
fn.settings.classes,
typeof seatChartsSettings.seats[fn.settings.character] == "undefined" ?
[] : seatChartsSettings.seats[fn.settings.character].classes
).join(' '));
//basically a wrapper function
fn.data = function() {
return fn.settings.data;
};
fn.char = function() {
return fn.settings.character;
};
fn.node = function() {
return fn.settings.$node;
};
/*
* Can either set or return status depending on arguments.
*
* If there's no argument, it will return the current style.
*
* If you pass an argument, it will update seat's style
*/
fn.style = function() {
return arguments.length == 1 ?
(function(newStyle) {
var oldStyle = fn.settings.style;
//if nothing changes, do nothing
if (newStyle == oldStyle) {
return oldStyle;
}
//focused is a special style which is not associated with status
fn.settings.status = newStyle != 'focused' ? newStyle : fn.settings.status;
fn.settings.$node
.attr('aria-checked', newStyle == 'selected');
//if user wants to animate status changes, let him do this
seatChartsSettings.animate ?
fn.settings.$node.switchClass(oldStyle, newStyle, 200) :
fn.settings.$node.removeClass(oldStyle).addClass(newStyle);
return fn.settings.style = newStyle;
})(arguments[0]) : fn.settings.style;
};
//either set or retrieve
fn.status = function() {
return fn.settings.status = arguments.length == 1 ?
fn.style(arguments[0]) : fn.settings.status;
};
//using immediate function to convienietly get shortcut variables
(function(seatSettings, character, seat) {
//attach event handlers
$.each(['click', 'focus', 'blur'], function(index, callback) {
//we want to be able to call the functions for each seat object
fn[callback] = function() {
if (callback == 'focus') {
//if there's already a focused element, we have to remove focus from it first
if (seatCharts.attr('aria-activedescendant') !== undefined) {
seats[seatCharts.attr('aria-activedescendant')].blur();
}
seatCharts.attr('aria-activedescendant', seat.settings.id);
seat.node().focus();
}
/*
* User can pass his own callback function, so we have to first check if it exists
* and if not, use our default callback.
*
* Each callback function is executed in the current seat context.
*/
return fn.style(typeof seatSettings[character][callback] === 'function' ?
seatSettings[character][callback].apply(seat) : seatChartsSettings[callback].apply(seat));
};
});
//the below will become seatSettings, character, seat thanks to the immediate function
})(seatChartsSettings.seats, fn.settings.character, fn);
fn.node()
//the first three mouse events are simple
.on('click', fn.click)
.on('mouseenter', fn.focus)
.on('mouseleave', fn.blur)
//keydown requires quite a lot of logic, because we have to know where to move the focus
.on('keydown', (function(seat, $seat) {
return function (e) {
var $newSeat;
//everything depends on the pressed key
switch (e.which) {
//spacebar will just trigger the same event mouse click does
case 32:
e.preventDefault();
seat.click();
break;
//UP & DOWN
case 40:
case 38:
e.preventDefault();
/*
* This is a recursive, immediate function which searches for the first "focusable" row.
*
* We're using immediate function because we want a convenient access to some DOM elements
* We're using recursion because sometimes we may hit an empty space rather than a seat.
*
*/
$newSeat = (function findAvailable($rows, $seats, $currentRow) {
var $newRow;
//let's determine which row should we move to
if (!$rows.index($currentRow) && e.which == 38) {
//if this is the first row and user has pressed up arrow, move to the last row
$newRow = $rows.last();
} else if ($rows.index($currentRow) == $rows.length-1 && e.which == 40) {
//if this is the last row and user has pressed down arrow, move to the first row
$newRow = $rows.first();
} else {
//using eq to get an element at the desired index position
$newRow = $rows.eq(
//if up arrow, then decrement the index, if down increment it
$rows.index($currentRow) + (e.which == 38 ? (-1) : (+1))
);
}
//now that we know the row, let's get the seat using the current column position
$newSeat = $newRow.find('.seatCharts-seat,.seatCharts-space').eq($seats.index($seat));
//if the seat we found is a space, keep looking further
return $newSeat.hasClass('seatCharts-space') ?
findAvailable($rows, $seats, $newRow) : $newSeat;
})($seat
//get a reference to the parent container and then select all rows but the header
.parents('.seatCharts-container')
.find('.seatCharts-row:not(.seatCharts-header)'),
$seat
//get a reference to the parent row and then find all seat cells (both seats & spaces)
.parents('.seatCharts-row:first')
.find('.seatCharts-seat,.seatCharts-space'),
//get a reference to the current row
$seat.parents('.seatCharts-row:not(.seatCharts-header)')
);
//we couldn't determine the new seat, so we better give up
if (!$newSeat.length) {
return;
}
//remove focus from the old seat and put it on the new one
seat.blur();
seats[$newSeat.attr('id')].focus();
$newSeat.focus();
//update our "aria" reference with the new seat id
seatCharts.attr('aria-activedescendant', $newSeat.attr('id'));
break;
//LEFT & RIGHT
case 37:
case 39:
e.preventDefault();
/*
* The logic here is slightly different from the one for up/down arrows.
* User will be able to browse the whole map using just left/right arrow, because
* it will move to the next row when we reach the right/left-most seat.
*/
$newSeat = (function($seats) {
if (!$seats.index($seat) && e.which == 37) {
//user has pressed left arrow and we're currently on the left-most seat
return $seats.last();
} else if ($seats.index($seat) == $seats.length -1 && e.which == 39) {
//user has pressed right arrow and we're currently on the right-most seat
return $seats.first();
} else {
//simply move one seat left or right depending on the key
return $seats.eq($seats.index($seat) + (e.which == 37 ? (-1) : (+1)));
}
})($seat
.parents('.seatCharts-container:first')
.find('.seatCharts-seat:not(.seatCharts-space)'));
if (!$newSeat.length) {
return;
}
//handle focus
seat.blur();
seats[$newSeat.attr('id')].focus();
$newSeat.focus();
//update our "aria" reference with the new seat id
seatCharts.attr('aria-activedescendant', $newSeat.attr('id'));
break;
default:
break;
}
};
})(fn, fn.node()));
//.appendTo(seatCharts.find('.' + row));
}
})(fn, settings);
fn.addClass('seatCharts-container');
//true -> deep copy!
$.extend(true, settings, setup);
//Generate default row ids unless user passed his own
settings.naming.rows = settings.naming.rows || (function(length) {
var rows = [];
for (var i = 1; i <= length; i++) {
rows.push(i);
}
return rows;
})(settings.map.length);
//Generate default column ids unless user passed his own
settings.naming.columns = settings.naming.columns || (function(length) {
var columns = [];
for (var i = 1; i <= length; i++) {
columns.push(i);
}
return columns;
})(settings.map[0].split('').length);
if (settings.naming.top) {
var $headerRow = $('<div></div>')
.addClass('seatCharts-row seatCharts-header');
if (settings.naming.left) {
$headerRow.append($('<div></div>').addClass('seatCharts-cell'));
}
$.each(settings.naming.columns, function(index, value) {
$headerRow.append(
$('<div></div>')
.addClass('seatCharts-cell')
.text(value)
);
});
}
fn.append($headerRow);
//do this for each map row
$.each(settings.map, function(row, characters) {
var $row = $('<div></div>').addClass('seatCharts-row');
if (settings.naming.left) {
$row.append(
$('<div></div>')
.addClass('seatCharts-cell seatCharts-space')
.text(settings.naming.rows[row])
);
}
/*
* Do this for each seat (letter)
*
* Now users will be able to pass custom ID and label which overwrite the one that seat would be assigned by getId and
* getLabel
*
* New format is like this:
* a[ID,label]a[ID]aaaaa
*
* So you can overwrite the ID or label (or both) even for just one seat.
* Basically ID should be first, so if you want to overwrite just label write it as follows:
* a[,LABEL]
*
* Allowed characters in IDs areL 0-9, a-z, A-Z, _
* Allowed characters in labels are: 0-9, a-z, A-Z, _, ' ' (space)
*
*/
$.each(characters.match(/[a-z_]{1}(\[[0-9a-z_]{0,}(,[0-9a-z_ ]+)?\])?/gi), function (column, characterParams) {
var matches = characterParams.match(/([a-z_]{1})(\[([0-9a-z_ ,]+)\])?/i),
//no matter if user specifies [] params, the character should be in the second element
character = matches[1],
//check if user has passed some additional params to override id or label
params = typeof matches[3] !== 'undefined' ? matches[3].split(',') : [],
//id param should be first
overrideId = params.length ? params[0] : null,
//label param should be second
overrideLabel = params.length === 2 ? params[1] : null;
$row.append(character != '_' ?
//if the character is not an underscore (empty space)
(function(naming) {
//so users don't have to specify empty objects
settings.seats[character] = character in settings.seats ? settings.seats[character] : {};
var id = overrideId ? overrideId : naming.getId(character, naming.rows[row], naming.columns[column]);
seats[id] = new seat({
id : id,
label : overrideLabel ?
overrideLabel : naming.getLabel(character, naming.rows[row], naming.columns[column]),
row : row,
column : column,
character : character
});
seatIds.push(id);
return seats[id].node();
})(settings.naming) :
//this is just an empty space (_)
$('<div></div>').addClass('seatCharts-cell seatCharts-space')
);
});
fn.append($row);
});
//if there're any legend items to be rendered
settings.legend.items.length ? (function(legend) {
//either use user-defined container or create our own and insert it right after the seat chart div
var $container = (legend.node || $('<div></div>').insertAfter(fn))
.addClass('seatCharts-legend');
var $ul = $('<ul></ul>')
.addClass('seatCharts-legendList')
.appendTo($container);
$.each(legend.items, function(index, item) {
$ul.append(
$('<li></li>')
.addClass('seatCharts-legendItem')
.append(
$('<div></div>')
//merge user defined classes with our standard ones
.addClass(['seatCharts-seat', 'seatCharts-cell', item[1]].concat(
settings.classes,
typeof settings.seats[item[0]] == "undefined" ? [] : settings.seats[item[0]].classes).join(' ')
)
)
.append(
$('<span></span>')
.addClass('seatCharts-legendDescription')
.text(item[2])
)
);
});
return $container;
})(settings.legend) : null;
fn.attr({
tabIndex : 0
});
//when container's focused, move focus to the first seat
fn.focus(function() {
if (fn.attr('aria-activedescendant')) {
seats[fn.attr('aria-activedescendant')].blur();
}
fn.find('.seatCharts-seat:not(.seatCharts-space):first').focus();
seats[seatIds[0]].focus();
});
//public methods of seatCharts
fn.data('seatCharts', {
seats : seats,
seatIds : seatIds,
//set for one, set for many, get for one
status: function() {
var fn = this;
return arguments.length == 1 ? fn.seats[arguments[0]].status() : (function(seatsIds, newStatus) {
return typeof seatsIds == 'string' ? fn.seats[seatsIds].status(newStatus) : (function() {
$.each(seatsIds, function(index, seatId) {
fn.seats[seatId].status(newStatus);
});
})();
})(arguments[0], arguments[1]);
},
each : function(callback) {
var fn = this;
for (var seatId in fn.seats) {
if (false === callback.call(fn.seats[seatId], seatId)) {
return seatId;//return last checked
}
}
return true;
},
node : function() {
var fn = this;
//basically create a CSS query to get all seats by their DOM ids
return $('#' + fn.seatIds.join(',#'));
},
find : function(query) {//D, a.available, unavailable
var fn = this;
var seatSet = fn.set();
//is RegExp
return query instanceof RegExp ?
(function () {
fn.each(function (id) {
if (id.match(query)) {
seatSet.push(id, this);
}
});
return seatSet;
})() :
(query.length == 1 ?
(function (character) {
//user searches just for a particual character
fn.each(function () {
if (this.char() == character) {
seatSet.push(this.settings.id, this);
}
});
return seatSet;
})(query) :
(function () {
//user runs a more sophisticated query, so let's see if there's a dot
return query.indexOf('.') > -1 ?
(function () {
//there's a dot which separates character and the status
var parts = query.split('.');
fn.each(function (seatId) {
if (this.char() == parts[0] && this.status() == parts[1]) {
seatSet.push(this.settings.id, this);
}
});
return seatSet;
})() :
(function () {
fn.each(function () {
if (this.status() == query) {
seatSet.push(this.settings.id, this);
}
});
return seatSet;
})();
})()
);
},
set : function set() {//inherits some methods
var fn = this;
return {
seats : [],
seatIds : [],
length : 0,
status : function() {
var args = arguments,
that = this;
//if there's just one seat in the set and user didn't pass any params, return current status
return this.length == 1 && args.length == 0 ? this.seats[0].status() : (function() {
//otherwise call status function for each of the seats in the set
$.each(that.seats, function() {
this.status.apply(this, args);
});
})();
},
node : function() {
return fn.node.call(this);
},
each : function() {
return fn.each.call(this, arguments[0]);
},
get : function() {
return fn.get.call(this, arguments[0]);
},
find : function() {
return fn.find.call(this, arguments[0]);
},
set : function() {
return set.call(fn);
},
push : function(id, seat) {
this.seats.push(seat);
this.seatIds.push(id);
++this.length;
}
};
},
//get one object or a set of objects
get : function(seatsIds) {
var fn = this;
return typeof seatsIds == 'string' ?
fn.seats[seatsIds] : (function() {
var seatSet = fn.set();
$.each(seatsIds, function(index, seatId) {
if (typeof fn.seats[seatId] === 'object') {
seatSet.push(seatId, fn.seats[seatId]);
}
});
return seatSet;
})();
}
});
return fn.data('seatCharts');
}
})(jQuery);

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,47 @@
function savePlaceNumber() {
const selected_id = $('.selected')[0].innerText;
if(selected_id) {
const seat_number_input = $('.seat_number')[0];
seat_number_input.value = selected_id;
console.log(seat_number_input.value)
}
}
function toggleButtonAvailability() {
const button = $('.checkout-button')[0];
const selected_place = $('.selected')[0];
if(!selected_place){
$(button).css('pointer-events', 'none');
$(button).css('cursor', 'unset');
} else {
$(button).css('pointer-events', 'unset');
$(button).css('cursor', 'pointer');
}
}
function checkForUnavailablePlaces() {
const unavailablePlaces = Array();
$('.unavailable_place').each(function(){
unavailablePlaces.push($(this).val());
});
console.log(unavailablePlaces);
const allPlaces = $('.seatCharts-seat.seatCharts-cell.available');
if(unavailablePlaces){
allPlaces.each(function(){
if(unavailablePlaces.includes($(this).text()) && !$(this).parent().hasClass('seatCharts-legendItem')) {
$(this).addClass('unavailable');
$(this).css('pointer-events', 'none');
}
});
}
}
$(document).ready(function(){
checkForUnavailablePlaces();
toggleButtonAvailability();
$('.seatCharts-seat').on('click', function(){
toggleButtonAvailability();
savePlaceNumber();
});
});

View File

@ -0,0 +1,99 @@
var firstSeatLabel = 1;
$(document).ready(function() {
var $cart = $('#selected-seats'),
$counter = $('#counter'),
$total = $('#total'),
sc = $('#seat-map').seatCharts({
map: [
'c[1,1]c[2,2]c[3,3]c[4,4]c[5,5]c[6,6]',
'_',
'c[7,7]c[8,8]c[9,9]c[10,10]c[11,11]c[12,12]',
'c[13,13]c[14,14]c[15,15]c[16,16]c[17,17]c[18,18]',
],
seats: {
h: {
price : 2500,
classes : 'student-class',
category: 'Student Seat'
},
},
naming : {
rows: ['','','',''],
top : false,
getLabel : function (character, row, column) {
if (row == '1') {
return column;
} else if (row == '2') {
return column;
} else if (row == '3') {
return column;
}
},
},
legend : {
node : $('#legend'),
items : [
[ 'c', 'available', 'Dostępne miejsce'],
[ 'f', 'unavailable', 'Zajęte miejsce']
]
},
click: function () {
if (this.status() == 'available' && recalculateTotal(sc) < 1) {
//let's create a new <li> which we'll add to the cart items
$('<span> '+this.settings.label+ '</span>')
.attr('id', 'cart-item-'+this.settings.id)
.data('seatId', this.settings.id)
.appendTo($cart);
/*
* Lets update the counter and total
*
* .find function will not find the current seat, because it will change its stauts only after return
* 'selected'. This is why we have to add 1 to the length and the current seat price to the total.
*/
$counter.text(sc.find('selected').length+1);
$total.text(recalculateTotal(sc)+1);
return 'selected';
} else if (this.status() == 'selected') {
//update the counter
$counter.text(sc.find('selected').length-1);
//and total
$total.text(recalculateTotal(sc)-1);
//remove the item from our cart
$('#cart-item-'+this.settings.id).remove();
//seat has been vacated
return 'available';
} else if (this.status() == 'unavailable') {
//seat has been already booked
return 'unavailable';
} else {
return this.style();
}
}
});
//this will handle "[cancel]" link clicks
$('#selected-seats').on('click', '.cancel-cart-item', function () {
//let's just trigger Click event on the appropriate seat, so we don't have to repeat the logic here
sc.get($(this).parents('li:first').data('seatId')).click();
});
//let's pretend some seats have already been booked
//sc.get(['1_2', '4_1', '7_1', '7_2']).status('unavailable');
});
function recalculateTotal(sc) {
var total = 0;
//basically find every selected seat and sum its price
sc.find('selected').each(function () {
total += 1;//this.data().price;
});
return total;
}

View File

@ -18,9 +18,6 @@
<label for="student_surname"> Nazwisko studenta: </label>
<input type="text" name="student_surname" id="student_surname">
<label for="seat_number"> Nr miejsca: </label>
<input type="text" name="seat_number" id="seat_number">
<button type="submit"> Test requesta </button>
</form>
</div>

View File

@ -0,0 +1,24 @@
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="UTF-8">
<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-1.14.0.css">
<link rel="stylesheet" href="{{ asset('js/app.js') }}">
<script src="http://code.jquery.com/qunit/qunit-1.14.0.js"></script>
<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
<script type="text/javascript" src="{{ asset('js/map/jquery.seat-charts.min.js') }}"></script>
<title> @CHECK | @yield('map_title') </title>
@yield('map_meta')
</head>
<body>
<div class="wrapper">
@yield('map_content')
</div>
</body>
</html>

View File

@ -0,0 +1,44 @@
@extends('layouts.map')
@section('title') Wybór miejsca @endsection
@section('map_meta')
<meta name="csrf-token" content="{{ csrf_token() }}">
<link rel="stylesheet" type="text/css" href="{{ asset('css/map/jquery.seat-charts.css') }}">
<link rel="stylesheet" type="text/css" href="{{ asset('css/map/seatchart.css') }}">
<script type="text/javascript" src="{{ asset('js/map/seatchart.js') }}"></script>
<script type="text/javascript" src="{{ asset('js/map/seatchart-custom.js') }}"></script>
@endsection
@section('map_content')
<div class="seat-chart-wrapper">
<div id="seat-map">
<div class="front-indicator">{{ App\Subject::find(App\Classes::find($classes_id)->subject_id)->name }},
{{ App\Subject::find(App\Classes::find($classes_id)->subject_id)->weekday }} {{ App\Classes::find($classes_id)->date }} {{ App\Subject::find(App\Classes::find($classes_id)->subject_id)->time }}</div>
</div>
</div>
<br/>
<div class='seat-stat-wrapper'>
<div id="legend">
</div>
<div class="booking-details">
<h2> <span class="student_name"> {{ $student_name }} </span><span class="student_surname"> {{ $student_surname }} </span> </h2>
<h3 class="student_id_number"> {{ $student_id_number }}</h3>
<h3>Wybrane miejsce:
<span id="selected-seats"></span>
</h3>
@foreach($seat_numbers as $seat_number)
<input type="hidden" class="unavailable_place" value="{{ $seat_number }}">
@endforeach
<form method="POST" action="{{ route('user_save_classes_data') }}">
<input type="hidden" value="{{ $classes_id }}" class="classes_id" name="classes_id">
<input type="hidden" value="{{ $student_name }}" class="student_name" name="student_name">
<input type="hidden" value="{{ $student_surname }}" class="student_surname" name="student_surname">
<input type="hidden" value="{{ $student_id_number }}" class="student_id_number" name="student_id_number">
<input type="hidden" value="" class="seat_number" name="seat_number">
<button type="submit" class="checkout-button">Zapisz &raquo;</button>
</form>
</div>
</div>
@endsection

View File

@ -0,0 +1,12 @@
@extends('layouts.map')
@section('title') Wybór miejsca @endsection
@section('map_meta')
<link rel="stylesheet" type="text/css" href="{{ asset('css/map/przylozlegitke.css') }}">
<script type="text/javascript" src="{{ asset('js/map/przylozlegitke.js') }}"></script>
@endsection
@section('map_content')
<p class="code-p"> <b>Kod:</b> {{ $classes_code }}</p>
<h1 class="main-text">Przyłóż legitymację do czytnika</h1>
@endsection

View File

@ -0,0 +1,17 @@
@extends('layouts.map')
@section('title') Wybór miejsca @endsection
@section('map_meta')
<link rel="stylesheet" type="text/css" href="{{ asset('css/map/koncowastrona.css') }}">
<script type="text/javascript" src="{{ asset('js/map/seatchart.js') }}"></script>
@endsection
@section('map_content')
<h2>{{ $student_name }} {{ $student_surname }}</h2>
<h3>{{ $student_id_number }} </h3>
<h3>wybrane miejsce:</h3>
<h3 id="selected-seats">{{ $seat_number }}</h3>
<a href="{{ route('user_start_classes', [$classes_id]) }}"><button type="button" class="checkout-button">Przejdź do strony głównej &raquo;</button></a>
@endsection

View File

@ -85,9 +85,9 @@
<td> {{ App\Subject::find($classes_item->subject_id)->name }},
{{ App\Subject::find($classes_item->subject_id)->weekday }} {{ App\Subject::find($classes_item->subject_id)->time }}</td>
<td> {{ $classes_item->date }} </td>
{{--<td>--}}
{{--<a href="{{ route('user_start_classes', [$classes_item->id]) }}" name="start-classes-btn" class="btn btn-warning"> Rozpocznij zapisy </a>--}}
{{--</td>--}}
<td>
<a href="{{ route('user_start_classes', [$classes_item->id]) }}" name="start-classes-btn" class="btn btn-warning"> Kontynuuj zapisy </a>
</td>
<td>
<a href="{{ route('user_delete_classes', [$classes_item->id]) }}" name="delete-classes-btn" class="btn btn-danger"> Usuń </a>
</td>

View File

@ -57,6 +57,7 @@ Route::group(array('prefix' => 'user', 'namespace' => 'User'), function() { //TO
Route::get('/classes/start/{classes_id}', 'UserClassesController@start_classes')->name('user_start_classes');
Route::post('/classes/start', 'UserClassesController@start_classes_verified')->name('user_start_classes_verified')->middleware('classesCode');
Route::post('/classes/save', 'UserClassesController@save_classes_data')->name('user_save_classes_data');
Route::group(array('prefix' => 'add'), function() {
Route::post('/subject', 'UserSubjectsController@add_subject')->name('user_add_subject');