more consistent GUI

This commit is contained in:
Davide Alberani 2016-07-10 09:35:55 +02:00
parent ed553faac2
commit 24d6689abe
8 changed files with 48 additions and 50 deletions

View file

@ -3,43 +3,32 @@
<div eventman-message="eventman-message" control="message"></div> <div eventman-message="eventman-message" control="message"></div>
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-md-7 col-xs-7 vcenter"> <div class="col-md-8">
<h1>{{event.title}} <div class="panel panel-primary table-striped top5">
<div class="panel-heading">
<h1>{{event.title}} - {{'tickets' | translate}}
<button ng-if="event._id" ng-click="$state.go('event.edit', {id: event._id})" class="btn btn-success"> <button ng-if="event._id" ng-click="$state.go('event.edit', {id: event._id})" class="btn btn-success">
<span class="fa fa-pencil-square-o vcenter"></span> <span class="fa fa-gear vcenter"></span>
{{'Edit' | translate}} {{'Edit event' | translate}}
</button> </button>
&nbsp; &nbsp;
<button ng-if="event._id" ng-click="openQuickAddTicket()" class="btn btn-success"> <button ng-if="event._id" ng-click="openQuickAddTicket()" class="btn btn-success">
<span class="fa fa-user-plus vcenter"></span> <span class="fa fa-user-plus vcenter"></span>
{{'Quick add ticket' | translate}} {{'Quick add ticket' | translate}}
</button> </button>
<span>
<span class="label label-info vcenter pull-right">{{'Attendees:' | translate}} {{countAttendees}}</span>
&nbsp;
<span class="label label-warning vcenter pull-right">{{'Registered:' | translate}} {{((event.tickets || []) | registeredFilter).length}}</span>
</span>
</h1> </h1>
</div><!--
--><div class="col-md-5 col-xs-5 vcenter">
<div class="row">
<div class="col-md-6">
<h2><div class="label label-warning vcenter">{{'Registered:' | translate}} {{((event.tickets || []) | registeredFilter).length}}</div></h2>
</div> </div>
<div class="col-md-6">
<h2><div class="label label-info vcenter">{{'Attendees:' | translate}} {{countAttendees}}</div></h2>
</div>
</div>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-md-8">
<div class="panel panel-primary table-striped top5">
<div class="panel-heading">{{'tickets' | translate}}</div>
<div class="panel-body"> <div class="panel-body">
<form class="form-inline"> <form class="form-inline">
<div class="form-group"> <div class="form-group">
<label for="query-tickets">{{'Search:' | translate}}</label> <label for="query-tickets">{{'Search:' | translate}}</label>
<input eventman-focus type="text" id="query-tickets" class="form-control" placeholder="{{'Name or email' | translate}}" ng-model="query" ng-model-options="{debounce: 600}"> <input eventman-focus type="text" id="query-tickets" class="form-control" placeholder="{{'Name or email' | translate}}" ng-model="query" ng-model-options="{debounce: 600}">
</div> </div>&nbsp;<label>&nbsp;<input type="checkbox" ng-model="registeredFilterOptions.all" /> {{'Show cancelled tickets' | translate}}</label>
</form> </form>
<table class="table table-striped"> <table class="table table-striped">
<thead> <thead>
@ -54,7 +43,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr ng-repeat="ticket in (event.tickets || []) | splittedFilter:query | registeredFilter | orderBy:ticketsOrder"> <tr ng-repeat="ticket in (event.tickets || []) | splittedFilter:query | registeredFilter:registeredFilterOptions | orderBy:ticketsOrder">
<td class="text-right">{{$index+1}}</td> <td class="text-right">{{$index+1}}</td>
<td> <td>
<span> <span>
@ -88,7 +77,7 @@
<div class="col-md-4"> <div class="col-md-4">
<div class="panel panel-info top5"> <div class="panel panel-info top5">
<div class="panel-heading">{{'Unregistered persons' | translate}}</div> <div class="panel-heading"><h1>{{'Unregistered persons' | translate}}</h1></div>
<div class="panel-body small-table"> <div class="panel-body small-table">
<table class="table table-striped table-condensed"> <table class="table table-striped table-condensed">
<thead> <thead>

View file

