Merge branch 'master' into simple-order-cycles

This commit is contained in:
Rohan Mitchell
2014-10-23 09:36:03 +11:00
54 changed files with 788 additions and 366 deletions

View File

@@ -3,7 +3,7 @@ Darkswarm.controller "RegistrationCtrl", ($scope, RegistrationService, Enterpris
$scope.enterprise = EnterpriseRegistrationService.enterprise
$scope.select = RegistrationService.select
$scope.steps = ['details','address','contact','about','images','social']
$scope.steps = ['details','contact','type','about','images','social']
$scope.countries = availableCountries

View File

@@ -0,0 +1,7 @@
Darkswarm.directive "ofnInlineAlert", ->
restrict: 'A'
scope: true
link: (scope, elem, attrs) ->
scope.visible = true
scope.close = ->
scope.visible = false

View File

@@ -1,6 +0,0 @@
Darkswarm.directive "ofnInlineFlash", ->
restrict: 'E'
controller: ($scope) ->
$scope.visible = true
$scope.closeFlash = ->
$scope.visible = false

View File

@@ -3,7 +3,7 @@ Darkswarm.directive "ofnRegistrationLimitModal", (Navigation, $modal, Loading) -
link: (scope, elem, attr)->
scope.modalInstance = $modal.open
templateUrl: 'registration/limit_reached.html'
windowClass: "login-modal large"
windowClass: "login-modal register-modal xlarge"
backdrop: 'static'
scope.modalInstance.result.then scope.close, scope.close

View File

@@ -1,4 +1,4 @@
Darkswarm.factory "AuthenticationService", (Navigation, $modal, $location, Redirections)->
Darkswarm.factory "AuthenticationService", (Navigation, $modal, $location, Redirections, Loading)->
new class AuthenticationService
selectedPath: "/login"
@@ -25,4 +25,9 @@ Darkswarm.factory "AuthenticationService", (Navigation, $modal, $location, Redir
active: Navigation.active
close: ->
Navigation.navigate "/"
if location.pathname == "/"
Navigation.navigate "/"
else
Loading.message = "Taking you back to the home page"
location.hash = ""
location.pathname = "/"

View File

@@ -1,44 +1,47 @@
.container#registration-about
.header
%h2 Nice one!
%h5
Now let's flesh out the details about
%span.brick{"ng-show" => "enterprise.is_distributor"}
{{ enterprise.name }}
%span.turquoise{"ng-show" => "!enterprise.is_distributor" }
{{ enterprise.name }}
%ng-include{ src: "'registration/steps.html'" }
.row
.small-12.columns
%header
%h2 Nice one!
%h5
Now let's flesh out the details about
%span{ ng: { class: "{brick: !enterprise.is_primary_producer, turquoise: enterprise.is_primary_producer}" } }
{{ enterprise.name }}
%form{ name: 'about', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "update('images',about)" } }
.row
.small-12.columns
.alert-box.alert{"data-alert" => ""}
{{ enterprise.name }} won't be visible on the Open Food Network until you enter a long and short description.
%a.close{:href => "#"} ×
.alert-box.info{"data-alert" => ""}
{{ enterprise.name }} has been created on the Open Food Network. If you leave at any point from here onwards, your enterprise will be saved, and you can always login to the admin section to update or continue filling out your enterprise details.
%a.close{:href => "#"} ×
.alert-box.info{ "ofn-inline-alert" => true, ng: { show: "visible" } }
%h6 Success! {{ enterprise.name }} added to the Open Food Network
%span If you exit the wizard at any stage, login and go to admin to edit or update your enterprise details.
%a.close{ ng: { click: "close()" } } ×
.small-12.large-8.columns
.row
.small-12.columns
%label{ for: 'enterprise_description' } Short Description:
%input.chunky.small-12.columns{ id: 'enterprise_description', placeholder: "A short sentence describing your enterprise", ng: { model: 'enterprise.description' } }
.field
%label{ for: 'enterprise_description' } Short Description:
%input.chunky{ id: 'enterprise_description', placeholder: "A short sentence describing your enterprise", ng: { model: 'enterprise.description' } }
.row
.small-12.columns
%label{ for: 'enterprise_long_desc' } Long Description:
%textarea.chunky.small-12.columns{ id: 'enterprise_long_desc', rows: 6, placeholder: "This is your opportunity to tell the story of your enterprise - what makes you different and wonderful? We'd suggest keeping your description to under 600 characters or 150 words.", ng: { model: 'enterprise.long_description' } }
%small {{ enterprise.long_description.length }} characters / up to 600 recommended
.field
%label{ for: 'enterprise_long_desc' } Long Description:
%textarea.chunky{ id: 'enterprise_long_desc', rows: 6, placeholder: "This is your opportunity to tell the story of your enterprise - what makes you different and wonderful? We'd suggest keeping your description to under 600 characters or 150 words.", ng: { model: 'enterprise.long_description' } }
%small {{ enterprise.long_description.length }} characters / up to 600 recommended
.small-12.large-4.columns
.row
.small-12.columns
%label{ for: 'enterprise_abn' } ABN:
%input.chunky.small-12.columns{ id: 'enterprise_abn', placeholder: "eg. 99 123 456 789", ng: { model: 'enterprise.abn' } }
.field
%label{ for: 'enterprise_abn' } ABN:
%input.chunky{ id: 'enterprise_abn', placeholder: "eg. 99 123 456 789", ng: { model: 'enterprise.abn' } }
.row
.small-12.columns
%label{ for: 'enterprise_acn' } ACN:
%input.chunky.small-12.columns{ id: 'enterprise_acn', placeholder: "eg. 123 456 789", ng: { model: 'enterprise.acn' } }
.field
%label{ for: 'enterprise_acn' } ACN:
%input.chunky{ id: 'enterprise_acn', placeholder: "eg. 123 456 789", ng: { model: 'enterprise.acn' } }
.row.buttons.pad-top
.small-12.columns
%input.button.primary{ type: "submit", value: "Continue" }
%input.button.primary.right{ type: "submit", value: "Continue" }

View File

@@ -1,60 +0,0 @@
.container#registration-address
.header
%h2
Greetings
%span{ ng: { class: "{brick: enterprise.is_distributor, turquoise: !enterprise.is_distributor}" } }
{{ enterprise.name }}
%h5 Now we need to know where you are
%ng-include{ src: "'registration/steps.html'" }
%form{ name: 'address', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "selectIfValid('contact',address)" } }
.row.content
.small-12.medium-12.large-7.columns
.row
.small-12.columns.field
%label{ for: 'enterprise_address' } Address:
%input.chunky.small-12.columns{ id: 'enterprise_address', name: 'address1', required: true, placeholder: "eg. 123 Cranberry Drive", required: true, ng: { model: 'enterprise.address.address1' } }
%span.error.small-12.columns{ ng: { show: "address.address1.$error.required && submitted" } }
You need to enter an address.
.row
.small-12.large-8.columns.field
%label{ for: 'enterprise_city' } Suburb:
%input.chunky.small-12.columns{ id: 'enterprise_city', name: 'city', required: true, placeholder: "eg. Northcote", ng: { model: 'enterprise.address.city' } }
%span.error.small-12.columns{ ng: { show: "address.city.$error.required && submitted" } }
You need to enter a suburb.
.small-12.large-4.columns.field
%label{ for: 'enterprise_zipcode' } Postcode:
%input.chunky.small-12.columns{ id: 'enterprise_zipcode', name: 'zipcode', required: true, placeholder: "eg. 3070", ng: { model: 'enterprise.address.zipcode' } }
%span.error.small-12.columns{ ng: { show: "address.zipcode.$error.required && submitted" } }
You need to enter a postcode.
.row
.small-12.large-8.columns.field
%label{ for: 'enterprise_country' } Country:
%select.chunky.small-12.columns{ id: 'enterprise_country', name: 'country', required: true, ng: { model: 'enterprise.country', options: 'c as c.name for c in countries' } }
%span.error.small-12.columns{ ng: { show: "address.country.$error.required && submitted" } }
You need to enter a country.
.small-12.large-4.columns.field
%label{ for: 'enterprise_state' } State:
%select.chunky.small-12.columns{ id: 'enterprise_state', name: 'state', ng: { model: 'enterprise.address.state_id', options: 's.id as s.abbr for s in enterprise.country.states', show: 'countryHasStates()', required: 'countryHasStates()' } }
%span.error.small-12.columns{ ng: { show: "address.state.$error.required && submitted" } }
You need to enter a state.
.small-12.medium-12.large-5.hide-for-small-only
// This is the location area
/ %h6
/ Location display
/ %i.ofn-i_013-help.has-tip{ 'data-tooltip' => true, title: "Choose how you want to display your enterprise's address on the Open Food Network. By default, full location is shown everywhere including street name and number."}
/ .row
/ .small-12.columns
/ %label.indent-checkbox
/ %input{ type: 'checkbox', id: 'enterpise_suburb_only', ng: { model: 'enterprise.suburb_only' } }
/ Hide my street name and street number from the public (ie. only show the suburb)
/ .small-12.columns
/ %label.indent-checkbox
/ %input{ type: 'checkbox', id: 'enterprise_on_map', ng: { model: 'enterprise.on_map' } }
/ Blur my location on the map (show an approximate, not exact pin)
.row.buttons
.small-12.columns
%input.button.secondary{ type: "button", value: "Back", ng: { click: "select('details')" } }
 
