1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-01-17 06:52:27 +01:00

[feature] ability to filter events by category, theme and age

This commit is contained in:
Sylvain 2016-06-29 16:09:27 +02:00
parent 6e5fd86ad3
commit bdda4cd7b0
18 changed files with 153 additions and 71 deletions

View File

@ -1,13 +1,7 @@
'use strict'
Application.Controllers.controller "EventsController", ["$scope", "$state", 'Event', ($scope, $state, Event) ->
### PRIVATE STATIC CONSTANTS ###
# Number of events added to the page when the user clicks on 'load next events'
EVENTS_PER_PAGE = 12
Application.Controllers.controller "EventsController", ["$scope", "$state", 'Event', 'categoriesPromise', 'themesPromise', 'ageRangesPromise'
, ($scope, $state, Event, categoriesPromise, themesPromise, ageRangesPromise) ->
@ -16,33 +10,37 @@ Application.Controllers.controller "EventsController", ["$scope", "$state", 'Eve
## The events displayed on the page
$scope.events = []
## By default, the pagination mode is activated to limit the page size
$scope.paginateActive = true
## The currently displayed page number
$scope.page = 1
## List of categories for the events
$scope.categories = categoriesPromise
## List of events themes
$scope.themes = themesPromise
## List of age ranges
$scope.ageRanges = ageRangesPromise
## Active filters for the events list
$scope.filters =
category_id: null
theme_id: null
age_range_id: null
##
# Adds EVENTS_PER_PAGE events to the bottom of the page, grouped by month
# Adds a resultset of events to the bottom of the page, grouped by month
##
$scope.loadMoreEvents = ->
Event.query {page: $scope.page}, (data) ->
Event.query Object.assign({page: $scope.page}, $scope.filters), (data) ->
$scope.events = $scope.events.concat data
if data.length > 0
$scope.paginateActive = false if ($scope.page-2)*EVENTS_PER_PAGE+data.length >= data[0].nb_total_events
groupEvents(data)
$scope.page += 1
$scope.eventsGroupByMonth = _.groupBy($scope.events, (obj) ->
_.map ['month', 'year'], (key, value) -> obj[key]
)
$scope.monthOrder = _.sortBy _.keys($scope.eventsGroupByMonth), (k)->
monthYearArray = k.split(',')
date = new Date()
date.setMonth(monthYearArray[0])
date.setYear(monthYearArray[1])
return -date.getTime()
else
$scope.paginateActive = false
$scope.page += 1
if (!data[0] || data[0].nb_total_events <= $scope.events.length)
$scope.noMoreResults = true
@ -55,13 +53,58 @@ Application.Controllers.controller "EventsController", ["$scope", "$state", 'Eve
##
# Callback to refresh the events list according to the filters set
##
$scope.filterEvents = ->
# reinitialize results datasets
$scope.page = 1
$scope.eventsGroupByMonth = {}
$scope.events = []
$scope.monthOrder = []
# run a search query
Event.query Object.assign({page: $scope.page}, $scope.filters), (data) ->
$scope.events = data
groupEvents(data)
$scope.page += 1
if (!data[0] || data[0].nb_total_events <= $scope.events.length)
$scope.noMoreResults = true
### PRIVATE SCOPE ###
##
# Kind of constructor: these actions will be realized first when the controller is loaded
##
initialize = ->
$scope.loadMoreEvents()
$scope.filterEvents()
##
# Group the provided events by month/year and concat them with existing results
# Then compute the ordered list of months for the complete resultset.
# Affect the resulting events groups in $scope.eventsGroupByMonth and the ordered month keys in $scope.monthOrder.
# @param {Array} Events retrived from the API
##
groupEvents = (events) ->
if events.length > 0
eventsGroupedByMonth = _.groupBy(events, (obj) ->
_.map ['month', 'year'], (key, value) -> obj[key]
)
$scope.eventsGroupByMonth = Object.assign($scope.eventsGroupByMonth, eventsGroupedByMonth)
monthsOrder = _.sortBy _.keys($scope.eventsGroupByMonth), (k)->
monthYearArray = k.split(',')
date = new Date()
date.setMonth(monthYearArray[0])
date.setYear(monthYearArray[1])
return -date.getTime()
$scope.monthOrder = monthsOrder

View File

@ -439,6 +439,15 @@ angular.module('application.router', ['ui.router']).
templateUrl: '<%= asset_path "events/index.html" %>'
controller: 'EventsController'
resolve:
categoriesPromise: ['Category', (Category) ->
Category.query().$promise
]
themesPromise: ['EventTheme', (EventTheme) ->
EventTheme.query().$promise
]
ageRangesPromise: ['AgeRange', (AgeRange) ->
AgeRange.query().$promise
]
translations: [ 'Translations', (Translations) ->
Translations.query('app.public.events_list').$promise
]

View File

@ -20,38 +20,58 @@
<section class="m-lg">
<div ng-repeat="month in monthOrder">
<h1>{{month.split(',')[0]}}, {{month.split(',')[1]}}</h1>
<div class="row m-b-md">
<div class="col-md-3 m-b">
<select ng-model="filters.category_id" ng-change="filterEvents()" class="form-control" ng-options="c.id as c.name for c in categories">
<option value="" translate>{{ 'all_categories' }}</option>
</select>
</div>
<div class="row" ng-repeat="event in (eventsGroupByMonth[month].length/3 | array)">
<div class="col-xs-12 col-sm-6 col-md-4" ng-repeat="event in eventsGroupByMonth[month].slice(3*$index, 3*$index + 3)" ng-click="showEvent(event)">
<a class="block bg-white img-full p-sm p-l-m box-h-m event b b-light-dark m-t-sm" ui-sref="app.public.events_show({id: event.id})">
<div class="pull-left half-w m-t-n-sm">
<h5 class="text-xs">{{event.categories[0].name}}</h5>
<h4 class="m-n text-sm clear l-n">{{event.title}}</h4>
<h3 class="m-n">{{event.start_date | amDateFormat:'L'}} <span class="text-sm font-thin" translate> {{ 'to_date' }} </span> {{event.end_date | amDateFormat:'L'}}</h3>
<h6 class="m-n" ng-if="event.amount">{{ 'full_price_' | translate }} {{event.amount | currency}} <span ng-if="event.reduced_amount > 0">/ {{ 'reduced_rate_' | translate }} {{event.reduced_amount | currency}}</span></h6>
</div>
<!-- Event Image -->
<div class="pull-right crop-130">
<img class="pull-right" ng-src="{{event.event_image_small}}" title="{{event.title}}" ng-if="event.event_image">
<img class="pull-right img-responsive" src="data:image/png;base64," data-src="holder.js/100%x100%/text:&#xf03e;/font:FontAwesome/icon" bs-holder ng-if="!event.event_image">
</div>
</a>
<div class="col-md-3 m-b">
<select ng-model="filters.theme_id" ng-change="filterEvents()" class="form-control" ng-options="t.id as t.name for t in themes">
<option value="" translate>{{ 'all_themes' }}</option>
</select>
</div>
<div class="col-md-3 m-b">
<select ng-model="filters.age_range_id" ng-change="filterEvents()" class="form-control" ng-options="a.id as a.name for a in ageRanges">
<option value="" translate>{{ 'for_all' }}</option>
</select>
</div>
</div>
<div ng-repeat="month in monthOrder">
<h1>{{month.split(',')[0]}}, {{month.split(',')[1]}}</h1>
<div class="row" ng-repeat="event in (eventsGroupByMonth[month].length/3 | array)">
<div class="col-xs-12 col-sm-6 col-md-4" ng-repeat="event in eventsGroupByMonth[month].slice(3*$index, 3*$index + 3)" ng-click="showEvent(event)">
<a class="block bg-white img-full p-sm p-l-m box-h-m event b b-light-dark m-t-sm" ui-sref="app.public.events_show({id: event.id})">
<div class="pull-left half-w m-t-n-sm">
<h5 class="text-xs">{{event.categories[0].name}}</h5>
<h4 class="m-n text-sm clear l-n">{{event.title}}</h4>
<h3 class="m-n">{{event.start_date | amDateFormat:'L'}} <span class="text-sm font-thin" translate> {{ 'to_date' }} </span> {{event.end_date | amDateFormat:'L'}}</h3>
<h6 class="m-n" ng-if="event.amount">{{ 'full_price_' | translate }} {{event.amount | currency}} <span ng-if="event.reduced_amount > 0">/ {{ 'reduced_rate_' | translate }} {{event.reduced_amount | currency}}</span></h6>
</div>
<!-- Event Image -->
<div class="pull-right crop-130">
<img class="pull-right" ng-src="{{event.event_image_small}}" title="{{event.title}}" ng-if="event.event_image">
<img class="pull-right img-responsive" src="data:image/png;base64," data-src="holder.js/100%x100%/text:&#xf03e;/font:FontAwesome/icon" bs-holder ng-if="!event.event_image">
</div>
</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-12 text-center m-t-md">
<a class="btn btn-warning" ng-click="loadMoreEvents()" ng-if="paginateActive" translate>{{ 'load_the_next_events' }}</a>
<a class="btn btn-warning" ng-click="loadMoreEvents()" ng-hide="noMoreResults" translate>{{ 'load_the_next_events' }}</a>
</div>
</div>

View File

@ -1,9 +1,8 @@
class API::AgeRangesController < API::ApiController
before_action :authenticate_user!
before_action :authenticate_user!, except: [:index]
before_action :set_age_range, only: [:show, :update, :destroy]
def index
authorize AgeRange
@age_ranges = AgeRange.all
end

View File

@ -1,9 +1,8 @@
class API::CategoriesController < API::ApiController
before_action :authenticate_user!
before_action :authenticate_user!, except: [:index]
before_action :set_category, only: [:show, :update, :destroy]
def index
authorize Category
@categories = Category.all
end

View File

@ -1,9 +1,8 @@
class API::EventThemesController < API::ApiController
before_action :authenticate_user!
before_action :authenticate_user!, except: [:index]
before_action :set_event_theme, only: [:show, :update, :destroy]
def index
authorize EventTheme
@event_themes = EventTheme.all
end

View File

@ -3,9 +3,16 @@ class API::EventsController < API::ApiController
def index
@events = policy_scope(Event)
@total = @events.count
@page = params[:page]
# filters
@events = @events.joins(:categories).where('categories.id = :category', category: params[:category_id]) if params[:category_id]
@events = @events.joins(:event_themes).where('event_themes.id = :theme', theme: params[:theme_id]) if params[:theme_id]
@events = @events.where('age_range_id = :age_range', age_range: params[:age_range_id]) if params[:age_range_id]
# paginate
@events = @events.page(@page).per(12)
end
# GET /events/upcoming/:limit

View File

@ -1,5 +1,5 @@
class AgeRangePolicy < ApplicationPolicy
%w(index create update destroy show).each do |action|
%w(create update destroy show).each do |action|
define_method "#{action}?" do
user.is_admin?
end

View File

@ -1,5 +1,5 @@
class CategoryPolicy < ApplicationPolicy
%w(index create update destroy show).each do |action|
%w(create update destroy show).each do |action|
define_method "#{action}?" do
user.is_admin?
end

View File

@ -1,5 +1,5 @@
class EventThemePolicy < ApplicationPolicy
%w(index create update destroy show).each do |action|
%w(create update destroy show).each do |action|
define_method "#{action}?" do
user.is_admin?
end

View File

@ -1,8 +1,10 @@
total = @events.count
json.cache! [@events, @page] do
json.array!(@events) do |event|
json.partial! 'api/events/event', event: event
json.event_image_small event.event_image.attachment.small.url if event.event_image
json.url event_url(event, format: :json)
json.nb_total_events @total
json.nb_total_events total
end
end

View File

@ -1,7 +1,7 @@
maxInvoices = @invoices.except(:offset, :limit, :order).count
max_invoices = @invoices.except(:offset, :limit, :order).count
json.array!(@invoices) do |invoice|
json.maxInvoices maxInvoices
json.maxInvoices max_invoices
json.extract! invoice, :id, :created_at, :reference, :invoiced_type, :user_id, :avoir_date
json.total (invoice.total / 100.00)
json.url invoice_url(invoice, format: :json)

View File

@ -1,8 +1,8 @@
user_is_admin = (current_user and current_user.is_admin?)
maxMembers = @query.except(:offset, :limit, :order).count
max_members = @query.except(:offset, :limit, :order).count
json.array!(@members) do |member|
json.maxMembers maxMembers
json.maxMembers max_members
json.id member.id
json.username member.username
json.slug member.slug

View File

@ -1,7 +1,7 @@
maxMembers = @query.except(:offset, :limit, :order).count
max_members = @query.except(:offset, :limit, :order).count
json.array!(@members) do |member|
json.maxMembers maxMembers
json.maxMembers max_members
json.id member.id
json.email member.email if current_user
json.profile do

View File

@ -132,7 +132,6 @@ en:
my_projects: "My projects"
projects_to_whom_i_take_part_in: "Projects to whom I take part in"
all_machines: "All machines"
all_themes: "All themes"
all_materials: "All materials"
load_next_projects: "Load next projects"
@ -200,6 +199,8 @@ en:
events_list:
# Fablab's events list
the_fablab_s_events: "The Fablab's events"
all_categories: "All categories"
for_all: "For all"
events_show:
# details and booking of an event

View File

@ -132,7 +132,6 @@ fr:
my_projects: "Mes projets"
projects_to_whom_i_take_part_in: "Les projets auxquels je collabore"
all_machines: "Toutes les machines"
all_themes: "Toutes les thématiques"
all_materials: "Tous les matériaux"
load_next_projects: "Charger les projets suivants"
@ -200,6 +199,8 @@ fr:
events_list:
# liste des évènements du fablab
the_fablab_s_events: "Les évènements du Fab Lab"
all_categories: "Toutes les catégories"
for_all: "Tout public"
events_show:
# détails d'un événement et réservation

View File

@ -87,6 +87,7 @@ en:
_click_on_the_synchronization_button_opposite_: "click on the synchronization button opposite"
_disconnect_then_reconnect_: "disconnect then reconnect"
_for_your_changes_to_take_effect: "for your changes to take effect."
all_themes: "All themes"
messages:
you_will_lose_any_unsaved_modification_if_you_quit_this_page: "You will lose any unsaved modification if you quit this page"

View File

@ -87,6 +87,7 @@ fr:
_click_on_the_synchronization_button_opposite_: "cliquez sur le bouton de synchronisation ci-contre"
_disconnect_then_reconnect_: "déconnectez-vous puis re-connectez vous"
_for_your_changes_to_take_effect: "pour que les modifications soient prises en compte."
all_themes: "Toutes les thématiques"
messages:
you_will_lose_any_unsaved_modification_if_you_quit_this_page: "Vous perdrez les modifications non enregistrées si vous quittez cette page"