@ -4,7 +4,7 @@
<div class="panel-heading"> <div class="panel-heading">
<h1>{{'Events' | translate}} <h1>{{'Events' | translate}}
<button ng-click="$state.go('event.new')" class="btn btn-success" ng-if="hasPermission('event|create')"> <button ng-click="$state.go('event.new')" class="btn btn-success" ng-if="hasPermission('event|create')">
<span class="fa fa-plus-circle vcenter"></span> <span class="fa fa-calendar vcenter"></span>
{{'Add event' | translate}} {{'Add event' | translate}}
</button> </button>
</h1> </h1>
@ -52,7 +52,7 @@
</td> </td>
<td> <td>
<button ng-if="hasPermission('event:tickets-all|create')" ng-click="$state.go('event.ticket.new', {id: event._id})" class="btn btn-link fa fa-user-plus" type="button" title="{{'Join this event' | translate}}"></button> <button ng-if="hasPermission('event:tickets-all|create')" ng-click="$state.go('event.ticket.new', {id: event._id})" class="btn btn-link fa fa-user-plus" type="button" title="{{'Join this event' | translate}}"></button>
<button ng-if="hasPermission('tickets|update')" ng-click="$state.go('event.tickets', {id: event._id})" class="btn btn-link fa fa-list" type="button" title="{{'Manage attendees' | translate}}"></button> <button ng-if="hasPermission('ticket|update')" ng-click="$state.go('event.tickets', {id: event._id})" class="btn btn-link fa fa-ticket" type="button" title="{{'Manage tickets' | translate}}"></button>
<button ng-if="hasPermission('event|update')" ng-click="$state.go('event.edit', {id: event._id})" type="button" class="btn btn-link fa fa-cog fa-lg" title="{{'Edit' | translate}}"></button> <button ng-if="hasPermission('event|update')" ng-click="$state.go('event.edit', {id: event._id})" type="button" class="btn btn-link fa fa-cog fa-lg" title="{{'Edit' | translate}}"></button>
<button ng-if="hasPermission('event|delete')" ng-click="deleteEvent(event._id)" type="button" class="btn btn-link fa fa-trash fa-lg" title="{{'Delete' | translate}}"></button> <button ng-if="hasPermission('event|delete')" ng-click="deleteEvent(event._id)" type="button" class="btn btn-link fa fa-trash fa-lg" title="{{'Delete' | translate}}"></button>
</td> </td>

View file

@ -1,20 +1,19 @@
<!-- import persons --> <!-- import tickets -->
<div class="container"> <div class="container">
<h1>{{'Import persons' | translate}}</h1>
<div class="panel panel-primary"> <div class="panel panel-primary">
<div class="panel-heading"> <div class="panel-heading">
<div class="panel-title">{{'Import persons from eventbrite CSV' | translate}}</div> <div class="panel-title"><h1>{{'Import tickets from Eventbrite CSV' | translate}}</h1></div>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<form name="ebCSVForm" class="well"> <form name="ebCSVForm" class="well">
<div class="form-group"> <div class="form-group">
<label for="eb-csv-import">{{'CSV file' | translate}}</label> <label for="eb-csv-import">{{'CSV file' | translate}}</label>
<input name="file" ng-file-select ng-model="file" type="file" id="eb-csv-import" ng-required="true"> <input name="file" ng-file-select ng-model="file" type="file" id="eb-csv-import" ng-required="true">
<p class="help-block">{{'CSV exported from eventbrite' | translate}}</p> <p class="help-block">{{'CSV exported from Eventbrite' | translate}}</p>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="forEvent">{{'Associate users to this event' | translate}}</label> <label for="forEvent">{{'Associate tickets to this event' | translate}}</label>
<select class="form-control" id="forEvent" ng-model="targetEvent" ng-required="true"> <select class="form-control" id="forEvent" ng-model="targetEvent" ng-required="true">
<option ng-repeat="event in events" value="{{event._id}}">{{event.title}}</option> <option ng-repeat="event in events" value="{{event._id}}">{{event.title}}</option>
</select> </select>

View file

@ -73,8 +73,8 @@
<div ng-if="logo.imgURL" class="navbar-brand"><a ng-if="logo.link" href="{{logo.link}}" target="_blank"><img src="{{logo.imgURL}}" /></a></div> <div ng-if="logo.imgURL" class="navbar-brand"><a ng-if="logo.link" href="{{logo.link}}" target="_blank"><img src="{{logo.imgURL}}" /></a></div>
<ul class="nav navbar-nav"> <ul class="nav navbar-nav">
<li ng-class="{active: isActive('/events') || isActive('/event')}"><a ui-sref="events">{{'Events' | translate}}</a></li> <li ng-class="{active: isActive('/events') || isActive('/event')}"><a ui-sref="events">{{'Events' | translate}}</a></li>
<li ng-if="hasPermission('admin|all')" ng-class="{active: isActive('/users') || isActive('/user')}"><a ui-sref="users">{{'Users' | translate}}</a></li>
<li ng-if="hasPermission('admin|all')" ng-class="{active: isActive('/tickets')}"><a ui-sref="tickets">{{'All tickets' | translate}}</a></li> <li ng-if="hasPermission('admin|all')" ng-class="{active: isActive('/tickets')}"><a ui-sref="tickets">{{'All tickets' | translate}}</a></li>
<li ng-if="hasPermission('admin|all')" ng-class="{active: isActive('/users')}"><a ui-sref="users">{{'Users' | translate}}</a></li>
<li ng-if="hasPermission('admin|all')" ng-class="{active: isActive('/import/persons')}"><a ui-sref="import.persons">{{'Import tickets' | translate}}</a></li> <li ng-if="hasPermission('admin|all')" ng-class="{active: isActive('/import/persons')}"><a ui-sref="import.persons">{{'Import tickets' | translate}}</a></li>
</ul> </ul>
</div> </div>

