Working on surveys/attendee questions

Working on attendee check-in page
This commit is contained in:
Dave 2016-04-07 14:33:07 +01:00 committed by Dave Earley
parent cef552ed04
commit 6127084c36
16 changed files with 311 additions and 23 deletions

View File

@ -45,7 +45,8 @@ class EventAttendeesController extends MyBaseController
->where(function ($query) use ($searchQuery) {
$query->where('orders.order_reference', 'like', $searchQuery.'%')
->orWhere('attendees.first_name', 'like', $searchQuery.'%')
->orWhere('attendees.email', 'like', $searchQuery.'%')
->orWhere('attendees.email', 'like', $searchQuery.'%')
->orWhere('attendees.reference', 'like', $searchQuery.'%')
->orWhere('attendees.last_name', 'like', $searchQuery.'%');
})
->orderBy(($sort_by == 'order_reference' ? 'orders.' : 'attendees.').$sort_by, $sort_order)

View File

@ -18,12 +18,20 @@ class EventCheckInController extends MyBaseController
*/
public function showCheckIn($event_id)
{
$data['event'] = Event::scope()->findOrFail($event_id);
$data['attendees'] = $data['event']->attendees;
return view('ManageEvent.CheckIn', $data);
}
public function showQRCodeModal(Request $request, $event_id)
{
return view('ManageEvent.Modals.QrcodeCheckIn');
}
/**
* Search attendees
*

View File

@ -431,7 +431,7 @@ class EventCheckoutController extends Controller
$event = Event::findOrFail($ticket_order['event_id']);
$attendee_increment = 1;
$mirror_buyer_info = isset($request_data['mirror_buyer_info']) ? ($request_data['mirror_buyer_info'] == 'on') : false;
$ticket_questions = $request_data['ticket_holder_questions'];
$ticket_questions = isset($request_data['ticket_holder_questions']) ? $request_data['ticket_holder_questions'] : [];
/*

View File

@ -9,6 +9,7 @@ use App\Models\Question;
use App\Models\QuestionAnswer;
use App\Models\QuestionType;
use Illuminate\Http\Request;
use Excel;
/*
Attendize.com - Event Management & Ticketing
@ -222,7 +223,6 @@ class EventSurveyController extends MyBaseController
*/
public function showEventQuestionAnswers(Request $request, $event_id, $question_id)
{
$answers = QuestionAnswer::scope()->where('question_id', $question_id)->get();
$question = Question::scope()->withTrashed()->find($question_id);

View File

@ -609,6 +609,10 @@ Route::group(['middleware' => ['auth', 'first.run']], function () {
'uses' => 'EventCheckInController@postCheckInAttendee',
]);
Route::get('{event_id}/check_in_qrcode', [
'as' => 'showQRCodeModal',
'uses' => 'EventCheckInController@showQRCodeModal'
]);
/*
* -------

View File

@ -51,6 +51,16 @@ class Event extends MyBaseModel
return $this->belongsToMany('\App\Models\Question', 'event_question');
}
/**
* The questions associated with the event.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function questions_with_tashed()
{
return $this->belongsToMany('\App\Models\Question', 'event_question')->withTrashed();
}
/**
* The attendees associated with the event.
*

View File

@ -37,7 +37,7 @@ class Question extends MyBaseModel
public function answers()
{
return $this->hasMany('\App\Models\Answers');
return $this->hasMany('\App\Models\QuestionAnswer');
}
/**

View File

@ -94,6 +94,6 @@ a:hover{
}
#v{
width: 300px;
width: 300px;
}
}

View File

@ -7,6 +7,7 @@
{!! HTML::style('assets/stylesheet/application.css') !!}
{!! HTML::script('vendor/jquery/jquery.js') !!}
{!! HTML::style('assets/stylesheet/qrcode-check-in.css') !!}
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0">
@ -40,6 +41,11 @@
:-ms-input-placeholder { /* Internet Explorer 10+ */
}
body {
background-color: #0384a6;
}
.attendeeList .container {
background: #fff;
border-radius: 2px;
@ -65,7 +71,7 @@
}
header {
background: #6784DB;
background-color: #FFF;
padding: 10px 0;
position: fixed;
top: 0;
@ -93,11 +99,20 @@
height: 40px;
}
.qr_search {
height: 40px;
background: #FFF;
color: #000;
font-size: 25px;
border: none;
border-right: 1px solid #999;
}
.clearSearch {
position: absolute;
top: 10px;
top: 8px;
right: 25px;
font-size: 20px;
font-size: 24px;
cursor: pointer;
display: none;
}
@ -149,6 +164,10 @@
@media (min-width: 100px) and (max-width: 767px) {
header {
border-bottom: 1px solid #ddd;
}
section.attendeeList {
margin-top: 60px;
}
@ -300,6 +319,12 @@
search();
});
$('.qr_search').on('click', function(e) {
load();
$('#QrModal').modal('show');
});
$("input#search").on("keyup", function(e) {
clearTimeout($.data(this, 'timer'));
var search_string = $(this).val();
@ -319,6 +344,7 @@
</head>
<body>
<header>
<div class="menuToggle hide">
<i class="ico-menu"></i>
@ -327,11 +353,19 @@
<div class="row">
<div class="col-md-12">
<div class="attendee_input_wrap">
{!! Form::text('attendees_q', null, [
<div class="input-group">
<span class="input-group-btn">
<button title="Scan QR Code" class="btn btn-default qr_search" type="button"><i class="ico-qrcode"></i> </button>
</span>
{!! Form::text('attendees_q', null, [
'class' => 'form-control attendee_search',
'id' => 'search',
'placeholder' => 'Search by Attendee Name, Order Reference, Attendee Reference... '
]) !!}
</div>
<span class="clearSearch ico-cancel"></span>
</div>
</div>
@ -345,9 +379,9 @@
<div class="row">
<div class="col-md-12">
<div class="attendee_list">
<h3 class="attendees_title">
<h4 class="attendees_title">
All Attendees
</h3>
</h4>
<ul class="list-group" id="attendee_list">
Loading Attendees...
</ul>
@ -361,10 +395,221 @@
<div class="container">
<div class="row">
<div class="col-md-12">
23/145 attendees checked in.
</div>
</div>
</div>
</footer>
{{--QR Modal--}}
<div role="dialog" id="QrModal" class="modal fade" style="display: none;">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header text-center">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h3 class="modal-title">
<i class="ico-qrcode"></i>
Check-in
</h3>
</div>
<div class="modal-body">
@if(session()->has('success_message'))
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3 col-xs-12">
<div class="alert alert-success alert-dismissible text-center" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<p><strong>Success</strong>: {{ session('success_message') }}</p>
</div>
</div>
</div>
</div>
@endif
<div id="outdiv">
</div>
<p><a onclick="event.preventDefault(); workingAway = false; load();" href="{{ Request::url() }}"><i class="fa fa-refresh"></i> Scan another ticket</a></p>
<div id="result"></div>
<canvas id="qr-canvas" width="800" height="600"></canvas>
</div>
<div class="modal-footer">
{!! Form::button('Close', ['class'=>"btn modal-close btn-danger",'data-dismiss'=>'modal']) !!}
</div>
</div><!-- /end modal content-->
</div>
</div>
{{-- /END QR Modal--}}
{!! HTML::script('vendor/qrcode-scan/llqrcode.js') !!}
{{--QR JS - THIS WILL BE MOVED--}}
<script>
// QRCODE reader Copyright 2011 Lazar Laszlo
// http://www.webqr.com
var workingAway = false;
var gCtx = null;
var gCanvas = null;
var c=0;
var stype=0;
var gUM=false;
var webkit=false;
var moz=false;
var v=null;
var beepSound = new Audio('/mp3/beep.mp3');
var vidhtml = '<video id="v" autoplay></video>';
function initCanvas(w,h)
{
gCanvas = document.getElementById("qr-canvas");
gCanvas.style.width = w + "px";
gCanvas.style.height = h + "px";
gCanvas.width = w;
gCanvas.height = h;
gCtx = gCanvas.getContext("2d");
gCtx.clearRect(0, 0, w, h);
}
function captureToCanvas() {
if(stype!=1)
return;
if(gUM)
{
try{
gCtx.drawImage(v,0,0);
try{
qrcode.decode();
}
catch(e){
console.log(e);
setTimeout(captureToCanvas, 500);
};
}
catch(e){
console.log(e);
setTimeout(captureToCanvas, 500);
};
}
}
function htmlEntities(str) {
return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}
function read(qrcode_token)
{
if(workingAway) {
return;
}
workingAway = true;
$.ajax({
type: "POST",
url: '{{ route('postQRCodeCheckInAttendee', ['event_id' => $event->id]) }}',
data: {qrcode_token: htmlEntities(qrcode_token)},
cache: false,
complete: function(){
beepSound.play();
},
error: function() {
},
success: function(response) {
document.getElementById("result").innerHTML = "<b>" + response.message +"</b>";
}
});
}
function isCanvasSupported(){
var elem = document.createElement('canvas');
return !!(elem.getContext && elem.getContext('2d'));
}
function success(stream) {
if(webkit)
v.src = window.webkitURL.createObjectURL(stream);
else
if(moz)
{
v.mozSrcObject = stream;
v.play();
}
else
v.src = stream;
gUM=true;
setTimeout(captureToCanvas, 500);
}
function error(error) {
gUM=false;
return;
}
function load()
{
if(isCanvasSupported() && window.File && window.FileReader)
{
initCanvas(800, 600);
qrcode.callback = read;
setwebcam();
}
else
{
document.getElementById("mainbody").style.display="inline";
document.getElementById("mainbody").innerHTML='<p id="mp1">Attendize Checkpoint Manager for HTML5 capable browsers</p><br>'+
'<br><p id="mp2">sorry your browser is not supported</p><br><br>'+
'<p id="mp1">try <a href="http://www.mozilla.com/firefox"><img src="/assets/images/firefox.png"/></a> or <a href="http://chrome.google.com"><img src="/assets/images/chrome_logo.gif"/></a> or <a href="http://www.opera.com"><img src="/assets/images/Opera-logo.png"/></a></p>';
}
}
function setwebcam()
{
// document.getElementById("help-text").style.display = "block";
document.getElementById("result").innerHTML='Scanning&nbsp;&nbsp;&nbsp;<i class="fa fa-spinner fa-spin"></i>';
if(stype==1)
{
setTimeout(captureToCanvas, 500);
return;
}
var n=navigator;
document.getElementById("outdiv").innerHTML = vidhtml;
v=document.getElementById("v");
if(n.getUserMedia)
n.getUserMedia({video: true, audio: false}, success, error);
else
if(n.webkitGetUserMedia)
{
webkit=true;
n.webkitGetUserMedia({video:true, audio: false}, success, error);
}
else
if(n.mediaDevices.getUserMedia)
{
moz=true;
n.mozGetUserMedia({video: true, audio: false}, success, error);
}
else
if(n.mozGetUserMedia)
{
moz=true;
n.mozGetUserMedia({video: true, audio: false}, success, error);
}
stype=1;
setTimeout(captureToCanvas, 500);
}
</script>
{!! HTML::script('assets/javascript/backend.js') !!}
</body>
</html>

View File

@ -1,5 +1,5 @@
<div role="dialog" id="{{ $modal_id }}" class="modal fade" style="display: none;">
<div role="dialog" class="modal fade" style="display: none;">
{!! Form::open(['url' => route('postCreateEventQuestion', ['event_id'=>$event->id]), 'id' => 'edit-question-form', 'class' => 'ajax']) !!}
<script id="question-option-template" type="text/template">
<tr>

View File

@ -1,4 +1,4 @@
<div role="dialog" id="{{ $modal_id }}" class="modal fade" style="display: none;">
<div role="dialog" class="modal fade" style="display: none;">
{!! Form::model($question, ['url' => route('postEditEventQuestion', ['event_id' => $event->id, 'question_id' => $question->id]), 'id' => 'edit-question-form', 'class' => 'ajax']) !!}
<script id="question-option-template" type="text/template">
<tr>

View File

@ -4,13 +4,12 @@
<div class="modal-header text-center">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h3 class="modal-title">
Q: {{ $question->title }}
</h3>
</div>
@if(count($answers))
<div class="table-responsive">
<table class="table">
<thead>
<tr>
@ -30,8 +29,12 @@
@foreach($answers as $answer)
<tr>
<td>
{{ $answer->attendee->full_name }}<br>
<a href="javascript:void(0);">{{ $answer->attendee->email }}</a><br>
{{ $answer->attendee->full_name }}
@if($answer->attendee->is_cancelled)
(<span title="This attendee has been cancelled" class="text-danger">Cancelled</span>)
@endif<br>
<a title="Go to attendee: {{ $answer->attendee->full_name }}" href="{{route('showEventAttendees', ['event_id' => $answer->attendee->event_id, 'q' => $answer->attendee->reference])}}">{{ $answer->attendee->email }}</a><br>
</td>
<td>
@ -46,6 +49,14 @@
</table>
</div>
@else
<div class="modal-body">
<div class="alert alert-info">
Sorry, there's no answers to this question yet.
</div>
</div>
@endif
<div class="modal-footer">
{!! Form::button('Close', ['class'=>"btn modal-close btn-danger",'data-dismiss'=>'modal']) !!}

View File

@ -5,10 +5,8 @@
Attendize QRCode Check In: {{ $event->title }}
</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
<link href='https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,700' rel='stylesheet' type='text/css'>
{!! HTML::style('assets/stylesheet/qrcode-check-in.css') !!}
{!! HTML::style('assets/stylesheet/application.css') !!}
{!! HTML::style('assets/stylesheet/qrcode-check-in.css') !!}
{!! HTML::script('vendor/jquery/jquery.js') !!}
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0">
@ -86,7 +84,7 @@
<footer id="footer">
<br>
<br>
<h5 align="center" style="color: #6D717A;">&copy; <a href="https://www.attendize.com/">Attendize</a> {{ date('Y') }} &middot; All Rights Reserved.</h5>
<h5 align="center" style="color: #6D717A;">Powered By <a href="https://www.attendize.com/">Attendize</a> </h5>
</footer>
</div>

View File

@ -80,6 +80,9 @@ Event Surveys
<th>
Applies to tickets
</th>
<th>
# Replies
</th>
<th>
</th>
@ -99,6 +102,13 @@ Event Surveys
<td>
{{implode(', ', array_column($question->tickets->toArray(), 'title'))}}
</td>
<td>
<a class="loadModal" data-modal-id="showEventQuestionAnswers" href="javascript:void(0);"
data-href="{{route('showEventQuestionAnswers', ['event_id' => $event->id, 'question_id' => $question->id])}}">
{{ $question->answers->count() }}
</a>
</td>
<td class="text-center">
<div class="btn-group">
<button type="button" class="btn btn-xs btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Action <span class="caret"></span></button>

View File

@ -142,5 +142,6 @@
@yield('foot')
@include('Shared.Partials.GlobalFooterJS')
</body>
</html>