Merge branch 'master' into ent_types_frontend

This commit is contained in:
Rafael Schouten
2014-09-25 10:09:42 +10:00
37 changed files with 402 additions and 111 deletions

View File

@@ -15,6 +15,8 @@
#= require ../shared/bindonce.min.js
#= require ../shared/ng-infinite-scroll.min.js
#= require ../shared/angular-local-storage.js
#= require angularjs-file-upload
#= require angular-rails-templates
#= require_tree ../templates

View File

@@ -0,0 +1,13 @@
angular.module('Darkswarm').controller "EnterpriseImageCtrl", ($scope, EnterpriseImageService) ->
$scope.imageStep = 'logo'
$scope.imageSteps = ['logo', 'promo']
$scope.imageUploader = EnterpriseImageService.imageUploader
$scope.imageSelect = (image_step) ->
EnterpriseImageService.imageSrc = null
$scope.imageStep = image_step
$scope.imageSrc = ->
EnterpriseImageService.imageSrc

View File

@@ -12,4 +12,4 @@ Darkswarm.controller "RegistrationFormCtrl", ($scope, RegistrationService, Enter
EnterpriseRegistrationService.update(nextStep) if $scope.valid(form)
$scope.selectIfValid = (nextStep, form) ->
RegistrationService.select(nextStep) if $scope.valid(form)
RegistrationService.select(nextStep) if $scope.valid(form)

View File

@@ -1,18 +1,19 @@
window.Darkswarm = angular.module("Darkswarm", ["ngResource",
'mm.foundation',
'angularLocalStorage',
'pasvaz.bindonce',
'infinite-scroll',
'angular-flash.service',
window.Darkswarm = angular.module("Darkswarm", ["ngResource",
'mm.foundation',
'angularLocalStorage',
'pasvaz.bindonce',
'infinite-scroll',
'angular-flash.service',
'templates',
'ngSanitize',
'ngAnimate',
'google-maps',
'duScroll',
'angularFileUpload',
]).config ($httpProvider, $tooltipProvider, $locationProvider, $anchorScrollProvider) ->
$httpProvider.defaults.headers.post['X-CSRF-Token'] = $('meta[name="csrf-token"]').attr('content')
$httpProvider.defaults.headers.put['X-CSRF-Token'] = $('meta[name="csrf-token"]').attr('content')
$httpProvider.defaults.headers['common']['X-Requested-With'] = 'XMLHttpRequest'
$httpProvider.defaults.headers.post['X-CSRF-Token'] = $('meta[name="csrf-token"]').attr('content')
$httpProvider.defaults.headers.put['X-CSRF-Token'] = $('meta[name="csrf-token"]').attr('content')
$httpProvider.defaults.headers['common']['X-Requested-With'] = 'XMLHttpRequest'
$httpProvider.defaults.headers.common.Accept = "application/json, text/javascript, */*"
# This allows us to trigger these two events on tooltips
@@ -20,4 +21,3 @@ window.Darkswarm = angular.module("Darkswarm", ["ngResource",
# We manually handle our scrolling
$anchorScrollProvider.disableAutoScrolling()

View File

@@ -0,0 +1,12 @@
Darkswarm.factory "EnterpriseImageService", (FileUploader, spreeApiKey) ->
new class EnterpriseImageService
imageSrc: null
imageUploader: new FileUploader
headers:
'X-Spree-Token': spreeApiKey
autoUpload: true
configure: (enterprise) =>
@imageUploader.url = "/api/enterprises/#{enterprise.id}/update_image"
@imageUploader.onSuccessItem = (image, response) => @imageSrc = response

View File

@@ -1,4 +1,4 @@
Darkswarm.factory "EnterpriseRegistrationService", ($http, RegistrationService, CurrentUser, spreeApiKey, Loading, availableCountries, enterpriseAttributes) ->
Darkswarm.factory "EnterpriseRegistrationService", ($http, RegistrationService, EnterpriseImageService, CurrentUser, spreeApiKey, Loading, availableCountries, enterpriseAttributes) ->
new class EnterpriseRegistrationService
enterprise:
user_ids: [CurrentUser.id]
@@ -22,6 +22,7 @@ Darkswarm.factory "EnterpriseRegistrationService", ($http, RegistrationService,
).success((data) =>
Loading.clear()
@enterprise.id = data
EnterpriseImageService.configure(@enterprise)
RegistrationService.select('about')
).error((data) =>
Loading.clear()
@@ -54,4 +55,4 @@ Darkswarm.factory "EnterpriseRegistrationService", ($http, RegistrationService,
enterprise[key] = value
enterprise.address_attributes = @enterprise.address if @enterprise.address?
enterprise.address_attributes.country_id = @enterprise.country.id if @enterprise.country?
enterprise
enterprise

View File

@@ -1,4 +1,4 @@
Darkswarm.factory "RegistrationService", (Navigation, $modal, Loading)->
angular.module('Darkswarm').factory "RegistrationService", (Navigation, $modal, Loading)->
new class RegistrationService
constructor: ->
@@ -20,4 +20,4 @@ Darkswarm.factory "RegistrationService", (Navigation, $modal, Loading)->
close: ->
Loading.message = "Taking you back to the home page"
Navigation.go "/"
Navigation.go "/"

View File

@@ -9,7 +9,7 @@
{{ enterprise.name }}
%ng-include{ src: "'registration/steps.html'" }
%form{ name: 'about', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "update('social',about)" } }
%form{ name: 'about', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "update('images',about)" } }
.row
.small-12.columns
.alert-box.alert{"data-alert" => ""}

View File

@@ -1,14 +1,20 @@
.container#registration-images
.container#registration-images{ 'nv-file-drop' => true, uploader: "imageUploader", options:"{ alias: imageStep }", ng: { controller: "EnterpriseImageCtrl" } }
.header
%h2 Thanks!
%h5 Let's upload some pretty pictures so your profile looks great! :)
%ng-include{ src: "'registration/steps.html'" }
.row.content
%form{ name: 'images', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "select('social')" } }
.row{ ng: { repeat: 'image_step in imageSteps', show: "imageStep == image_step" } }
%ng-include{ src: "'registration/images/'+ image_step + '.html'" }
.row.buttons
.small-12.columns
%input.button.primary.left{ type: "button", value: "Back", ng: { click: "select('about')" } }
 
%input.button.primary.right{ type: "button", value: "Continue", ng: { click: "select('social')" } }
.row.buttons.pad-top{ ng: { if: "imageStep == 'logo'" } }
.small-12.columns
%input.button.primary{ type: "button", value: "Back", ng: { click: "select('about')" } }
 
%input.button.primary{ type: "button", value: "Continue", ng: { click: "imageSelect('promo')" } }
.row.buttons.pad-top{ ng: { if: "imageStep == 'promo'" } }
.small-12.columns
%input.button.primary{ type: "button", value: "Back", ng: { click: "imageSelect('logo')" } }
 
%input.button.primary{ type: "submit", value: "Continue" }

View File

@@ -0,0 +1,41 @@
.small-12.medium-12.large-6.columns
.row
.small-12.columns.center
.row
.small-12.columns.center
%h4
Step 1. Select Logo Image
.row
.small-12.columns.center
%span.small
Tip: Square images will work best, preferably at least 300×300px
.row.pad-top
.small-12.columns
.image-select.small-12.columns
%label.small-12.columns.button{ for: 'image-select' } Choose a logo image
%input#image-select{ type: 'file', hidden: true, 'nv-file-select' => true, uploader: "imageUploader", options: '{ alias: imageStep }' }
.row.show-for-large-up
.large-12.columns
%span#or.large-12.columns
OR
.row.show-for-large-up
.large-12.columns
#image-over{ 'nv-file-over' => true, uploader: "imageUploader" }
Drag and drop your logo here
.small-12.medium-12.large-6.columns
.row
.small-12.columns.center
.row
.small-12.columns.center
%h4
Step 2. Review Your Logo
.row
.small-12.columns.center
%span.small
Tip: for best results, your logo should fill the available space
.row.pad-top
.small-12.columns.center
#image-placeholder.logo
%img{ ng: { show: "imageSrc()", src: '{{ imageSrc() }}' } }
.message{ ng: { hide: "imageSrc()" } }
Your logo will appear here for review once uploaded

View File

@@ -0,0 +1,39 @@
.small-12.medium-12.large-12.columns
.row
.small-12.columns.center
%h4
Step 3. Select Promo Image
.row
.small-12.medium-12.large-5.columns.center
.row
.small-12.columns.center
%span.small
Tip: Shown as a banner, preferred size is 1200×260px
.row.pad-top
.small-12.columns
.image-select.small-12.columns
%label.small-12.columns.button{ for: 'image-select' } Choose a promo image
%input#image-select{ type: 'file', hidden: true, 'nv-file-select' => true, uploader: "imageUploader", options: '{ alias: imageStep }' }
.large-2.columns
%span#or.horizontal.large-12.columns
OR
.large-5.columns
#image-over{ 'nv-file-over' => true, uploader: "imageUploader" }
Drag and drop your promo here
.small-12.medium-12.large-12.columns.pad-top
.row
.small-12.columns.center
%h4
Step 4. Review Your Promo Banner
.row
.small-12.columns.center
.row
.small-12.columns.center
%span.small
Tip: for best results, your promo image should fill the available space
.row.pad-top
.small-12.columns.center
#image-placeholder.promo
%img{ ng: { show: "imageSrc()", src: '{{ imageSrc() }}' } }
.message{ ng: { hide: "imageSrc()" } }
Your logo will appear here for review once uploaded

View File

@@ -6,35 +6,34 @@
.small-12.medium-3.large-2.columns.text-right.hide-for-small-only
%img{:src => "/assets/potatoes.png"}
.small-12.medium-9.large-10.columns
%p
Your profile gives you an online presence on the
%strong Open Food Network,
%p
Your profile gives you an online presence on the
%strong Open Food Network,
allowing you to easily connect with potential customers or partners. You can always choose to update your info later, as well as choose to upgrade your Profile to and Online Store, where you can sell products, track orders and receive payments. Creating a profile takes about 5-10 minutes.
.row{ 'data-equalizer' => true }
.small-12.medium-6.large-6.columns.pad-top{ 'data-equalizer-watch' => true }
%h5 You'll need the following:
%ul.check-list
%li
%li
Your enterprise address and contact details
%li
%li
Your logo image
%li
%li
A pretty picture for your profile header
%li
%li
Some 'About Us' text
.small-12.medium-6.large-6.columns{ 'data-equalizer-watch' => true}
.highlight-box
%h5 Your profile entitles you to:
%ul.small-block-grid-1
%li
%li
%i.ofn-i_020-search
A searchable listing
%li
%li
%i.ofn-i_040-hub
A pin on the OFN map
.row
.small-12.columns
%hr
%input.button.primary{ type: "button", value: "Let's get started!", ng: { click: "select('details')" } }

View File

@@ -30,6 +30,6 @@
.row.buttons
.small-12.columns
%input.button.secondary{ type: "button", value: "Back", ng: { click: "select('about')" } }
%input.button.secondary{ type: "button", value: "Back", ng: { click: "select('images')" } }
 
%input.button.primary{ type: "submit", value: "Continue" }
%input.button.primary{ type: "submit", value: "Continue" }

View File

@@ -80,6 +80,53 @@
color: #333
@include box-shadow(inset 0 0 1px 0 #fff)
.image-select
label
font-size: 18px
padding: 21px 0px
#logo-select
display: none
#image-over
font-size: 18px
padding: 41px 0px
border: 3px dashed #494949
text-align: center
font-weight: bold
color: #494949
&.nv-file-over
background-color: #78cd91
#or
text-align: center
font-weight: bold
font-size: 18px
padding: 21px 0px
&.horizontal
padding: 41px 0px
#image-placeholder
font-size: 18px
font-weight: bold
color: #373737
background-color: #e1e1e1
text-align: center
border: 3px dashed #494949
margin-left: auto
margin-right: auto
&.logo
.message
padding-top: 6em
width: 306px
height: 306px
&.promo
.message
padding-top: 4em
width: 726px
height: 166px
#registration-details
#enterprise-types
a.panel
@@ -112,4 +159,3 @@
p
clear: both
font-size: 0.875rem

View File

@@ -7,6 +7,7 @@ module Admin
before_filter :check_bulk_type, only: :bulk_update
before_filter :override_owner, only: :create
before_filter :check_owner, only: :update
before_filter :check_bulk_owner, only: :bulk_update
helper 'spree/products'
include OrderCyclesHelper
@@ -79,11 +80,19 @@ module Admin
end
def check_owner
unless spree_current_user == @enterprise.owner || spree_current_user.admin?
unless ( spree_current_user == @enterprise.owner ) || spree_current_user.admin?
params[:enterprise].delete :owner_id
end
end
def check_bulk_owner
unless spree_current_user.admin?
params[:enterprise_set][:collection_attributes].each do |i, enterprise_params|
enterprise_params.delete :owner_id
end
end
end
# Overriding method on Spree's resource controller
def location_after_save
if params[:enterprise].key? :producer_properties_attributes

View File

@@ -27,9 +27,9 @@ module Api
end
def update
authorize! :update, Enterprise
@enterprise = Enterprise.find(params[:id])
authorize! :update, @enterprise
if @enterprise.update_attributes(params[:enterprise])
render text: @enterprise.id, :status => 200
else
@@ -37,6 +37,19 @@ module Api
end
end
def update_image
@enterprise = Enterprise.find(params[:id])
authorize! :update, @enterprise
if params[:logo] && @enterprise.update_attributes( { logo: params[:logo] } )
render text: @enterprise.logo.url(:medium), :status => 200
elsif params[:promo] && @enterprise.update_attributes( { promo_image: params[:promo] } )
render text: @enterprise.promo_image.url(:medium), :status => 200
else
invalid_resource!(@enterprise)
end
end
private
def override_owner

View File

@@ -2,7 +2,7 @@ require 'open_food_network/spree_api_key_loader'
class RegistrationController < BaseController
include OpenFoodNetwork::SpreeApiKeyLoader
before_filter :load_spree_api_key, only: :index
before_filter :load_spree_api_key, only: [:index, :store]
before_filter :check_user, except: :authenticate
layout 'registration'

View File

@@ -12,6 +12,7 @@ Spree::Api::ProductsController.class_eval do
def bulk_products
@products = OpenFoodNetwork::Permissions.new(current_api_user).managed_products.
merge(product_scope).
order('created_at DESC').
ransack(params[:q]).result.
page(params[:page]).per(params[:per_page])

View File

@@ -34,7 +34,7 @@ class Enterprise < ActiveRecord::Base
path: 'public/images/enterprises/logos/:id/:style/:basename.:extension'
has_attached_file :promo_image,
styles: { large: "1200x260#", thumb: "100x100>" },
styles: { large: "1200x260#", medium: "720x156#", thumb: "100x100>" },
url: '/images/enterprises/promo_images/:id/:style/:basename.:extension',
path: 'public/images/enterprises/promo_images/:id/:style/:basename.:extension'

View File

@@ -2,12 +2,17 @@ class AbilityDecorator
include CanCan::Ability
def initialize(user)
add_base_abilities user if is_new_user? user
add_enterprise_management_abilities user if can_manage_enterprises? user
add_product_management_abilities user if can_manage_products? user
add_relationship_management_abilities user if can_manage_relationships? user
end
def is_new_user?(user)
user.enterprises.blank?
end
def can_manage_enterprises?(user)
user.enterprises.present?
end
@@ -22,6 +27,9 @@ class AbilityDecorator
can_manage_enterprises? user
end
def add_base_abilities(user)
can [:create], Enterprise
end
def add_enterprise_management_abilities(user)
# Spree performs authorize! on (:create, nil) when creating a new order from admin, and also (:search, nil)
@@ -71,7 +79,7 @@ class AbilityDecorator
can [:admin, :index, :read, :create, :edit, :update, :fire], Spree::Shipment
can [:admin, :index, :read, :create, :edit, :update, :fire], Spree::Adjustment
can [:admin, :index, :read, :create, :edit, :update, :fire], Spree::ReturnAuthorization
can [:create], OrderCycle
can [:admin, :index, :read, :edit, :update, :bulk_update, :clone], OrderCycle do |order_cycle|
user.enterprises.include? order_cycle.coordinator

View File

@@ -16,7 +16,8 @@
%col{style: "width: 5%;"}/
- if spree_current_user.admin?
%col{style: "width: 12%;"}/
%col{style: "width: 18%;"}/
- if spree_current_user.admin?
%col{style: "width: 18%;"}/
%col{style: "width: 25%;"}/
%thead
%tr{"data-hook" => "enterprises_header"}
@@ -25,7 +26,8 @@
%th Visible?
- if spree_current_user.admin?
%th Type
%th Owner
- if spree_current_user.admin?
%th Owner
%th
%tbody
= f.fields_for :collection do |enterprise_form|
@@ -41,7 +43,8 @@
%td= enterprise_form.check_box :visible
- if spree_current_user.admin?
%td= enterprise_form.select :type, Enterprise::TYPES, {}, class: 'select2 fullwidth'
%td= enterprise_form.select :owner_id, enterprise.users.map{ |e| [ e.email, e.id ] }, {}, class: "select2 fullwidth"
- if spree_current_user.admin?
%td= enterprise_form.select :owner_id, enterprise.users.map{ |e| [ e.email, e.id ] }, {}, class: "select2 fullwidth"
%td{"data-hook" => "admin_users_index_row_actions"}
= render 'actions', enterprise: enterprise
- if @enterprises.empty?

View File

@@ -31,6 +31,6 @@
%section{ role: "main" }
= yield
#footer
%loading