Added ability to order tickets (closes #214)

This commit is contained in:
Dave Earley 2016-10-23 17:51:46 +01:00
parent 16a125ff66
commit cc0c22a743
7 changed files with 135 additions and 106 deletions

View File

@ -253,4 +253,28 @@ class EventTicketsController extends MyBaseController
]),
]);
}
/**
* Updates the sort order of tickets
*
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function postUpdateTicketsOrder(Request $request)
{
$ticket_ids = $request->get('ticket_ids');
$sort = 1;
foreach ($ticket_ids as $ticket_id) {
$ticket = Ticket::scope()->find($ticket_id);
$ticket->sort_order = $sort;
$ticket->save();
$sort++;
}
return response()->json([
'status' => 'success',
'message' => 'Ticket Order Successfully Updated',
]);
}
}

View File

@ -33,7 +33,7 @@ class EventViewController extends Controller
$data = [
'event' => $event,
'tickets' => $event->tickets()->where('is_hidden', 0)->orderBy('created_at', 'desc')->get(),
'tickets' => $event->tickets()->where('is_hidden', 0)->orderBy('sort_order', 'asc')->get(),
'is_embedded' => 0,
];
/*

View File

@ -19,7 +19,7 @@ class EventViewEmbeddedController extends Controller
$data = [
'event' => $event,
'tickets' => $event->tickets()->where('is_hidden', 0)->orderBy('created_at', 'desc')->get(),
'tickets' => $event->tickets()->where('is_hidden', 0)->orderBy('sort_order', 'asc')->get(),
'is_embedded' => '1',
];

View File

@ -364,6 +364,10 @@ Route::group(['middleware' => ['auth', 'first.run']], function () {
'as' => 'postPauseTicket',
'uses' => 'EventTicketsController@postPauseTicket',
]);
Route::post('{event_id}/tickets/order', [
'as' => 'postUpdateTicketsOrder',
'uses' => 'EventTicketsController@postUpdateTicketsOrder',
]);
/*
* Ticket questions

View File

@ -475,4 +475,4 @@ body {
.minicolors-theme-semanticui input {
text-indent: 30px;
}
.page-title .title .organiser_logo{position:absolute;height:45px;right:20px;top:5px;bottom:5px}.page-title .title .organiser_logo img{max-height:45px}#calendar{border:1px solid #ddd;background:#fff}#calendar .fc-button{background:transparent;border:none;color:inherit;box-shadow:none}#calendar .fc-event{border-color:#fff;-webkit-border-radius:0;border-radius:0;padding:2px;transition:none}#calendar .fc-toolbar{text-align:center;margin-bottom:0em;padding:7px}#calendar h2{font-size:15px;text-transform:uppercase;margin-top:6px}#calendar .fc-view{margin:-1px}.nav li.nav-button a span{padding:10px}.event.panel{margin-top:10px}.event .event-date{border:1px solid #fff;padding-bottom:9px;padding-top:7px;text-align:center;text-shadow:0 1px 1px rgba(0,0,0,0.1);width:46px;position:absolute;background-color:#ffffff;top:-13px;border-color:#404675;color:#666}.event .event-date .day{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:22px;font-weight:500;margin:-2px auto -6px auto}.event .event-date .month{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:10px;font-weight:500;margin:-2px auto 0 auto}.event .event-meta{margin:0;padding:0;margin-left:60px;height:55px;margin-top:10px;color:#ffffff}.event .event-meta li{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;list-style:none;font-size:12px}.event .event-meta li a{color:#ffffff}.event .event-meta li.event-title a{font-size:16px}.event .event-meta li.event-organiser a{font-weight:bold}.event .panel-title{height:60px;padding:10px}.event .panel-title a{margin:0;height:40px;display:table-cell;vertical-align:middle;text-indent:50px}.stat-box{padding:20px;background-color:#fff;color:#2e3254;text-align:center;margin-bottom:10px;border:1px solid #e0e0e0}.stat-box h3{margin-bottom:5px;margin-top:0;font-weight:200}.stat-box span{text-transform:uppercase;font-weight:lighter;color:#aeb2d3}.top_of_page_alert{border:none;margin:0;text-align:center;border-bottom:5px solid}.v-align-text{text-align:center;position:relative;top:50%;-ms-transform:translateY(-50%);-wekbit-transform:translateY(-50%);transform:translateY(-50%)}@media (max-width:992px){.page-header>[class*=" col-"],.page-header>[class^="col-"]{margin-bottom:10px}}@media (max-width:480px){.btn-group-responsive{margin-bottom:-10px;float:none !important;display:block !important}.btn-group-responsive .btn{width:100%;padding-left:0;padding-right:0;margin-bottom:10px}.btn-group-responsive .pull-left,.btn-group-responsive .pull-right{float:none !important}}label.required::after{content:'*';color:red;padding-left:3px;font-size:9px}.hasDatepicker[disabled],.hasDatepicker[readonly],fieldset[disabled] .hasDatepicker{cursor:pointer !important;background-color:#fff !important;opacity:1}.more-options{display:none}.col-sort{color:#fff}.col-sort :hover{color:#fff}.pac-container{z-index:9999}.dtpicker-overlay{z-index:9999}.dtpicker-close{display:none}.dtpicker-header .dtpicker-title{color:#AFAFAF;text-align:center;font-size:18px;font-weight:normal}.dtpicker-header .dtpicker-value{padding:.8em .2em .2em .2em;color:#404675;text-align:center;font-size:1.4em}.dtpicker-buttonCont .dtpicker-button{background:#404675;border-radius:0}.dtpicker-content{border-radius:0}.sidebar-open-ltr body{overflow-x:hidden}.order_options .event_count{font-weight:bold;color:#777}.well{background-color:#f9f9f9;box-shadow:none}.input-group-btn select{width:115px !important;border-left:0;font-size:12px}.btn-file{position:relative;overflow:hidden}.btn-file input[type=file]{position:absolute;top:0;right:0;min-width:100%;min-height:100%;font-size:100px;text-align:right;filter:alpha(opacity=0);opacity:0;background:red;cursor:inherit;display:block}input[readonly]{background-color:white !important;cursor:text !important}html.working{cursor:progress}.order_options{padding:10px 0}.minicolors-theme-default.minicolors{width:auto;display:block}.minicolors-theme-default .minicolors-input{padding-left:35px;height:auto;width:100%;display:block}.minicolors-theme-default .minicolors-swatch{top:8px;left:6px;width:18px;height:18px}.pagination>.active>span,.pagination>.active:focus>span,.pagination>.active:hover>span,.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default,.pagination>li>a:hover,.pager>li>a:hover,.pagination>li>span:hover,.pager>li>span:hover,.pagination>li>a:focus,.pager>li>a:focus,.pagination>li>span:focus,.pager>li>span:focus{color:#ffffff !important}.btn-default .caret{border-top-color:#fff}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-right:none}.modal-backdrop{background:url(../images/background.png) repeat;background-color:#2e3254}
.page-title .title .organiser_logo{position:absolute;height:45px;right:20px;top:5px;bottom:5px}.page-title .title .organiser_logo img{max-height:45px}#calendar{border:1px solid #ddd;background:#fff}#calendar .fc-button{background:transparent;border:none;color:inherit;box-shadow:none}#calendar .fc-event{border-color:#fff;-webkit-border-radius:0;border-radius:0;padding:2px;transition:none}#calendar .fc-toolbar{text-align:center;margin-bottom:0em;padding:7px}#calendar h2{font-size:15px;text-transform:uppercase;margin-top:6px}#calendar .fc-view{margin:-1px}.nav li.nav-button a span{padding:10px}.event.panel{margin-top:10px}.event .event-date{border:1px solid #fff;padding-bottom:9px;padding-top:7px;text-align:center;text-shadow:0 1px 1px rgba(0,0,0,0.1);width:46px;position:absolute;background-color:#ffffff;top:-13px;border-color:#404675;color:#666}.event .event-date .day{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:22px;font-weight:500;margin:-2px auto -6px auto}.event .event-date .month{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:10px;font-weight:500;margin:-2px auto 0 auto}.event .event-meta{margin:0;padding:0;margin-left:60px;height:55px;margin-top:10px;color:#ffffff}.event .event-meta li{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;list-style:none;font-size:12px}.event .event-meta li a{color:#ffffff}.event .event-meta li.event-title a{font-size:16px}.event .event-meta li.event-organiser a{font-weight:bold}.event .panel-title{height:60px;padding:10px}.event .panel-title a{margin:0;height:40px;display:table-cell;vertical-align:middle;text-indent:50px}.stat-box{padding:20px;background-color:#fff;color:#2e3254;text-align:center;margin-bottom:10px;border:1px solid #e0e0e0}.stat-box h3{margin-bottom:5px;margin-top:0;font-weight:200}.stat-box span{text-transform:uppercase;font-weight:lighter;color:#aeb2d3}.top_of_page_alert{border:none;margin:0;text-align:center;border-bottom:5px solid}.v-align-text{text-align:center;position:relative;top:50%;-ms-transform:translateY(-50%);-wekbit-transform:translateY(-50%);transform:translateY(-50%)}@media (max-width:992px){.page-header>[class*=" col-"],.page-header>[class^="col-"]{margin-bottom:10px}}@media (max-width:480px){.btn-group-responsive{margin-bottom:-10px;float:none !important;display:block !important}.btn-group-responsive .btn{width:100%;padding-left:0;padding-right:0;margin-bottom:10px}.btn-group-responsive .pull-left,.btn-group-responsive .pull-right{float:none !important}}label.required::after{content:'*';color:red;padding-left:3px;font-size:9px}.hasDatepicker[disabled],.hasDatepicker[readonly],fieldset[disabled] .hasDatepicker{cursor:pointer !important;background-color:#fff !important;opacity:1}.more-options{display:none}.col-sort{color:#fff}.col-sort :hover{color:#fff}.pac-container{z-index:9999}.dtpicker-overlay{z-index:9999}.dtpicker-close{display:none}.dtpicker-header .dtpicker-title{color:#AFAFAF;text-align:center;font-size:18px;font-weight:normal}.dtpicker-header .dtpicker-value{padding:.8em .2em .2em .2em;color:#404675;text-align:center;font-size:1.4em}.dtpicker-buttonCont .dtpicker-button{background:#404675;border-radius:0}.dtpicker-content{border-radius:0}.sidebar-open-ltr body{overflow-x:hidden}.order_options .event_count{font-weight:bold;color:#777}.well{background-color:#f9f9f9;box-shadow:none}.input-group-btn select{width:115px !important;border-left:0;font-size:12px}.btn-file{position:relative;overflow:hidden}.btn-file input[type=file]{position:absolute;top:0;right:0;min-width:100%;min-height:100%;font-size:100px;text-align:right;filter:alpha(opacity=0);opacity:0;background:red;cursor:inherit;display:block}input[readonly]{background-color:white !important;cursor:text !important}html.working{cursor:progress}.order_options{padding:10px 0}.minicolors-theme-default.minicolors{width:auto;display:block}.minicolors-theme-default .minicolors-input{padding-left:35px;height:auto;width:100%;display:block}.minicolors-theme-default .minicolors-swatch{top:8px;left:6px;width:18px;height:18px}.pagination>.active>span,.pagination>.active:focus>span,.pagination>.active:hover>span,.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default,.pagination>li>a:hover,.pager>li>a:hover,.pagination>li>span:hover,.pager>li>span:hover,.pagination>li>a:focus,.pager>li>a:focus,.pagination>li>span:focus,.pager>li>span:focus{color:#ffffff !important}.btn-default .caret{border-top-color:#fff}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-right:none}.modal-backdrop{background:url(../images/background.png) repeat;background-color:#2e3254}.ticket .sortHandle{width:20px;height:20px;color:#dfdfdf;font-size:20px;position:absolute;bottom:20px;left:15px;cursor:move;z-index:10}

View File

@ -426,4 +426,14 @@ html.working {
background-color: @attendize-base-color;
}
.ticket .sortHandle {
width: 20px;
height: 20px;
color: #dfdfdf;
font-size: 20px;
position: absolute;
bottom: 20px;
left: 15px;
cursor: move;
z-index: 10;
}

View File

@ -14,38 +14,35 @@
Event Tickets
@stop
@section('head')
<script>
$(function () {
$('.sortable').sortable({
handle: '.sortHanlde',
forcePlaceholderSize: true,
placeholderClass: 'col-md-4 col-sm-6 col-xs-12',
}).bind('sortupdate', function (e, ui) {
var data = $('.sortable tr').map(function () {
return $(this).data('question-id');
var data = $('.sortable .ticket').map(function () {
return $(this).data('ticket-id');
}).get();
$.ajax({
type: 'POST',
url: '',//Attendize.postUpdateTicketsOrderRoute,
url: '{{ route('postUpdateTicketsOrder' ,['event_id' => $event->id]) }}',
dataType: 'json',
data: {question_ids: data},
data: {ticket_ids: data},
success: function (data) {
showMessage(data.message)
showMessage(data.message);
},
error: function (data) {
console.log(data);
showMessage('Something went wrong. Please try again.');
}
});
});
});
</script>
@stop
@stop
@section('menu')
@include('ManageEvent.Partials.Sidebar')
@ -93,7 +90,6 @@
@section('content')
@if($tickets->count())
<div class="row">
<div class="col-md-3 col-xs-6">
<div class='order_options'>
@ -106,109 +102,104 @@
</div>
</div>
</div>
@endif
<!--Start ticket table-->
<div class="row sortable">
@if($tickets->count())
@endif
<!--Start ticket table-->
<div class="row sortable">
@if($tickets->count())
@foreach($tickets as $ticket)
<div id="ticket_{{$ticket->id}}" class="col-md-4 col-sm-6 col-xs-12 ">
<div class="panel panel-success ticket">
<div style="cursor: pointer;" data-modal-id='ticket-{{ $ticket->id }}'
data-href="{{ route('showEditTicket', ['event_id' => $event->id, 'ticket_id' => $ticket->id]) }}"
class="panel-heading loadModal">
<h3 class="panel-title">
@if($ticket->is_hidden)
<i title="This ticket is hidden" class="ico-eye-blocked ticket_icon mr5 ellipsis"></i>
@else
<i class="ico-ticket ticket_icon mr5 ellipsis"></i>
@endif
{{$ticket->title}}
<span class="pull-right">
@foreach($tickets as $ticket)
<div id="ticket_{{$ticket->id}}" class="col-md-4 col-sm-6 col-xs-12">
<div class="panel panel-success ticket" data-ticket-id="{{$ticket->id}}">
<div style="cursor: pointer;" data-modal-id='ticket-{{ $ticket->id }}'
data-href="{{ route('showEditTicket', ['event_id' => $event->id, 'ticket_id' => $ticket->id]) }}"
class="panel-heading loadModal">
<h3 class="panel-title">
@if($ticket->is_hidden)
<i title="This ticket is hidden"
class="ico-eye-blocked ticket_icon mr5 ellipsis"></i>
@else
<i class="ico-ticket ticket_icon mr5 ellipsis"></i>
@endif
{{$ticket->title}}
<span class="pull-right">
{{ ($ticket->is_free) ? "FREE" : money($ticket->price, $event->currency) }}
</span>
</h3>
</h3>
</div>
<div class='panel-body'>
<ul class="nav nav-section nav-justified mt5 mb5">
<li>
<div class="section">
<h4 class="nm">{{ $ticket->quantity_sold }}</h4>
<p class="nm text-muted">Sold</p>
</div>
</li>
<li>
<div class="section">
<h4 class="nm">
{{ ($ticket->quantity_available === null) ? '&infin;' : $ticket->quantity_remaining }}
</h4>
<p class="nm text-muted">Remaining</p>
</div>
</li>
<li>
<div class="section">
<h4 class="nm hint--top"
title="{{money($ticket->sales_volume, $event->currency)}} + {{money($ticket->organiser_fees_volume, $event->currency)}} Organiser Booking Fees">
{{money($ticket->sales_volume + $ticket->organiser_fees_volume, $event->currency)}}
<sub title="Doesn't account for refunds.">*</sub>
</h4>
<p class="nm text-muted">Revenue</p>
</div>
</li>
</ul>
</div>
<div class="panel-footer" style="height: 56px;">
<div class="sortHandle" title="Drag to re-order">
<i class="ico-paragraph-justify"></i>
</div>
<div class='panel-body'>
<ul class="nav nav-section nav-justified mt5 mb5">
<li>
<div class="section">
<h4 class="nm">{{ $ticket->quantity_sold }}</h4>
<p class="nm text-muted">Sold</p>
</div>
</li>
<li>
<div class="section">
<h4 class="nm">
{{ ($ticket->quantity_available === null) ? '&infin;' : $ticket->quantity_remaining }}
</h4>
<p class="nm text-muted">Remaining</p>
</div>
</li>
<li>
<div class="section">
<h4 class="nm hint--top"
title="{{money($ticket->sales_volume, $event->currency)}} + {{money($ticket->organiser_fees_volume, $event->currency)}} Organiser Booking Fees">
{{money($ticket->sales_volume + $ticket->organiser_fees_volume, $event->currency)}}
<sub title="Doesn't account for refunds.">*</sub>
</h4>
<p class="nm text-muted">Revenue</p>
</div>
</li>
</ul>
</div>
<div class="panel-footer sortHandle" style="height: 56px;">
<ul class="nav nav-section nav-justified">
<li>
<a href="javascript:void(0);">
@if($ticket->sale_status === config('attendize.ticket_status_on_sale'))
@if($ticket->is_paused)
Ticket Sales Paused &nbsp;
<span class="pauseTicketSales label label-info"
data-id="{{$ticket->id}}"
data-route="{{route('postPauseTicket', ['event_id'=>$event->id])}}">
<ul class="nav nav-section nav-justified">
<li>
<a href="javascript:void(0);">
@if($ticket->sale_status === config('attendize.ticket_status_on_sale'))
@if($ticket->is_paused)
Ticket Sales Paused &nbsp;
<span class="pauseTicketSales label label-info"
data-id="{{$ticket->id}}"
data-route="{{route('postPauseTicket', ['event_id'=>$event->id])}}">
<i class="ico-play4"></i> Resume
</span>
@else
On Sale &nbsp;
<span class="pauseTicketSales label label-info"
data-id="{{$ticket->id}}"
data-route="{{route('postPauseTicket', ['event_id'=>$event->id])}}">
@else
On Sale &nbsp;
<span class="pauseTicketSales label label-info"
data-id="{{$ticket->id}}"
data-route="{{route('postPauseTicket', ['event_id'=>$event->id])}}">
<i class="ico-pause"></i> Pause
</span>
@endif
@else
{{\App\Models\TicketStatus::find($ticket->sale_status)->name}}
@endif
</a>
</li>
</ul>
</div>
@else
{{\App\Models\TicketStatus::find($ticket->sale_status)->name}}
@endif
</a>
</li>
</ul>
</div>
</div>
@endforeach
</div>
@endforeach
@else
@if($q)
@include('Shared.Partials.NoSearchResults')
@else
@if($q)
@include('Shared.Partials.NoSearchResults')
@else
@include('ManageEvent.Partials.TicketsBlankSlate')
@endif
@include('ManageEvent.Partials.TicketsBlankSlate')
@endif
</div><!--/ end ticket table-->
<div class="row">
<div class="col-md-12">
{!! $tickets->appends(['q' => $q, 'sort_by' => $sort_by])->render() !!}
</div>
@endif
</div><!--/ end ticket table-->
<div class="row">
<div class="col-md-12">
{!! $tickets->appends(['q' => $q, 'sort_by' => $sort_by])->render() !!}
</div>
</div>
@stop