1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2024-12-01 12:24:28 +01:00

space creation interface

This commit is contained in:
Sylvain 2017-02-14 11:28:07 +01:00
parent 9d367f95db
commit da95e6e0d8
7 changed files with 250 additions and 6 deletions

View File

@ -1,4 +1,76 @@
### COMMON CODE ###
##
# Provides a set of common callback methods to the $scope parameter. These methods are used
# in the various spaces' admin controllers.
#
# Provides :
# - $scope.submited(content)
# - $scope.cancel()
# - $scope.fileinputClass(v)
# - $scope.addFile()
# - $scope.deleteFile(file)
#
# Requires :
# - $scope.space.space_files_attributes = []
# - $state (Ui-Router) [ 'app.public.spaces_list' ]
##
class SpacesController
constructor: ($scope, $state) ->
##
# For use with ngUpload (https://github.com/twilson63/ngUpload).
# Intended to be the callback when the upload is done: any raised error will be stacked in the
# $scope.alerts array. If everything goes fine, the user is redirected to the spaces list.
# @param content {Object} JSON - The upload's result
##
$scope.submited = (content) ->
if !content.id?
$scope.alerts = []
angular.forEach content, (v, k)->
angular.forEach v, (err)->
$scope.alerts.push
msg: k+': '+err
type: 'danger'
else
$state.go('app.public.spaces_list')
##
# Changes the current user's view, redirecting him to the spaces list
##
$scope.cancel = ->
$state.go('app.public.spaces_list')
##
# For use with 'ng-class', returns the CSS class name for the uploads previews.
# The preview may show a placeholder or the content of the file depending on the upload state.
# @param v {*} any attribute, will be tested for truthiness (see JS evaluation rules)
##
$scope.fileinputClass = (v)->
if v
'fileinput-exists'
else
'fileinput-new'
##
# This will create a single new empty entry into the space attachements list.
##
$scope.addFile = ->
$scope.space.space_files_attributes.push {}
##
# This will remove the given file from the space attachements list. If the file was previously uploaded
# to the server, it will be marked for deletion on the server. Otherwise, it will be simply truncated from
# the attachements array.
# @param file {Object} the file to delete
##
$scope.deleteFile = (file) ->
index = $scope.space.space_files_attributes.indexOf(file)
if file.id?
file._destroy = true
else
$scope.space.space_files_attributes.splice(index, 1)
##
# Manages the transition when a user clicks on the reservation button.
# According to the status of user currently logged into the system, redirect him to the reservation page,
@ -26,7 +98,7 @@ _reserveSpace = (space, e) ->
##
Application.Controllers.controller "SpacesController", ["$scope", "$state", 'spacesPromise', ($scope, $state, spacesPromise) ->
## Retrieve the list of machines
## Retrieve the list of spaces
$scope.spaces = spacesPromise
##
@ -36,7 +108,7 @@ Application.Controllers.controller "SpacesController", ["$scope", "$state", 'spa
$state.go('app.public.space_show', { id: space.slug })
##
# Callback to book a reservation for the current machine
# Callback to book a reservation for the current space
##
$scope.reserveSpace = _reserveSpace.bind
$scope: $scope
@ -57,7 +129,7 @@ Application.Controllers.controller "NewSpaceController", ["$scope", "$state", 'C
## Form action on the above URL
$scope.method = "post"
## default machine parameters
## default space parameters
$scope.space =
space_files_attributes: []

View File

@ -0,0 +1,134 @@
<form role="form"
name="spaceForm"
class="form-horizontal"
action="{{ actionUrl }}"
ng-upload="submited(content)"
upload-options-enable-rails-csrf="true"
unsaved-warning-form
novalidate>
<input name="_method" type="hidden" ng-value="method">
<section class="panel panel-default bg-light m-lg">
<div class="panel-body m-r">
<uib-alert ng-repeat="alert in alerts" type="{{alert.type}}" close="closeAlert($index)">{{alert.msg}}</uib-alert>
<div class="form-group m-b-lg" ng-class="{'has-error': spaceForm['space[name]'].$dirty && spaceForm['space[name]'].$invalid}">
<label for="space_name" class="col-sm-2 control-label">{{ 'space.name' | translate }} *</label>
<div class="col-sm-4">
<input ng-model="space.name"
type="text"
name="space[name]"
class="form-control"
id="space_name"
placeholder="{{'space.name' | translate}}"
required>
<span class="help-block" ng-show="spaceForm['space[name]'].$dirty && spaceForm['space[name]'].$error.required" translate>{{ 'space.name_is_required' }}</span>
</div>
</div>
<div class="form-group m-b-lg">
<label for="space_image" class="col-sm-2 control-label">{{ 'space.illustration' | translate }} *</label>
<div class="col-sm-10">
<div class="fileinput" data-provides="fileinput" ng-class="fileinputClass(space.space_image)">
<div class="fileinput-new thumbnail" style="width: 334px; height: 250px;">
<img src="data:image/png;base64," data-src="holder.js/100%x100%/text:&#xf03e;/font:FontAwesome/icon" bs-holder ng-if="!space.space_image">
</div>
<div class="fileinput-preview fileinput-exists thumbnail" style="max-width: 334px;">
<img ng-src="{{ space.space_image }}" alt="" />
</div>
<div>
<span class="btn btn-default btn-file">
<span class="fileinput-new">{{ 'space.add_an_illustration' | translate }} <i class="fa fa-upload fa-fw"></i></span>
<span class="fileinput-exists" translate>{{ 'change' }}</span>
<input type="file"
id="space_image"
ng-model="space.space_image"
name="space[space_image_attributes][attachment]"
accept="image/*"
required
bs-jasny-fileinput>
</span>
<a href="#" class="btn btn-danger fileinput-exists" data-dismiss="fileinput" translate>{{ 'delete' }}</a>
</div>
</div>
</div>
</div>
<div class="form-group m-b-xl" ng-class="{'has-error': spaceForm['space[default_places]'].$dirty && spaceForm['space[default_places]'].$invalid}">
<label for="default_places" class="col-sm-2 control-label">{{ 'space.default_places' | translate }} *</label>
<div class="col-sm-10">
<input type="number"
name="space[default_places]"
ng-model="space.default_places"
id="default_places"
class="form-control"
required>
<span class="help-block" ng-show="spaceForm['space[default_places]'].$dirty && spaceForm['space[default_places]'].$error.required" translate>{{ 'space.default_places_is_required' }}</span>
</div>
</div>
<div class="form-group m-b-xl">
<label for="space_description" class="col-sm-2 control-label" translate>{{ 'space.description' }}</label>
<div class="col-sm-10">
<input type="hidden"
name="space[description]"
ng-value="space.description" />
<summernote ng-model="space.description"
id="space_description"
placeholder=""
config="summernoteOpts"
name="space[description]">
</summernote>
</div>
</div>
<div class="form-group m-b-xl">
<label for="space_characteristics" class="col-sm-2 control-label" translate>{{ 'space.characteristics' }}</label>
<div class="col-sm-10">
<input type="hidden"
name="space[characteristics]"
ng-value="space.characteristics" />
<summernote ng-model="space.characteristics"
id="space_characteristics"
placeholder=""
config="summernoteOpts"
name="space[characteristics]">
</summernote>
</div>
</div>
<div class="form-group m-b-xl">
<label class="col-sm-2 control-label" translate>{{ 'space.attached_files_(pdf)' }}</label>
<div class="col-sm-10">
<div ng-repeat="file in space.space_files_attributes" ng-show="!file._destroy">
<input type="hidden" ng-model="file.id" name="space[space_files_attributes][][id]" ng-value="file.id" />
<input type="hidden" ng-model="file._destroy" name="space[space_files_attributes][][_destroy]" ng-value="file._destroy"/>
<div class="fileinput input-group" data-provides="fileinput" ng-class="fileinputClass(file.attachment)">
<div class="form-control" data-trigger="fileinput">
<i class="glyphicon glyphicon-file fileinput-exists"></i> <span class="fileinput-filename">{{file.attachment}}</span>
</div>
<span class="input-group-addon btn btn-default btn-file"><span class="fileinput-new" translate>{{ 'space.attach_a_file' }}</span>
<span class="fileinput-exists" translate>{{ 'change' }}</span><input type="file" name="space[space_files_attributes][][attachment]" accept=".pdf"></span>
<a class="input-group-addon btn btn-danger fileinput-exists" data-dismiss="fileinput" ng-click="deleteFile(file)"><i class="fa fa-trash-o"></i></a>
</div>
</div>
<a class="btn btn-default" ng-click="addFile()" role="button"> {{ 'space.add_an_attachment' | translate }} <i class="fa fa-file-o fa-fw"></i></a>
</div>
</div>
</div> <!-- ./panel-body -->
<div class="panel-footer no-padder">
<input type="submit"
value="{{ 'space.add_this_space' | translate }}"
class="r-b btn-valid btn btn-warning btn-block p-lg btn-lg text-u-c"
ng-disabled="spaceForm.$invalid"/>
</div>
</section>
</form>

View File

@ -42,7 +42,7 @@ class API::SpacesController < API::ApiController
end
def space_params
params.require(:space).permit(:name, :description, :characteristics, space_image_attributes: [:attachment],
params.require(:space).permit(:name, :description, :characteristics, :default_places, space_image_attributes: [:attachment],
space_files_attributes: [:id, :attachment, :_destroy])
end
end

View File

@ -2,6 +2,8 @@ class Space < ActiveRecord::Base
extend FriendlyId
friendly_id :name, use: :slugged
validates :name, :default_places, presence: true
has_one :space_image, as: :viewable, dependent: :destroy
accepts_nested_attributes_for :space_image, allow_destroy: true
has_many :space_files, as: :viewable, dependent: :destroy

View File

@ -73,7 +73,7 @@ fr:
# créer un nouvel espace
add_a_new_space: "Ajouter un nouvel espace"
watch_out_when_creating_a_new_space_its_prices_are_initialized_at_0_for_all_subscriptions: "Attention, lors de la création d'un espace, ses tarifs de réservation sont initialisés à zero pour tout les abonnements."
consider_changing_its_prices_before_creating_any_reservation_slot: "Pensez à modifier ces prix avant de créer des créneaux pour cette machine."
consider_changing_its_prices_before_creating_any_reservation_slot: "Pensez à modifier ces prix avant de créer des créneaux pour cet espace."
events:
# gestion et suivi des évènements

View File

@ -381,3 +381,21 @@ en:
unable_to_apply_the_coupon_because_amount_exceeded: "Unable to apply the coupon: the discount exceed the total amount of this purchase."
unable_to_apply_the_coupon_because_undefined: "Unable to apply the coupon: an unexpected error occurred, please contact the Fablab's manager."
unable_to_apply_the_coupon_because_rejected: "This code does not exists."
space:
# form to create/edit a space
space:
name: "Name"
name_is_required: "Name is required."
illustration: "Illustration"
add_an_illustration: "Add an illustration"
description: "Description"
description_is_required: "Description is required."
characteristics: "Characteristics"
characteristics_are_required: "Characteristics are required."
attached_files_(pdf): "Attached files (pdf)"
attach_a_file: "Attach a file"
add_an_attachment: "Add an attachment"
add_this_space: "Add this space"
default_places: "Default maximum tickets"
default_places_is_required: "Default maximum tickets is required."

View File

@ -380,4 +380,22 @@ fr:
unable_to_apply_the_coupon_because_already_used: "Impossible d'appliquer la réduction : vous avez déjà utilisé ce code promo par le passé."
unable_to_apply_the_coupon_because_amount_exceeded: "Impossible d'appliquer la réduction : la réduction dépasse le total de cet achat."
unable_to_apply_the_coupon_because_undefined: "Impossible d'appliquer la réduction : une erreur inattendue s'est produite, veuillez contacter le gestionnaire du Fablab."
unable_to_apply_the_coupon_because_rejected: "Ce code promo n'existe pas."
unable_to_apply_the_coupon_because_rejected: "Ce code promo n'existe pas."
space:
# formulaire de création/modification d'un espace
space:
name: "Nom"
name_is_required: "Le nom est requis."
illustration: "Visuel"
add_an_illustration: "Ajouter un visuel"
description: "Description"
description_is_required: "La description est requise."
characteristics: "Caractéristiques"
characteristics_are_required: "Les caractéristiques sont requises."
attached_files_(pdf): "Pièces jointes (pdf)"
attach_a_file: "Joindre un fichier"
add_an_attachment: "Ajouter une pièce jointe"
add_this_space: "Ajouter cet espace"
default_places: "Maximum de places par défaut"
default_places_is_required: "Le nombre de places maximum par défaut est requis."