%input.button.primary{ type: "submit", value: "Continue" }

View File

@@ -1,12 +1,13 @@
.container#registration-contact
.header
%h2 Last step to create your enterprise!
%h5
Who is responsible for managing
%span{ ng: { class: "{brick: enterprise.is_distributor, turquoise: !enterprise.is_distributor}" } }
{{ enterprise.name }}?
%ng-include{ src: "'registration/steps.html'" }
%form{ name: 'contact', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "create(contact)" } }
.row
.small-12.columns
%header
%h2 Greetings!
%h5
Who is responsible for managing {{ enterprise.name }}?
%form{ name: 'contact', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "selectIfValid('type',contact)" } }
.row.content
.small-12.medium-12.large-7.columns
.row
@@ -39,8 +40,8 @@
/ .small-12.columns
/ %label.indent-checkbox
/ %input{ type: 'checkbox', id: 'contact_phone_profile', ng: { model: 'enterprise.phone_in_profile' } }   Display phone in profile
.row.buttons
.small-12.columns
%input.button.secondary{ type: "button", value: "Back", ng: { click: "select('address')" } }
 
%input.button.primary{ type: "submit", value: "Continue" }
%input.button.secondary{ type: "button", value: "Back", ng: { click: "select('details')" } }
%input.button.primary.right{ type: "submit", value: "Continue" }

View File

@@ -1,43 +1,77 @@
.container#registration-details{bindonce: true}
.header
%h2 Let's Get Started
%h5{ bo: { if: "enterprise.sells != 'own'" } } Woot! First we need to know what sort of enterprise you are:
%h5{ bo: { if: "enterprise.sells == 'own'" } } Woot! First we need to know the name of your farm:
%ng-include{ src: "'registration/steps.html'" }
%form{ name: 'details', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "selectIfValid('address',details)" } }
.row
.small-12.columns.field
%label{ for: 'enterprise_name', bo: { if: "enterprise.sells != 'own'" } } Enterprise Name:
%label{ for: 'enterprise_name', bo: { if: "enterprise.sells == 'own'" } } Farm Name:
%input.chunky.small-12.columns{ id: 'enterprise_name', name: 'name', placeholder: "eg. Charlie's Awesome Farm", required: true, ng: { model: 'enterprise.name' } }
%span.error.small-12.columns{ ng: { show: "details.name.$error.required && submitted" } }
You need to enter a name for your enterprise!
.row
.small-12.columns
%header
%h2 Let's Get Started
%h5{ bo: { if: "enterprise.type != 'own'" } } Woot! First we need to know a little bit about your enterprise:
%h5{ bo: { if: "enterprise.type == 'own'" } } Woot! First we need to know a little bit about your farm:
.row#enterprise-types{ 'data-equalizer' => true, bo: { if: "enterprise.sells != 'own'" } }
.small-12.columns.field
%form{ name: 'details', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "selectIfValid('contact',details)" } }
.row
.small-12.medium-9.large-12.columns.end
.field
%label{ for: 'enterprise_name', bo: { if: "enterprise.type != 'own'" } } Enterprise Name:
%label{ for: 'enterprise_name', bo: { if: "enterprise.type == 'own'" } } Farm Name:
%input.chunky{ id: 'enterprise_name', name: 'name', placeholder: "e.g. Charlie's Awesome Farm", required: true, ng: { model: 'enterprise.name' } }
%span.error{ ng: { show: "details.name.$error.required && submitted" } }
Please choose a unique name for your enterprise
.row
.small-12.medium-9.large-6.columns
.field
%label{ for: 'enterprise_address' } Address line 1:
%input.chunky{ id: 'enterprise_address', name: 'address1', required: true, placeholder: "e.g. 123 Cranberry Drive", required: true, ng: { model: 'enterprise.address.address1' } }
%span.error{ ng: { show: "details.address1.$error.required && submitted" } }
Please enter an address
.field
%label{ for: 'enterprise_address2' } Address line 2:
%input.chunky{ id: 'enterprise_address2', name: 'address2', required: false, placeholder: "", required: false, ng: { model: 'enterprise.address.address2' } }
.small-12.medium-9.large-6.columns.end
.row
.small-12.columns
%label Choose one:
.small-12.medium-8.large-8.columns
.field
%label{ for: 'enterprise_city' } Suburb:
%input.chunky{ id: 'enterprise_city', name: 'city', required: true, placeholder: "e.g. Northcote", ng: { model: 'enterprise.address.city' } }
%span.error{ ng: { show: "details.city.$error.required && submitted" } }
Please enter a suburb
.small-12.medium-4.large-4.columns
.field
%label{ for: 'enterprise_zipcode' } Postcode:
%input.chunky{ id: 'enterprise_zipcode', name: 'zipcode', required: true, placeholder: "e.g. 3070", ng: { model: 'enterprise.address.zipcode' } }
%span.error{ ng: { show: "details.zipcode.$error.required && submitted" } }
Postcode required
.row
-# TODO redesign this to refelct the extra options available.
.small-12.medium-4.large-4.columns{ 'data-equalizer-watch' => true }
%a.panel#producer-panel{ href: "#", ng: { click: "enterprise.is_primary_producer = true", class: "{selected: (!enterprise.is_distributor && enterprise.is_primary_producer)}" } }
.left
/ %render-svg{ path: "/assets/map-icon-producer.svg" }
%h4 I'm A Producer
%p Producers make yummy things to eat &/or drink. You're a producer if you grow it, raise it, brew it, bake it, ferment it, milk it or mould it.
.small-12.medium-4.large-4.columns{ 'data-equalizer-watch' => true }
%a.panel#hub-panel{ href: "#", ng: { click: "enterprise.is_distributor = true; enterprise.is_primary_producer = false", class: "{selected: (enterprise.is_distributor && !enterprise.is_primary_producer)}" } }
.left
/ %render-svg{ path: "/assets/map-icon-hub.svg" }
%h4 I'm A Hub
%p Hubs connect the producer to the eater. Hubs can be co-ops, independent retailers, buying groups, wholesalers, CSA box schemes, farm-gate stalls, etc.
.small-12.medium-4.large-4.columns{ 'data-equalizer-watch' => true }
%a.panel#both-panel{ href: "#", ng: { click: "enterprise.is_distributor = true; enterprise.is_primary_producer = true", class: "{selected: (enterprise.is_distributor && enterprise.is_primary_producer)}" } }
.left
/ %render-svg{path: "/assets/map-icon-both.svg"}
%h4 I'm Both
%p Hey there, Jack-of-all-trades! Not only do you produce things to eat &/or drink, you also want to sell your yummies through an Open Food Network shopfront.
.small-12.medium-4.large-4.columns
.field
%label{ for: 'enterprise_state' } State:
%select.chunky{ id: 'enterprise_state', name: 'state', ng: { model: 'enterprise.address.state_id', options: 's.id as s.abbr for s in enterprise.country.states', show: 'countryHasStates()', required: 'countryHasStates()' } }
%span.error{ ng: { show: "details.state.$error.required && submitted" } }
State required
.small-12.medium-8.large-8.columns
.field
%label{ for: 'enterprise_country' } Country:
%select.chunky{ id: 'enterprise_country', name: 'country', required: true, ng: { model: 'enterprise.country', options: 'c as c.name for c in countries' } }
%span.error{ ng: { show: "details.country.$error.required && submitted" } }
Please select a country
/ .small-12.medium-12.large-5.hide-for-small-only
/ %h6
/ Location display
/ %i.ofn-i_013-help.has-tip{ 'data-tooltip' => true, title: "Choose how you want to display your enterprise's address on the Open Food Network. By default, full location is shown everywhere including street name and number."}
/ .row
/ .small-12.columns
/ %label.indent-checkbox
/ %input{ type: 'checkbox', id: 'enterpise_suburb_only', ng: { model: 'enterprise.suburb_only' } }
/ Hide my street name and street number from the public (ie. only show the suburb)
/ .small-12.columns
/ %label.indent-checkbox
/ %input{ type: 'checkbox', id: 'enterprise_on_map', ng: { model: 'enterprise.on_map' } }
/ Blur my location on the map (show an approximate, not exact pin)
.row.buttons
.small-12.columns
%hr
%input.button.primary.right{ type: "submit", value: "Continue" }

View File

@@ -1,18 +1,24 @@
.container#registration-finished
.header
%h2 Well done!
%h5
You have successfully completed the profile for
%span.brick{"ng-show" => "enterprise.is_distributor"}
{{ enterprise.name }}
%span.turquoise{"ng-show" => "!enterprise.is_distributor" }
{{ enterprise.name }}
.content{ style: 'text-align: center'}
%h3 Why not check it out on the Open Food Network?
%a.button.primary{ type: "button", href: "/map" } Go to Map Page >
.row
.small-12.columns.pad-top
%header
%h2 Finished!
.panel.callout
%p
Thanks for filling out the details for
%span{ ng: { class: "{brick: !enterprise.is_primary_producer, turquoise: enterprise.is_primary_producer}" } }
{{ enterprise.name }}
%p You can change or update your enterprise at any stage by logging into Open Food Network and going to Admin.
.row
.small-12.columns.text-center
%h4
Activate
%span{ ng: { class: "{brick: !enterprise.is_primary_producer, turquoise: enterprise.is_primary_producer}" } }
{{ enterprise.name }}
%br
%br
%p
We've sent a confirmation email to
%strong {{ enterprise.email }}.
%br Please follow the instructions there to make your enterprise visible on the Open Food Network.
%h3 Next step - add some products:
%a.button.primary{ type: "button", href: "/admin/products/new" } Add a Product >
%a.button.primary{ type: "button", href: "/" } Open Food Network home >

View File

@@ -1,20 +1,22 @@
.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
.small-12.columns
%header
%h2 Thanks!
%h5 Let's upload some pretty pictures so your profile looks great! :)
%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.pad-top{ ng: { if: "imageStep == 'logo'" } }
.small-12.columns
%input.button.primary{ type: "button", value: "Back", ng: { click: "select('about')" } }
%input.button.secondary{ type: "button", value: "Back", ng: { click: "select('about')" } }
 
%input.button.primary{ type: "button", value: "Continue", ng: { click: "imageSelect('promo')" } }
%input.button.primary.right{ 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" }
%input.button.secondary{ type: "button", value: "Back", ng: { click: "imageSelect('logo')" } }
%input.button.primary.right{ type: "submit", value: "Continue" }

View File

@@ -36,6 +36,10 @@
.row.pad-top
.small-12.columns.center
#image-placeholder.logo
%img{ ng: { show: "imageSrc()", src: '{{ imageSrc() }}' } }
.message{ ng: { hide: "imageSrc()" } }
%img{ ng: { show: "imageSrc() && !imageUploader.isUploading", src: '{{ imageSrc() }}' } }
.message{ ng: { hide: "imageSrc() || imageUploader.isUploading" } }
Your logo will appear here for review once uploaded
.loading{ ng: { hide: "!imageUploader.isUploading" } }
%img.spinner{ src: "/assets/loading.gif" }
%br/
Uploading...

View File

@@ -34,6 +34,10 @@
.row.pad-top
.small-12.columns.center
#image-placeholder.promo
%img{ ng: { show: "imageSrc()", src: '{{ imageSrc() }}' } }
.message{ ng: { hide: "imageSrc()" } }
%img{ ng: { show: "imageSrc() && !imageUploader.isUploading", src: '{{ imageSrc() }}' } }
.message{ ng: { hide: "imageSrc() || imageUploader.isUploading" } }
Your logo will appear here for review once uploaded
.loading{ ng: { hide: "!imageUploader.isUploading" } }
%img.spinner{ src: "/assets/loading.gif" }
%br/
Uploading...

View File

@@ -1,39 +1,45 @@
%div
.header
%h2 Hi there!
%h4 This wizard will step you through creating a profile
.row
.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,
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
Your enterprise address and contact details
%li
Your logo image
%li
A pretty picture for your profile header
%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
%i.ofn-i_020-search
A searchable listing
%li
%i.ofn-i_040-hub
A pin on the OFN map
.row
.small-12.columns
.row
.small-12.columns
%header
%h2 Hi there!
%h4
%small
%i.ofn-i_040-hub
Create your enterprise profile
.hide-for-large-up
%hr
%input.button.primary{ type: "button", value: "Let's get started!", ng: { click: "select('details')" } }
%input.button.small.primary{ type: "button", value: "Let's get started!", ng: { click: "select('details')" } }
%hr
.row{ 'data-equalizer' => true }
.small-12.medium-12.large-6.columns.pad-top{ 'data-equalizer-watch' => true }
%h5 You'll need:
%ul.check-list
%li
5-10 minutes
%li
Enterprise address
%li
Primary contact details
%li
Your logo image
%li
Landscape image for your profile
%li
'About Us' text
.small-9.medium-8.large-5.columns.pad-top.end{ 'data-equalizer-watch' => true}
%h5
What do I get?
%p
Your profile helps people
%strong find
and
%strong contact
you on the Open Food Network.
%p Use this space to tell the story of your enterprise, to help drive connections to your social and online presence.
.row.show-for-large-up
.small-12.columns
%hr
%input.button.primary.right{ type: "button", value: "Let's get started!", ng: { click: "select('details')" } }

View File

@@ -1,15 +1,16 @@
%div
.header.center
%h2 Oh no!
%h4 You have reached the limit!
.row
.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
You have reached the limit for the number of enterprises you are allowed to own on the
%strong Open Food Network.
.row
.small-12.columns
%hr
%input.button.primary{ type: "button", value: "Return to the homepage", ng: { click: "close()" } }
.row
.small-12.columns
%header
%h2 Oh no!
%h4 You have reached the limit!
.row
.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
You have reached the limit for the number of enterprises you are allowed to own on the
%strong Open Food Network.
.row
.small-12.columns
%hr
%input.button.primary{ type: "button", value: "Return to the homepage", ng: { click: "close()" } }

View File

@@ -1,35 +1,49 @@
.container#registration-social
.header
%h2 Last step!
%h5 How can people find {{ enterprise.name }} online?
%ng-include{ src: "'registration/steps.html'" }
.row
.small-12.columns
%header
%h2 Final step!
%h5
How can people find
%span{ ng: { class: "{brick: !enterprise.is_primary_producer, turquoise: enterprise.is_primary_producer}" } }
{{ enterprise.name }}
online?
%form{ name: 'social', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "update('finished',social)" } }
.row.content
.small-12.large-7.columns
.row
.small-12.columns
%label{ for: 'enterprise_website' } Website:
%input.chunky.small-12.columns{ id: 'enterprise_website', placeholder: "eg. openfoodnetwork.org.au", ng: { model: 'enterprise.website' } }
.field
%label{ for: 'enterprise_website' } Website:
%input.chunky{ id: 'enterprise_website', placeholder: "eg. openfoodnetwork.org.au", ng: { model: 'enterprise.website' } }
.row
.small-12.columns
%label{ for: 'enterprise_facebook' } Facebook:
%input.chunky.small-12.columns{ id: 'enterprise_facebook', placeholder: "eg. www.facebook.com/PageNameHere", ng: { model: 'enterprise.facebook' } }
.field
%label{ for: 'enterprise_facebook' } Facebook:
%input.chunky{ id: 'enterprise_facebook', placeholder: "eg. www.facebook.com/PageNameHere", ng: { model: 'enterprise.facebook' } }
.row
.small-12.columns
%label{ for: 'enterprise_linkedin' } LinkedIn:
%input.chunky.small-12.columns{ id: 'enterprise_linkedin', placeholder: "eg. www.linkedin.com/YourNameHere", ng: { model: 'enterprise.linkedin' } }
.field
%label{ for: 'enterprise_linkedin' } LinkedIn:
%input.chunky{ id: 'enterprise_linkedin', placeholder: "eg. www.linkedin.com/YourNameHere", ng: { model: 'enterprise.linkedin' } }
.small-12.large-5.columns
.row
.small-12.columns
%label{ for: 'enterprise_twitter' } Twitter:
%input.chunky.small-12.columns{ id: 'enterprise_twitter', placeholder: "eg. @twitter_handle", ng: { model: 'enterprise.twitter' } }
.field
%label{ for: 'enterprise_twitter' } Twitter:
%input.chunky{ id: 'enterprise_twitter', placeholder: "eg. @twitter_handle", ng: { model: 'enterprise.twitter' } }
.row
.small-12.columns
%label{ for: 'enterprise_instagram' } Instagram:
%input.chunky.small-12.columns{ id: 'enterprise_instagram', placeholder: "eg. @instagram_handle", ng: { model: 'enterprise.instagram' } }
.field
%label{ for: 'enterprise_instagram' } Instagram:
%input.chunky{ id: 'enterprise_instagram', placeholder: "eg. @instagram_handle", ng: { model: 'enterprise.instagram' } }
.row.buttons
.small-12.columns
%input.button.secondary{ type: "button", value: "Back", ng: { click: "select('images')" } }
 
%input.button.primary{ type: "submit", value: "Continue" }
%input.button.primary.right{ type: "submit", value: "Continue" }

View File

@@ -1,5 +1,3 @@
.row#progress-bar
.small-12.medium-2.columns.item{ ng: { repeat: 'step in steps', class: "{active: (currentStep() == step),'show-for-medium-up': (currentStep() != step)}" } }
{{ $index+1 + ". " + step }}

View File

@@ -0,0 +1,46 @@
.container#registration-type{bindonce: true}
%ng-include{ src: "'registration/steps.html'" }
.row
.small-12.columns
%header
%h2
Last step to add
%span{ ng: { class: "{brick: !enterprise.is_primary_producer, turquoise: enterprise.is_primary_producer}" } }
{{ enterprise.name }}!
%h4
Are you a producer?
%form{ name: 'type', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "create(type)" } }
.row#enterprise-types{ 'data-equalizer' => true, bo: { if: "enterprise.type != 'own'" } }
.small-12.columns.field
.row
.small-12.medium-6.large-6.columns{ 'data-equalizer-watch' => true }
%a.btnpanel#producer-panel{ href: "#", ng: { click: "enterprise.is_primary_producer = true", class: "{selected: enterprise.is_primary_producer}" } }
%i.ofn-i_059-producer
%h4 Yes, I'm a producer
.small-12.medium-6.large-6.columns{ 'data-equalizer-watch' => true }
%a.btnpanel#hub-panel{ href: "#", ng: { click: "enterprise.is_primary_producer = false", class: "{selected: enterprise.is_primary_producer == false}" } }
%i.ofn-i_063-hub
%h4 No, I'm not a producer
.row
.small-12.columns
%input.chunky{ id: 'enterprise_is_primary_producer', name: 'is_primary_producer', hidden: true, required: true, ng: { model: 'enterprise.is_primary_producer' } }
%span.error{ ng: { show: "type.is_primary_producer.$error.required && submitted" } }
Please choose one. Are you are producer?
.row
.small-12.columns
.panel.callout
.left
%i.ofn-i_013-help
 
%p Producers make yummy things to eat &/or drink. You're a producer if you grow it, raise it, brew it, bake it, ferment it, milk it or mould it.
/ %p Hubs connect the producer to the eater. Hubs can be co-ops, independent retailers, buying groups, wholesalers, CSA box schemes, farm-gate stalls, etc.
.row.buttons
.small-12.columns
%input.button.secondary{ type: "button", value: "Back", ng: { click: "select('contact')" } }
%input.button.primary.right{ type: "submit", value: "Continue" }

View File

@@ -0,0 +1,15 @@
.alert
border: 3px solid #919191
border-radius: 6px
margin-bottom: 20px
color: #919191
padding: 5px 10px
h6
color: #919191
.message
font-weight: bold
&:hover
border-color: #DA5354
color: #DA5354
h6
color: #DA5354

View File

@@ -2,44 +2,25 @@
@import mixins
#registration-modal
.header
header
text-align: center
background-color: #efefef
padding-bottom: 1rem
// background-color: #efefef
@media all and (max-width: 64em)
text-align: left
.container
background-color: #ffffff
.content
// margin-bottom: 15px
i
font-size: 150%
.buttons
ofn-inline-flash
display: block
padding: 15px
position: relative
margin-bottom: 10px
&.brick
background-color: $clr-brick-light
border: 2px solid $clr-brick
color: $clr-brick
&.turquoise
background-color: $clr-turquoise-light
border: 2px solid $clr-turquoise
color: $clr-turquoise
.close-button
position: absolute
top: 0px
right: 0px
.field
margin-bottom: 15px
margin-bottom: 1em
input.chunky
.chunky
padding: 8px
font-size: 105%
font-size: 1rem
margin: 0
width: 100%
label.indent-checkbox
display: block
@@ -51,9 +32,9 @@
label
margin-bottom: 3px
ol, ul
// font-size: 80%
ol, ul, p
font-size: 0.875rem
ol, ul
padding: 0
margin: 0
ol
@@ -62,22 +43,24 @@
.highlight-box
background: white
padding: 1rem 1.2rem
@media all and (max-width: 640px)
@media all and (max-width: 64em)
margin-top: 1rem
#progress-bar
margin-bottom: 15px
.item
padding: 12px 0px
font-size: 0.75rem
padding: 10px 0px
text-transform: uppercase
text-align: center
background-color: #333
border: 2px solid #333
background-color: $clr-blue
border: 2px solid $clr-blue
color: #fff
.item.active
background-color: #cccccc
border: 2px solid #333
color: #333
background-color: $disabled-light
border: 2px solid $clr-blue
color: $clr-blue
font-weight: 700
@include box-shadow(inset 0 0 1px 0 #fff)
@@ -110,39 +93,57 @@
font-size: 18px
font-weight: bold
color: #373737
background-color: #e1e1e1
background-color: #f1f1f1
text-align: center
border: 3px dashed #494949
margin-left: auto
margin-right: auto
.spinner
width: 100px
&.logo
.message
padding-top: 6em
.loading
padding-top: 4em
width: 306px
height: 306px
&.promo
.message
padding-top: 4em
.loading
padding-top: 1em
width: 726px
height: 166px
#registration-details
#registration-type
#enterprise-types
a.panel
a.btnpanel
display: block
padding: 1rem
margin-bottom: 1rem
background-color: #efefef
color: black
@media all and (min-width: 768px)
min-height: 200px
text-align: center
border: 1px solid transparent
i
font-size: 3rem
h4
margin-top: 1rem
&:hover
background-color: #fff
&#producer-panel:hover
border: 1px solid $clr-turquoise
&, & *
color: $clr-turquoise
&#hub-panel:hover, &#both-panel:hover
border: 1px solid $clr-brick
&, & *
color: $clr-brick
&.selected
&, & *
color: #fff

View File

@@ -0,0 +1,7 @@
Devise::ConfirmationsController.class_eval do
protected
# Override of devise method in Devise::ConfirmationsController
def after_confirmation_path_for(resource_name, resource)
spree.admin_path
end
end

View File

@@ -2,17 +2,12 @@ require 'open_food_network/spree_api_key_loader'
class RegistrationController < BaseController
include OpenFoodNetwork::SpreeApiKeyLoader
before_filter :load_spree_api_key, only: [:index, :store]
before_filter :load_spree_api_key, only: [:index]
before_filter :check_user, except: :authenticate
layout 'registration'
def index
@enterprise_attributes = { type: 'profile' }
end
def store
@enterprise_attributes = { is_distributor: true, is_primary_producer: true, type: 'single' }
render :index
@enterprise_attributes = { sells: 'none' }
end
private

View File

@@ -0,0 +1,11 @@
Spree::Admin::ImageSettingsController.class_eval do
# Spree stores attachent definitions in JSON. This converts the style name and format to
# strings. However, when paperclip encounters these, it doesn't recognise the format.
# Here we solve that problem by converting format and style name to symbols.
def update_paperclip_settings_with_format_styles
update_paperclip_settings_without_format_styles
Spree::Image.reformat_styles
end
alias_method_chain :update_paperclip_settings, :format_styles
end

View File

@@ -0,0 +1,21 @@
module Admin
module ImageSettingsHelper
def admin_image_settings_format_options
[['Unchanged', ''], ['PNG', 'png'], ['JPEG', 'jpg']]
end
def admin_image_settings_geometry_from_style(style)
geometry, format = admin_image_settings_split_style style
geometry
end
def admin_image_settings_format_from_style(style)
geometry, format = admin_image_settings_split_style style
format
end
def admin_image_settings_split_style(style)
[style, nil].flatten[0..1]
end
end
end

View File

@@ -1,8 +1,16 @@
require 'devise/mailers/helpers'
class EnterpriseMailer < Spree::BaseMailer
def creation_confirmation(enterprise)
find_enterprise(enterprise)
subject = "#{@enterprise.name} is now on #{Spree::Config[:site_name]}"
mail(:to => @enterprise.owner.email, :from => from_address, :subject => subject)
include Devise::Mailers::Helpers
def confirmation_instructions(record, token, opts={})
@token = token
find_enterprise(record)
opts = {
subject: "Please confirm your email for #{@enterprise.name}",
to: [ @enterprise.owner.email, @enterprise.email ].uniq,
from: from_address,
}
devise_mail(record, :confirmation_instructions, opts)
end
private

View File

@@ -1,5 +1,5 @@
Spree::UserMailer.class_eval do
def signup_confirmation(user)
@user = user
mail(:to => user.email, :from => from_address,

View File

@@ -2,11 +2,13 @@ class Enterprise < ActiveRecord::Base
SELLS = %w(none own any)
ENTERPRISE_SEARCH_RADIUS = 100
devise :confirmable, reconfirmable: true
self.inheritance_column = nil
acts_as_gmappable :process_geocoding => false
after_create :send_creation_email
before_create :check_email
has_and_belongs_to_many :groups, class_name: 'EnterpriseGroup'
has_many :producer_properties, foreign_key: 'producer_id'
@@ -34,7 +36,7 @@ class Enterprise < ActiveRecord::Base
path: 'public/images/enterprises/logos/:id/:style/:basename.:extension'
has_attached_file :promo_image,
styles: { large: "1200x260#", medium: "720x156#", thumb: "100x100>" },
styles: { large: ["1200x260#", :jpg], medium: ["720x156#", :jpg], thumb: ["100x100>", :jpg] },
url: '/images/enterprises/promo_images/:id/:style/:basename.:extension',
path: 'public/images/enterprises/promo_images/:id/:style/:basename.:extension'
@@ -59,6 +61,8 @@ class Enterprise < ActiveRecord::Base
scope :by_name, order('name')
scope :visible, where(:visible => true)
scope :confirmed, where('confirmed_at IS NOT NULL')
scope :unconfirmed, where('confirmed_at IS NULL')
scope :is_primary_producer, where(:is_primary_producer => true)
scope :is_distributor, where('sells != ?', 'none')
scope :supplying_variant_in, lambda { |variants| joins(:supplied_products => :variants_including_master).where('spree_variants.id IN (?)', variants).select('DISTINCT enterprises.*') }
@@ -254,10 +258,16 @@ class Enterprise < ActiveRecord::Base
select('DISTINCT spree_taxons.*')
end
protected
def devise_mailer
EnterpriseMailer
end
private
def send_creation_email
EnterpriseMailer.creation_confirmation(self).deliver
def check_email
skip_confirmation! if owner.enterprises.confirmed.map(&:email).include?(email)
end
def strip_url(url)

View File

@@ -15,7 +15,7 @@ class EnterpriseGroup < ActiveRecord::Base
path: 'public/images/enterprise_groups/logos/:id/:style/:basename.:extension'
has_attached_file :promo_image,
styles: {large: "1200x260#"},
styles: {large: ["1200x260#", :jpg]},
url: '/images/enterprise_groups/promo_images/:id/:style/:basename.:extension',
path: 'public/images/enterprise_groups/promo_images/:id/:style/:basename.:extension'

View File

@@ -0,0 +1,23 @@
Spree::Image.class_eval do
# Spree stores attachent definitions in JSON. This converts the style name and format to
# strings. However, when paperclip encounters these, it doesn't recognise the format.
# Here we solve that problem by converting format and style name to symbols.
# See also: ImageSettingsController decorator.
#
# eg. {'mini' => ['48x48>', 'png']} is converted to {mini: ['48x48>', :png]}
def self.format_styles(styles)
styles_a = styles.map do |name, style|
style[1] = style[1].to_sym if style.is_a? Array
[name.to_sym, style]
end
Hash[styles_a]
end
def self.reformat_styles
Spree::Image.attachment_definitions[:attachment][:styles] =
format_styles(Spree::Image.attachment_definitions[:attachment][:styles])
end
reformat_styles
end

View File

@@ -0,0 +1,11 @@
/ replace_contents '#styles_list'
- @styles.each_with_index do |(style_name, style_value), index|
.field.three.columns
= label_tag "attachment_styles[#{style_name}]", style_name
%a.destroy_style.with-tip{:alt => t(:destroy), :href => "#", :title => t(:destroy)}
%i.icon-trash
= text_field_tag "attachment_styles[#{style_name}][]", admin_image_settings_geometry_from_style(style_value), :class => 'fullwidth'
%br/
- current_format = admin_image_settings_format_from_style(style_value) || ''
= select_tag "attachment_styles[#{style_name}][]", options_for_select(admin_image_settings_format_options, current_format), :class => 'fullwidth', :id => "attachment_styles_format_#{style_name}"

View File

@@ -45,6 +45,10 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer
has_one :address, serializer: Api::AddressSerializer
def visible
object.visible && object.confirmed?
end
def pickup
object.shipping_methods.where(:require_ship_address => false).present?
end

View File

@@ -1,3 +1,7 @@
class Api::StateSerializer < ActiveModel::Serializer
attributes :id, :name, :abbr
def abbr
object.abbr.upcase
end
end

View File

@@ -0,0 +1,100 @@
/ ORIGINAL & UGLY:
/ %p= "Welcome #{@resource.contact}!"
/ %p= "Please confirm your email address for #{@resource.name}."
/ %p= "Click the link below to activate your enterprise:"
/ %p= link_to 'Confirm this email address', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token)
%html{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;", :xmlns => "http://www.w3.org/1999/xhtml"}
%head{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
/ If you delete this meta tag, Half Life 3 will never be released.
%meta{:content => "width=device-width", :name => "viewport", :style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}/
%meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type", :style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}/
%title{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"} Open Food Network
%link{:href => "http://rohanmitchell.com/random/template/basic-email-template/stylesheets/email.css", :rel => "stylesheet", :style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;", :type => "text/css"}/
%body{:bgcolor => "#FFFFFF", :style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-webkit-text-size-adjust: none;height: 100%;width: 100%!important;"}
/ HEADER
%table.head-wrap{:bgcolor => "#333333", :style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;width: 100%;"}
%tr{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
%td{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
%td.header.container{:style => "margin: 0 auto!important;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;display: block!important;max-width: 600px!important;clear: both!important;"}
.content{:style => "margin: 0 auto;padding: 15px;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;max-width: 600px;display: block;"}
%table{:bgcolor => "#333333", :style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;width: 100%;"}
%tr{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
%td{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
%img{:src => "https://openfoodnetwork.org.au/assets/ofn_logo_beta-8e4dfc79deb25def2d107dea52dce492.png", :style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;max-width: 100%;", :width => "200"}/
%td{:align => "right", :style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
%h6.collapse{:style => "margin: 0!important;padding: 0;font-family: \"HelveticaNeue-Light\", \"Helvetica Neue Light\", \"Helvetica Neue\", Helvetica, Arial, \"Lucida Grande\", sans-serif;line-height: 1.1;margin-bottom: 15px;color: #999;font-weight: 900;font-size: 14px;text-transform: uppercase;"} Open Food Network
%td{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
/ /HEADER
/ BODY
%table.body-wrap{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;width: 100%;"}
%tr{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
%td{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
%td.container{:bgcolor => "#FFFFFF", :style => "margin: 0 auto!important;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;display: block!important;max-width: 600px!important;clear: both!important;"}
.content{:style => "margin: 0 auto;padding: 15px;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;max-width: 600px;display: block;"}
%table{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;width: 100%;"}
%tr{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
%td{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
%h3{:style => "margin: 0;padding: 0;font-family: \"HelveticaNeue-Light\", \"Helvetica Neue Light\", \"Helvetica Neue\", Helvetica, Arial, \"Lucida Grande\", sans-serif;line-height: 1.1;margin-bottom: 15px;color: #000;font-weight: 500;font-size: 27px;"}= "Welcome, #{@resource.contact}!"
%p.lead{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;margin-bottom: 10px;font-weight: normal;font-size: 17px;line-height: 1.6;"}
= "Please confirm email address for your enterprise "
%strong
= "#{@resource.name}."
%p &nbsp;
/ Callout Panel
%p.callout{:style => "margin: 0; padding: 15px;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;margin-bottom: 15px;font-weight: normal;font-size: 14px;line-height: 1.6;background-color: #e1f0f5;"}
= "Click the link below to confirm email and to activate your enterprise. This link can be used only once:"
%br
%strong
= link_to 'Confirm this email address »', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token)
/ /Callout Panel
%p &nbsp;
%p{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;margin-bottom: 10px;font-weight: normal;font-size: 14px;line-height: 1.6;"}= "We're so excited that you're joining the Open Food Network! Don't hestitate to get in touch if you have any questions."
%p &nbsp;
/ social & contact
%table.social{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;background-color: #ebebeb;width: 100%;", :width => "100%"}
%tr{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
%td{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
/ column 1
%table.column{:align => "left", :style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;width: 280px;float: left;min-width: 279px;"}
%tr{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
%td{:style => "margin: 0;padding: 15px;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
%h5{:style => "margin: 0;padding: 0;font-family: \"HelveticaNeue-Light\", \"Helvetica Neue Light\", \"Helvetica Neue\", Helvetica, Arial, \"Lucida Grande\", sans-serif;line-height: 1.1;margin-bottom: 15px;color: #000;font-weight: 900;font-size: 17px;"} Connect with Us:
%p{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;margin-bottom: 10px;font-weight: normal;font-size: 14px;line-height: 1.6;"}
%a.soc-btn.fb{:href => "https://www.facebook.com/OpenFoodNet", :style => "margin: 0;padding: 3px 7px;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;color: #FFF;font-size: 12px;margin-bottom: 10px;text-decoration: none;font-weight: bold;display: block;text-align: center;background-color: #3B5998!important;", :target => "_blank"} Facebook
%a.soc-btn.tw{:href => "https://twitter.com/OpenFoodNet", :style => "margin: 0;padding: 3px 7px;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;color: #FFF;font-size: 12px;margin-bottom: 10px;text-decoration: none;font-weight: bold;display: block;text-align: center;background-color: #1daced!important;", :target => "_blank"} Twitter
%a.soc-btn.li{:href => "http://www.linkedin.com/groups/Open-Food-Foundation-4743336", :style => "margin: 0;padding: 3px 7px;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;color: #FFF;font-size: 12px;margin-bottom: 10px;text-decoration: none;font-weight: bold;display: block;text-align: center;background-color: #0073b2!important;", :target => "_blank"} LinkedIn
/ /column 1
/ column 2
%table.column{:align => "left", :style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;width: 280px;float: left;min-width: 279px;"}
%tr{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
%td{:style => "margin: 0;padding: 15px;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
%h5{:style => "margin: 0;padding: 0;font-family: \"HelveticaNeue-Light\", \"Helvetica Neue Light\", \"Helvetica Neue\", Helvetica, Arial, \"Lucida Grande\", sans-serif;line-height: 1.1;margin-bottom: 15px;color: #000;font-weight: 900;font-size: 17px;"} Email us:
%p{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;margin-bottom: 10px;font-weight: normal;font-size: 14px;line-height: 1.6;"}
%strong{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
%a{:href => "hello@openfoodnetwork.org", :style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;color: #0096ad;"} hello@openfoodnetwork.org
/ /column 2
%span.clear{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;display: block;clear: both;"}
/ /social & contact
/ /content
%td{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
/ /BODY
/ FOOTER
%table.footer-wrap{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;width: 100%;clear: both!important;"}
%tr{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
%td{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
%td.container{:style => "margin: 0 auto!important;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;display: block!important;max-width: 600px!important;clear: both!important;"}
/ content
.content{:style => "margin: 0 auto;padding: 15px;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;max-width: 600px;display: block;"}
%table{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;width: 100%;"}
%tr{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
%td{:align => "center", :style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
%p{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;margin-bottom: 10px;font-weight: normal;font-size: 14px;line-height: 1.6;"}
%a{:href => "https://openfoodnetwork.org.au/Terms-of-service.pdf", :style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;color: #0096ad;", :target => "_blank"} Terms of service
|
%a{:href => "http://www.openfoodnetwork.org.au", :style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;color: #0096ad;", :target => "_blank"} Open Food Network
/ | <a href="#"><unsubscribe>Unsubscribe</unsubscribe></a>
/ /content
%td{:style => "margin: 0;padding: 0;font-family: \"Helvetica Neue\", \"Helvetica\", Helvetica, Arial, sans-serif;"}
/ /FOOTER

View File

@@ -1,9 +0,0 @@
%h1
= @enterprise.name + " has been created"
%h3
Why not check it out on
%a{ href: "#{map_url}" }
= Spree::Config[:site_name] + "?"
If you have any questions, please get in touch with us at: hello@openfoodnetwork.org

View File

@@ -0,0 +1,4 @@
- @enterprises.unconfirmed.each do |enterprise|
.alert
%h6= "Action Required: Please confirm the email address for #{enterprise.name}."
%span.message= "We've sent a confirmation email to #{enterprise.email}, so please check there for further instructions. Thanks!"

View File

@@ -1,10 +1,17 @@
%h1{ :style => 'margin-bottom: 30px'} Dashboard
- if @enterprises.unconfirmed.any?
= render partial: "spree/admin/overview/unconfirmed"
%hr
- if @enterprises.empty?
= render partial: "spree/admin/overview/enterprises"
- else
- if can? :admin, Spree::Product
= render partial: "spree/admin/overview/products"

View File

@@ -0,0 +1,5 @@
Devise.setup do |config|
# Add a default scope to devise, to prevent it from checking
# whether other devise enabled models are signed into a session or not
config.default_scope = :spree_user
end

View File

@@ -27,9 +27,16 @@ module.exports = function(config) {
'app/assets/javascripts/admin/util.js.erb'
],
preprocessors: {
'**/*.coffee': ['coffee']
},
coffeePreprocessor: {
options: {
sourceMap: true
},
transformPath: function(path) {
return path.replace(/\.coffee$/, '.js');
}
},

View File

@@ -6,7 +6,6 @@ Openfoodnetwork::Application.routes.draw do
get "/map", to: "map#index", as: :map
get "/register", to: "registration#index", as: :registration
get "/register/store", to: "registration#store", as: :store_registration
get "/register/auth", to: "registration#authenticate", as: :registration_auth
resource :shop, controller: "shop" do
@@ -35,6 +34,8 @@ Openfoodnetwork::Application.routes.draw do
end
end
devise_for :enterprise
namespace :admin do
resources :order_cycles do
post :bulk_update, on: :collection, as: :bulk_update

View File

@@ -1,9 +1,15 @@
class EnterpriseConfigRefactor < ActiveRecord::Migration
class Enterprise < ActiveRecord::Base
self.inheritance_column = nil
end
def up
add_column :enterprises, :sells, :string, null: false, default: 'none'
add_index :enterprises, :sells
add_index :enterprises, [:is_primary_producer, :sells]
Enterprise.reset_column_information
Enterprise.all.each do |enterprise|
enterprise.update_attributes!({:sells => sells_what?(enterprise)})
end
@@ -17,6 +23,8 @@ class EnterpriseConfigRefactor < ActiveRecord::Migration
add_column :enterprises, :type, :string, null: false, default: 'profile'
add_column :enterprises, :is_distributor, :boolean
Enterprise.reset_column_information
Enterprise.all.each do |enterprise|
enterprise.update_attributes!({
:type => type?(enterprise),

View File

@@ -0,0 +1,16 @@
class AddConfirmableToEnterprise < ActiveRecord::Migration
def up
add_column :enterprises, :confirmation_token, :string
add_column :enterprises, :confirmed_at, :datetime
add_column :enterprises, :confirmation_sent_at, :datetime
add_column :enterprises, :unconfirmed_email, :string
add_index :enterprises, :confirmation_token, :unique => true
# Existing enterprises are assumed to be confirmed
Enterprise.update_all(:confirmed_at => Time.now)
end
def down
remove_columns :enterprises, :confirmation_token, :confirmed_at, :confirmation_sent_at, :unconfirmed_email
end
end

View File

@@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20140927005043) do
ActiveRecord::Schema.define(:version => 20141010043405) do
create_table "adjustment_metadata", :force => true do |t|
t.integer "adjustment_id"
@@ -264,10 +264,15 @@ ActiveRecord::Schema.define(:version => 20140927005043) do
t.string "instagram"
t.string "linkedin"
t.integer "owner_id", :null => false
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.string "sells", :default => "none", :null => false
end
add_index "enterprises", ["address_id"], :name => "index_enterprises_on_address_id"
add_index "enterprises", ["confirmation_token"], :name => "index_enterprises_on_confirmation_token", :unique => true
add_index "enterprises", ["is_primary_producer", "sells"], :name => "index_enterprises_on_is_primary_producer_and_sells"
add_index "enterprises", ["owner_id"], :name => "index_enterprises_on_owner_id"
add_index "enterprises", ["sells"], :name => "index_enterprises_on_sells"

View File

@@ -0,0 +1,15 @@
require 'spec_helper'
describe Devise::ConfirmationsController do
context "after confirmation" do
before do
e = create(:enterprise, confirmed_at: nil)
@request.env["devise.mapping"] = Devise.mappings[:enterprise]
spree_get :show, confirmation_token: e.confirmation_token
end
it "should redirect to admin root" do
expect(response).to redirect_to spree.admin_path
end
end
end

View File

@@ -7,11 +7,6 @@ describe RegistrationController do
get :index
response.should redirect_to registration_auth_path(anchor: "signup?after_login=/register")
end
it "store" do
get :store
response.should redirect_to registration_auth_path(anchor: "signup?after_login=/register/store")
end
end
describe "redirecting when user has reached enterprise ownership limit" do
@@ -41,12 +36,5 @@ describe RegistrationController do
expect(assigns(:spree_api_key)).to eq user.spree_api_key
end
end
describe "store" do
it "loads the spree api key" do
get :store
expect(assigns(:spree_api_key)).to eq user.spree_api_key
end
end
end
end

View File

@@ -97,6 +97,7 @@ FactoryGirl.define do
long_description '<p>Hello, world!</p><p>This is a paragraph.</p>'
email 'enterprise@example.com'
address { FactoryGirl.create(:address) }
confirmed_at { Time.now }
end
factory :supplier_enterprise, :parent => :enterprise do

View File

@@ -0,0 +1,43 @@
require 'spec_helper'
feature %q{
As an admin
I want to manage image formats
} do
include AuthenticationWorkflow
include WebHelper
before(:all) do
styles = {"mini" => "48x48>",
"small" => "100x100>",
"product" => "240x240>",
"large" => "600x600>"}
Spree::Config[:attachment_styles] = ActiveSupport::JSON.encode(styles)
Spree::Image.attachment_definitions[:attachment][:styles] = ActiveSupport::JSON.decode(Spree::Config[:attachment_styles])
Spree::Image.reformat_styles
end
scenario "setting the image format for a paperclip style" do
# When I go to the image settings page
login_to_admin_section
visit spree.edit_admin_image_settings_path
# All the styles should default to "Unchanged"
page.should have_select 'attachment_styles_format_mini', selected: 'Unchanged'
page.should have_select 'attachment_styles_format_small', selected: 'Unchanged'
page.should have_select 'attachment_styles_format_product', selected: 'Unchanged'
page.should have_select 'attachment_styles_format_large', selected: 'Unchanged'
# When I change a style to "PNG" and save
select 'PNG', from: 'attachment_styles_format_mini'
click_button 'Update'
# Then the change should be saved to the image formats
page.should have_content "Image Settings successfully updated."
page.should have_select 'attachment_styles_format_mini', selected: 'PNG'
styles = Spree::Image.attachment_definitions[:attachment][:styles]
styles[:mini].should == ['48x48>', :png]
end
end

View File

@@ -1,4 +1,4 @@
require "spec_helper"
require 'spec_helper'
feature %q{
As an admin

View File

@@ -3,14 +3,14 @@ require 'spec_helper'
feature %q{
As a consumer
I want to see a list of producers
So that I can shop at hubs distributing their products
So that I can shop at hubs distributing their products
}, js: true do
include UIComponentHelper
let!(:producer) { create(:supplier_enterprise) }
let!(:invisible_producer) { create(:supplier_enterprise, visible: false) }
let(:taxon) { create(:taxon) }
let!(:product) { create(:simple_product, supplier: producer, taxons: [taxon]) }
before do
visit producers_path
end
@@ -20,7 +20,7 @@ feature %q{
expand_active_table_node producer.name
page.should have_content producer.supplied_taxons.first.name.split.map(&:capitalize).join(' ')
end
it "doesn't show invisible producers" do
page.should_not have_content invisible_producer.name
end

View File

@@ -3,8 +3,7 @@ require 'spec_helper'
feature "Registration", js: true do
include WebHelper
# TODO fix this after removal of is_distributor.
pending "Registering a Profile" do
describe "Registering a Profile" do
let(:user) { create(:user, password: "password", password_confirmation: "password") }
it "Allows a logged in user to register a profile" do
@@ -18,25 +17,22 @@ feature "Registration", js: true do
# Enter Login details
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_login_and_ensure_content "This wizard will step you through creating a profile"
click_login_and_ensure_content "Hi there!"
expect(URI.parse(current_url).path).to eq registration_path
# Done reading introduction
click_button_and_ensure_content "Let's get started!", "Woot! First we need to know what sort of enterprise you are:"
click_button_and_ensure_content "Let's get started!", "Woot! First we need to know a little bit about your enterprise:"
# Filling in details
fill_in 'enterprise_name', with: "My Awesome Enterprise"
click_link 'both-panel'
click_button_and_ensure_content "Continue", "Greetings My Awesome Enterprise"
# Filling in address
fill_in 'enterprise_address', with: '123 Abc Street'
fill_in 'enterprise_city', with: 'Northcote'
fill_in 'enterprise_zipcode', with: '3070'
select 'Australia', from: 'enterprise_country'
select 'Vic', from: 'enterprise_state'
select 'VIC', from: 'enterprise_state'
click_button 'Continue'
# Filling in Contact Details
@@ -46,6 +42,11 @@ feature "Registration", js: true do
fill_in 'enterprise_phone', with: '12 3456 7890'
click_button 'Continue'
# Choosing a type
expect(page).to have_content 'Last step to add My Awesome Enterprise!'
click_link 'producer-panel'
click_button 'Continue'
# Enterprise should be created
expect(page).to have_content 'Nice one!'
e = Enterprise.find_by_name('My Awesome Enterprise')
@@ -76,7 +77,7 @@ feature "Registration", js: true do
click_button 'Continue'
# Filling in social
expect(page).to have_content 'Last step!'
expect(page).to have_content 'How can people find My Awesome Enterprise online?'
fill_in 'enterprise_website', with: 'www.shop.com'
fill_in 'enterprise_facebook', with: 'FaCeBoOk'
fill_in 'enterprise_linkedin', with: 'LiNkEdIn'
@@ -85,7 +86,7 @@ feature "Registration", js: true do
click_button 'Continue'
# Done
expect(page).to have_content "You have successfully completed the profile for My Awesome Enterprise"
expect(page).to have_content "Finished!"
e.reload
expect(e.website).to eq "www.shop.com"
expect(e.facebook).to eq "FaCeBoOk"
@@ -93,31 +94,6 @@ feature "Registration", js: true do
expect(e.twitter).to eq "@TwItTeR"
expect(e.instagram).to eq "@InStAgRaM"
end
it "Allows a logged in user to register a store" do
visit store_registration_path
expect(URI.parse(current_url).path).to eq registration_auth_path
page.has_selector? "dd", text: "Log in"
switch_to_login_tab
# Enter Login details
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_login_and_ensure_content "This wizard will step you through creating a profile"
expect(URI.parse(current_url).path).to eq store_registration_path
# Done reading introduction
click_button_and_ensure_content "Let's get started!", "Woot! First we need to know the name of your farm:"
# Details Page
expect(page).to have_content "Woot! First we need to know the name of your farm:"
expect(page).to_not have_selector '#enterprise-types'
# Everything from here should be covered in 'profile' spec
end
end
def switch_to_login_tab

View File

@@ -1,13 +1,16 @@
require 'spec_helper'
describe EnterpriseMailer do
let!(:enterprise) { create(:enterprise) }
before do
@enterprise = create(:enterprise)
ActionMailer::Base.deliveries = []
end
it "should send an email when given an enterprise" do
EnterpriseMailer.creation_confirmation(@enterprise).deliver
it "should send an email confirmation when given an enterprise" do
EnterpriseMailer.confirmation_instructions(enterprise, 'token').deliver
ActionMailer::Base.deliveries.count.should == 1
mail = ActionMailer::Base.deliveries.first
expect(mail.subject).to eq "Please confirm your email for #{enterprise.name}"
end
end

View File

@@ -3,6 +3,25 @@ require 'spec_helper'
describe Enterprise do
include AuthenticationWorkflow
describe "sending emails" do
describe "on creation" do
let!(:user) { create_enterprise_user( enterprise_limit: 2 ) }
let!(:enterprise) { create(:enterprise, owner: user) }
it "when the email address has not already been confirmed" do
mail_message = double "Mail::Message"
EnterpriseMailer.should_receive(:confirmation_instructions).and_return mail_message
mail_message.should_receive :deliver
create(:enterprise, owner: user, email: "unknown@email.com", confirmed_at: nil )
end
it "when the email address has already been confirmed" do
EnterpriseMailer.should_not_receive(:confirmation_instructions)
e = create(:enterprise, owner: user, email: enterprise.email, confirmed_at: nil)
end
end
end
describe "associations" do
it { should belong_to(:owner) }
it { should have_many(:supplied_products) }
@@ -102,6 +121,7 @@ describe Enterprise do
it { should delegate(:city).to(:address) }
it { should delegate(:state_name).to(:address) }
end
describe "scopes" do
describe 'active' do
it 'find active enterprises' do
@@ -111,6 +131,28 @@ describe Enterprise do
end
end
describe "confirmed" do
it "find enterprises with a confirmed date" do
s1 = create(:supplier_enterprise)
d1 = create(:distributor_enterprise)
s2 = create(:supplier_enterprise, confirmed_at: nil)
d2 = create(:distributor_enterprise, confirmed_at: nil)
expect(Enterprise.confirmed).to include s1, d1
expect(Enterprise.confirmed).to_not include s2, d2
end
end
describe "unconfirmed" do
it "find enterprises without a confirmed date" do
s1 = create(:supplier_enterprise)
d1 = create(:distributor_enterprise)
s2 = create(:supplier_enterprise, confirmed_at: nil)
d2 = create(:distributor_enterprise, confirmed_at: nil)
expect(Enterprise.unconfirmed).to_not include s1, d1
expect(Enterprise.unconfirmed).to include s2, d2
end
end
describe "distributors_with_active_order_cycles" do
it "finds active distributors by order cycles" do
s = create(:supplier_enterprise)
@@ -504,8 +546,7 @@ describe Enterprise do
end
describe "provide enterprise category" do
let(:producer_sell_all) { build(:enterprise, is_primary_producer: true, sells: "any") }
let(:producer_sell_all) { build(:enterprise, is_primary_producer: true, sells: "any") }
let(:producer_sell_own) { build(:enterprise, is_primary_producer: true, sells: "own") }
let(:producer_sell_none) { build(:enterprise, is_primary_producer: true, sells: "none") }
let(:non_producer_sell_all) { build(:enterprise, is_primary_producer: false, sells: "any") }
@@ -519,7 +560,7 @@ describe Enterprise do
producer_sell_all.category.should == :producer_hub
producer_sell_own.category.should == :producer_shop
producer_sell_none.category.should == :producer
non_producer_sell_all.category.should == :hub
non_producer_sell_all.category.should == :hub
non_producer_sell_own.category.should == :hub
non_producer_sell_none.category.should == :hub_profile
end

View File

@@ -0,0 +1,18 @@
require 'spec_helper'
module Spree
describe Image do
describe "attachment definitions" do
let(:name_str) { {"mini" => "48x48>"} }
let(:formatted) { {mini: ["48x48>", "png"]} }
it "converts style names to symbols" do
Image.format_styles(name_str).should == {:mini => "48x48>"}
end
it "converts formats to symbols" do
Image.format_styles(formatted).should == {:mini => ["48x48>", :png]}
end
end
end
end

View File

@@ -13,9 +13,27 @@ describe Api::EnterpriseSerializer do
serializer = Api::EnterpriseSerializer.new enterprise
serializer.to_json.should match taxon.id.to_s
end
it "will render urls" do
serializer = Api::EnterpriseSerializer.new enterprise
serializer.to_json.should match "map_005-hub.svg"
end
describe "visibility" do
before do
enterprise.stub(:visible).and_return true
end
it "is visible when confirmed" do
enterprise.stub(:confirmed?).and_return true
serializer = Api::EnterpriseSerializer.new enterprise
expect(serializer.to_json).to match "\"visible\":true"
end
it "is not visible when unconfirmed" do
enterprise.stub(:confirmed?).and_return false
serializer = Api::EnterpriseSerializer.new enterprise
expect(serializer.to_json).to match "\"visible\":false"
end
end
end