View file

@ -172,12 +172,14 @@ eventManControllers.controller('EventTicketsCtrl', ['$scope', '$state', 'Event',
$scope.countAttendees = 0; $scope.countAttendees = 0;
$scope.message = {}; $scope.message = {};
$scope.event = {}; $scope.event = {};
$scope.event.tickets = [];
$scope.ticket = {}; // current ticket, for the event.ticket.* states $scope.ticket = {}; // current ticket, for the event.ticket.* states
$scope.tickets = []; // list of all tickets, for the 'tickets' state $scope.tickets = []; // list of all tickets, for the 'tickets' state
$scope.formSchema = {}; $scope.formSchema = {};
$scope.formData = {}; $scope.formData = {};
$scope.guiOptions = {dangerousActionsEnabled: false}; $scope.guiOptions = {dangerousActionsEnabled: false};
$scope.customFields = Setting.query({setting: 'ticket_custom_field', in_event_details: true}); $scope.customFields = Setting.query({setting: 'ticket_custom_field', in_event_details: true});
$scope.registeredFilterOptions = {all: true};
$scope.formFieldsMap = {}; $scope.formFieldsMap = {};
$scope.formFieldsMapRev = {}; $scope.formFieldsMapRev = {};
@ -186,10 +188,11 @@ eventManControllers.controller('EventTicketsCtrl', ['$scope', '$state', 'Event',
$scope.event = Event.get({id: $state.params.id}, function(data) { $scope.event = Event.get({id: $state.params.id}, function(data) {
$scope.$watchCollection(function() { $scope.$watchCollection(function() {
return $scope.event.tickets; return $scope.event.tickets;
}, function(prev, old) { }, function(new_collection, old_collection) {
$scope.calcAttendees(); $scope.calcAttendees();
} }
); );
if (!(data && data.formSchema)) { if (!(data && data.formSchema)) {
return; return;
} }
@ -219,7 +222,7 @@ eventManControllers.controller('EventTicketsCtrl', ['$scope', '$state', 'Event',
$scope.EventUpdates.open(); $scope.EventUpdates.open();
$scope.$watchCollection(function() { $scope.$watchCollection(function() {
return $scope.EventUpdates.data; return $scope.EventUpdates.data;
}, function(prev, old) { }, function(new_collection, old_collection) {
if (!($scope.EventUpdates.data && $scope.EventUpdates.data.update)) { if (!($scope.EventUpdates.data && $scope.EventUpdates.data.update)) {
return; return;
} }
@ -280,7 +283,7 @@ eventManControllers.controller('EventTicketsCtrl', ['$scope', '$state', 'Event',
$scope.event.tickets = []; $scope.event.tickets = [];
} }
var ticket_idx = $scope.event.tickets.findIndex(function(el, idx, array) { var ticket_idx = $scope.event.tickets.findIndex(function(el, idx, array) {
return ticket._id == el._id; return ticket._id == el._id;
}); });
if (ticket_idx != -1) { if (ticket_idx != -1) {
$log.warn('ticket already present: not added'); $log.warn('ticket already present: not added');
@ -289,7 +292,7 @@ eventManControllers.controller('EventTicketsCtrl', ['$scope', '$state', 'Event',
$scope.event.tickets.push(ticket); $scope.event.tickets.push(ticket);
} }
// Try to remove this person from the allPersons list using ID or email. // Try to remove this person from the allPersons list using ID of the original entry or email.
var field = null; var field = null;
var field_value = null; var field_value = null;
if (original_ticket && original_ticket._id) { if (original_ticket && original_ticket._id) {
@ -340,6 +343,7 @@ eventManControllers.controller('EventTicketsCtrl', ['$scope', '$state', 'Event',
} }
var removed_person = $scope.event.tickets.splice(ticket_idx, 1); var removed_person = $scope.event.tickets.splice(ticket_idx, 1);
// to be used to populate allPersons, if needed. // to be used to populate allPersons, if needed.
var person = null;
if (removed_person.length) { if (removed_person.length) {
person = removed_person[0]; person = removed_person[0];
} else { } else {
@ -413,16 +417,17 @@ eventManControllers.controller('EventTicketsCtrl', ['$scope', '$state', 'Event',
$scope.addTicket = function(ticket) { $scope.addTicket = function(ticket) {
ticket.event_id = $state.params.id; ticket.event_id = $state.params.id;
EventTicket.add(ticket, function(ticket) { EventTicket.add(ticket, function(ret_ticket) {
$log.debug('addTicket'); $log.debug('addTicket');
$log.debug(ticket); $log.debug(ret_ticket);
$scope._localAddTicket(ticket, ticket); $scope._localAddTicket(ret_ticket, ticket);
if (!$state.is('event.tickets')) { if (!$state.is('event.tickets')) {
$state.go('event.ticket.edit', {id: $scope.event._id, ticket_id: ticket._id}); $state.go('event.ticket.edit', {id: $scope.event._id, ticket_id: ret_ticket._id});
} else { } else {
$scope.query = ''; $scope.query = '';
$scope._setAttended(ticket); $scope._setAttended(ret_ticket);
if ($scope.$close) { if ($scope.$close) {
// Close the Quick ticket modal.
$scope.$close(); $scope.$close();
} }
} }

View file

@ -84,9 +84,6 @@ eventManServices.factory('EventTicket', ['$resource', '$rootScope',
isArray: true, isArray: true,
transformResponse: function(data, headers) { transformResponse: function(data, headers) {
data = angular.fromJson(data); data = angular.fromJson(data);
if (data.error) {
return data;
}
return data.tickets; return data.tickets;
} }
}, },
@ -97,6 +94,9 @@ eventManServices.factory('EventTicket', ['$resource', '$rootScope',
interceptor : {responseError: $rootScope.errorHandler}, interceptor : {responseError: $rootScope.errorHandler},
transformResponse: function(data, headers) { transformResponse: function(data, headers) {
data = angular.fromJson(data); data = angular.fromJson(data);
if (data.error) {
return data;
}
return data.ticket; return data.ticket;
} }
}, },
@ -109,6 +109,9 @@ eventManServices.factory('EventTicket', ['$resource', '$rootScope',
params: {uuid: $rootScope.app_uuid}, params: {uuid: $rootScope.app_uuid},
transformResponse: function(data, headers) { transformResponse: function(data, headers) {
data = angular.fromJson(data); data = angular.fromJson(data);
if (data.error) {
return data;
}
return data.ticket; return data.ticket;
} }
}, },
@ -120,6 +123,9 @@ eventManServices.factory('EventTicket', ['$resource', '$rootScope',
url: 'events/:event_id/tickets/:ticket_id', url: 'events/:event_id/tickets/:ticket_id',
params: {uuid: $rootScope.app_uuid}, params: {uuid: $rootScope.app_uuid},
transformResponse: function(data, headers) { transformResponse: function(data, headers) {
if (data.error) {
return data;
}
return angular.fromJson(data); return angular.fromJson(data);
} }
}, },

View file

@ -17,7 +17,7 @@
{{'Event details' | translate}} {{'Event details' | translate}}
</button> </button>
&nbsp;<button ng-click="$state.go('event.edit', {id: event._id})" class="btn btn-success" ng-if="event._id && hasPermission('event|update')"> &nbsp;<button ng-click="$state.go('event.edit', {id: event._id})" class="btn btn-success" ng-if="event._id && hasPermission('event|update')">
<span class="fa fa-calendar vcenter"></span> <span class="fa fa-gear vcenter"></span>
{{'Edit event' | translate}} {{'Edit event' | translate}}
</button> </button>
&nbsp;<button ng-click="$state.go('event.tickets', {id: event._id})" class="btn btn-success" ng-if="event._id && hasPermission('event:tickets-all|read')"> &nbsp;<button ng-click="$state.go('event.tickets', {id: event._id})" class="btn btn-success" ng-if="event._id && hasPermission('event:tickets-all|read')">

View file

@ -823,11 +823,8 @@ class EbCSVImportPersonsHandler(BaseHandler):
'Email': 'email', 'Email': 'email',
'Attendee #': 'attendee_nr', 'Attendee #': 'attendee_nr',
'Barcode #': 'ebqrcode', 'Barcode #': 'ebqrcode',
'Company': 'company', 'Company': 'company'
} }
# Only these information are stored in the person collection.
keepPersonData = ('name', 'surname', 'email', 'name_title', 'name_suffix',
'company', 'job_title')
@gen.coroutine @gen.coroutine
@authenticated @authenticated
@ -840,6 +837,8 @@ class EbCSVImportPersonsHandler(BaseHandler):
event_id = self.get_body_argument('targetEvent') event_id = self.get_body_argument('targetEvent')
except: except:
pass pass
if event_id is None:
return self.build_error('invalid event')
reply = dict(total=0, valid=0, merged=0, new_in_event=0) reply = dict(total=0, valid=0, merged=0, new_in_event=0)
for fieldname, contents in self.request.files.iteritems(): for fieldname, contents in self.request.files.iteritems():
for content in contents: for content in contents: