Compare commits

...

306 Commits

Author SHA1 Message Date
Maikel Linke
ec36a843cf Merge tag 'v1.8.8' into transifex 2017-04-06 10:31:26 +10:00
Transifex-Openfoodnetwork
e99dbaf4d8 Updating translations for config/locales/es.yml [skip ci] 2017-04-05 19:40:18 +10:00
Transifex-Openfoodnetwork
6defb09d2e Updating translations for config/locales/fr.yml [skip ci] 2017-03-21 09:03:15 +11:00
Transifex-Openfoodnetwork
2774c09d7a Updating translations for config/locales/nb.yml [skip ci] 2017-03-20 07:10:53 +11:00
Matt-Yorkley
c62a044598 PI highlight invalid fields in feedback tables 2017-03-17 16:11:52 +11:00
Matt-Yorkley
f73fbe7f23 SpreadsheetEntry Class and PI refactor 2017-03-17 16:11:52 +11:00
Matt-Yorkley
5e1e4c1d19 Product Import UX review updates
Minor tweaks

Minor fix
2017-03-17 16:11:52 +11:00
Matt-Yorkley
cc5a335fb7 Refactor and additional permissions checks
Don't include non-permitted enterprises in existin product count

Tweaked feedback
2017-03-17 16:11:52 +11:00
Matt-Yorkley
91fc3f33a0 PI reset and save step improvements 2017-03-17 16:11:52 +11:00
Matt-Yorkley
648753b412 Improved save step UI 2017-03-17 16:11:52 +11:00
Matt-Yorkley
24fcc3dd34 PI reset absent products 2017-03-17 16:11:52 +11:00
Matt-Yorkley
14fb40a996 Product Import options and defaults
Added available_on test

Obscure case fix and extra spec
2017-03-17 16:11:52 +11:00
Matt-Yorkley
f4511fc74d PI permission test 2017-03-17 16:11:52 +11:00
Matt-Yorkley
3d0f192490 Product Import update 2017-03-17 16:11:52 +11:00
Matt-Yorkley
6b7cdf3a37 Product Import Refactoring 2017-03-17 16:11:52 +11:00
Matt-Yorkley
052d6c6b02 Product Import basic specs 2017-03-17 16:11:52 +11:00
Matt-Yorkley
6e5c878491 Product Import cancan permissions and ui tab 2017-03-17 16:11:52 +11:00
Matt-Yorkley
c0c6cd1a60 Product Import feature 2017-03-17 16:11:52 +11:00
Matt-Yorkley
2ad433590d Add roo gem 2017-03-17 16:11:52 +11:00
Rohan Mitchell
2cb3da56ab Fix regression: Transaction fee double-charged 2017-03-17 12:02:13 +11:00
Rohan Mitchell
8582e6d6b4 Add robustness check against intermittent spec failure 2017-03-17 12:02:13 +11:00
Rohan Mitchell
170101cbfe Avoid reloading order during checkout request, which clears credit card number 2017-03-17 12:02:13 +11:00
Maikel Linke
8107f49373 Merge remote-tracking branch 'origin/master' into transifex
Conflicts:
	config/locales/fr.yml
2017-03-16 09:30:22 +11:00
Rob Harrington
7ef0964af2 Adding shortcuts for both sales tax reports to the reports index 2017-03-15 23:57:13 +11:00
Rob Harrington
18472ea8c3 Making 'tax types' report the default sales tax report 2017-03-15 23:56:44 +11:00
Rob Harrington
36e0f45a89 Show the shops invoice text on old invoice template 2017-03-15 17:39:21 +11:00
Rob Harrington
bea0b2b1e5 Adding feature toggle for receipt printing using qz 2017-03-15 16:39:04 +11:00
Rob Harrington
9a69951136 Using correct key for invoice_settings title translation 2017-03-15 16:12:50 +11:00
Rob Harrington
e19bab1aa2 Fixing translations for invoice settings edit template 2017-03-15 15:06:28 +11:00
Rob Harrington
8e2a111a0b Changing ofn-qz to openfoodfoundation fork 2017-03-15 15:06:28 +11:00
Pierre de Lacroix
70707969f3 Add Qz integration 2017-03-15 15:06:28 +11:00
Pierre de Lacroix
2fe25c6219 Allow both invoice layouts to coexist
Add a new "Invoice" page in the admin backend
with a checkbox to toggle between layouts
2017-03-15 15:06:28 +11:00
Pierre de Lacroix
cc1ef5b28b fixes on invoice and tax report 2017-03-15 15:04:57 +11:00
Pierre de Lacroix
3fc2070b2c fix aggregation of taxes for taxes on adjustments 2017-03-15 15:03:46 +11:00
Pierre de Lacroix
d22f5678be small fixes for sales tax report 2017-03-15 15:03:46 +11:00
Rob Harrington
0429906eed Slight adjustments to invoice layout
1. Hide tax column when no tax included in the order

2. Save a little bit of space in the header by sharing rows
2017-03-15 15:03:46 +11:00
Pierre de Lacroix
88a09da325 fix for pull request #1374 2017-03-15 15:03:18 +11:00
Pierre de Lacroix
963f0d601f fix test for tax report 2017-03-15 15:03:18 +11:00
Pierre de Lacroix
8570471c00 add tax rates report 2017-03-15 15:03:18 +11:00
Pierre de Lacroix
7925af30d6 add enterprise logo and custom text on invoices 2017-03-15 15:03:18 +11:00
Pierre de Lacroix
6f59751582 change i18n fallbacks parameter to EN in production settings 2017-03-15 15:03:18 +11:00
Pierre de Lacroix
2d2792225a change invoice layout to include amount for each relevant tax rate 2017-03-15 15:03:18 +11:00
Maikel Linke
a079a64cbe Merge branch 'master' of github.com:openfoodfoundation/openfoodnetwork into i18n2 2017-03-15 12:35:39 +11:00
Maikel Linke
656be690a3 Remove space from permalink tip 2017-03-15 12:11:56 +11:00
Maikel Linke
167045f695 Remove forgotten " character 2017-03-15 12:01:31 +11:00
François Turbelin
dbe968afbb Fixing translated interpolation in fr locale 2017-03-12 12:42:00 +01:00
François Turbelin
179b995fa0 Fixing wrong string interpolation in i18n files 2017-03-12 12:41:06 +01:00
François Turbelin
4791086207 Fixing i18n multiline issues 2017-03-12 12:39:29 +01:00
François Turbelin
be6b09a6e0 Adding i18n keys on JS templates 2017-03-12 12:22:13 +01:00
Transifex-Openfoodnetwork
f235099859 Updating translations for config/locales/fr.yml [skip ci] 2017-03-11 16:50:17 +11:00
Matt-Yorkley
ff8ca521ff Open tos pdf in new tab 2017-02-22 13:40:17 +11:00
Rob Harrington
98f7d52493 Refactor: wrapping registration templates in script tags 2017-02-22 13:40:17 +11:00
Rob Harrington
4815405839 WIP: Moving registration templates in app/views as partials 2017-02-22 13:40:17 +11:00
Rob Harrington
42a6e35185 Making registration spec click_and_ensure assertions more generic
Assertions can be made about checking checkboxes
2017-02-22 13:40:17 +11:00
Matt-Yorkley
408a57479e Flaky tests 2017-02-22 13:40:17 +11:00
Matt-Yorkley
beaf54107c Moved angular template to views folder 2017-02-22 13:40:17 +11:00
Matt-Yorkley
e45d1d42b4 Tidying up 2017-02-22 13:40:17 +11:00
Matt-Yorkley
bc442c7819 Re-adding a line removed in testing 2017-02-22 13:40:17 +11:00
Matt-Yorkley
6a361f2d7b Specced the new terms of service functionality 2017-02-22 13:40:17 +11:00
Matt-Yorkley
a62998e5f1 Enterprise Terms of Service 2017-02-22 13:40:17 +11:00
François Turbelin
ebcb8ff3e7 Finishing Translations keys implemtentation on Admin ERB views 2017-02-19 22:08:34 +01:00
Maikel Linke
da8c107331 Merge remote-tracking branch 'origin/master' into transifex
Conflicts:
	config/locales/fr.yml
2017-02-15 15:47:25 +11:00
Continuous Integration
5870927518 Merge remote-tracking branch 'origin/master' into HEAD 2017-02-10 16:42:27 +11:00
Transifex-Openfoodnetwork
e008a154e5 Updating translations for config/locales/sv.yml [skip ci] 2017-02-09 02:36:14 +11:00
Continuous Integration
a2d01b5144 Merge remote-tracking branch 'origin/master' into HEAD 2017-02-08 16:53:53 +11:00
Rob Harrington
8afd5c509b Using coffescript syntax to check for presence of enterprise_form 2017-02-08 15:59:11 +11:00
Matt-Yorkley
311f72e4cb Fixing JS spec failure 2017-02-08 15:59:11 +11:00
Matt-Yorkley
78563a7d75 Changed for build failure 2017-02-08 15:59:11 +11:00
Matt-Yorkley
9284dd9b63 Enable save after deleting enterprise manager 2017-02-08 15:59:11 +11:00
Continuous Integration
92981e4fcd Merge remote-tracking branch 'origin/master' into HEAD 2017-02-08 10:38:47 +11:00
Matt-Yorkley
9235727d45 Merge pull request #5 from mkllnk/pr-1329-enterprise-switcher
Re-use NavigationCheck logic
2017-02-02 15:26:01 +00:00
Matt-Yorkley
fc4ead9b05 Ensure on_demand set properly on new products 2017-02-02 01:06:20 +00:00
Maikel Linke
b8622e95b7 Re-use NavigationCheck logic
The enterprise switcher now uses the same code as NavigationCheck to
confirm leaving a changed form. This makes FormState obsolete.

Conflicts:
	app/assets/javascripts/admin/enterprises/controllers/enterprise_controller.js.coffee
2017-02-02 10:58:32 +11:00
Continuous Integration
f8341dccd4 Merge remote-tracking branch 'origin/master' into HEAD 2017-02-01 10:35:53 +11:00
Lynne
b8ed7789f0 Merge pull request #1427 from openfoodfoundation/revert-1424-master
Revert "translate ABN and ACN to company number, charity number"
2017-01-30 13:18:16 +00:00
Lynne
6d19613ecc Revert "translate ABN and ACN to company number, charity number" 2017-01-30 12:53:01 +00:00
Lynne
0d56cbf169 Merge pull request #1424 from OliverUK/master
translate ABN and ACN to company number, charity number
2017-01-30 12:04:54 +00:00
Lynne
67730e82c3 Update en-GB.yml 2017-01-30 12:04:24 +00:00
OliverUK
940ca7ade1 translate ABN and ACN to company number, charity number 2017-01-27 15:02:38 +00:00
Continuous Integration
05f9747f15 Merge remote-tracking branch 'origin/master' into HEAD 2017-01-25 12:41:02 +11:00
Matt-Yorkley
27903ab744 Merge branch 'master' into uk/switcher 2017-01-22 18:57:25 +00:00
Matt-Yorkley
931e528e14 Code review changes 2017-01-22 18:55:28 +00:00
Matt-Yorkley
6bed94a09b Include E2E permissions 2017-01-22 18:42:23 +00:00
Paul Mackay
165b437f31 #1226: fix OSM URL to use HTTPS 2017-01-20 15:59:22 +00:00
Continuous Integration
b526307ad1 Merge remote-tracking branch 'origin/master' into HEAD 2017-01-18 18:14:10 +11:00
Continuous Integration
a7bfddfcb5 Merge remote-tracking branch 'origin/master' into HEAD 2017-01-18 17:22:21 +11:00
Continuous Integration
52e4722dcb Merge remote-tracking branch 'origin/master' into HEAD 2017-01-18 11:19:57 +11:00
Rob Harrington
017916b193 Enterprise distributing_products scope uses INNER JOINS instead of OUTER JOINS 2017-01-17 19:28:21 +11:00
Paul Mackay
02e5ba4dfd Convert .sass files to .scss format 2017-01-15 12:11:53 +00:00
Paul Mackay
651626eb4f #1365: Remove /test dir as it is not used 2017-01-14 11:47:21 +00:00
Continuous Integration
20d01c3047 Merge remote-tracking branch 'origin/master' into HEAD 2017-01-13 11:44:47 +11:00
Continuous Integration
a391b6f076 Merge remote-tracking branch 'origin/master' into HEAD 2017-01-13 11:12:17 +11:00
Continuous Integration
ade73f66c8 Merge remote-tracking branch 'origin/master' into HEAD 2017-01-13 10:50:32 +11:00
Maikel Linke
44970a13bb Fix translation of email confirmation notice
The `_html` suffix was missing leading to `<br />` being displayed in
plain text. The new version also integrates the email address as a
variable in the translation.
2017-01-13 10:21:25 +11:00
Paul Mackay
d80f080af5 #1027: Use url helpers for basic pages
Set groups change frequency to monthly.
2017-01-12 10:18:30 +00:00
Continuous Integration
6ec7276cfc Merge remote-tracking branch 'origin/master' into HEAD 2017-01-11 16:30:37 +11:00
Continuous Integration
2444d3b547 Merge remote-tracking branch 'origin/master' into HEAD 2017-01-11 15:54:08 +11:00
Maikel Linke
e899633aff Merge duplicate locale entry admin.enterprises.index 2017-01-11 14:48:05 +11:00
Maikel Linke
a9f01c0f0d Fix typos in en.yml 2017-01-11 11:15:44 +11:00
Matt-Yorkley
e021afdd8a Updated spec 2017-01-10 23:53:13 +00:00
François Turbelin
88dea0f2b8 Adding i18n keys on Admin side (Rails views) 2017-01-11 10:00:06 +11:00
Matt-Yorkley
5150025641 Updated tag rules UI 2017-01-10 22:54:22 +00:00
Paul Mackay
fc400741b4 Remove lastmod for groups 2017-01-10 11:44:57 +00:00
Paul Mackay
5cb2194f5e #1027: Add sitemap.xml generation 2017-01-10 11:39:17 +00:00
Transifex-Openfoodnetwork
64f6a794fc Updating translations for config/locales/nb.yml [skip ci] 2017-01-08 23:36:57 +11:00
elf Pavlik
764c95488c made api key optional (google maps) 2017-01-07 10:25:32 -06:00
Lynne
6cabba4cd8 Merge pull request #1354 from openfoodfoundation/uk/translation
Uk/translation
2017-01-06 10:00:23 +00:00
elf Pavlik
bd1cd527d3 configurable google maps api key 2017-01-03 20:57:10 -06:00
Lynne Davis
d17f9dc504 update 2017-01-03 16:35:01 +00:00
Lynne Davis
f62c583130 uk translation updates 2017-01-03 16:12:41 +00:00
Maikel
b1e27e0dad Auto-merged master into uk/translation on deployment. 2017-01-04 02:24:40 +11:00
Levent Ali
6ae1272281 Mark order cycle form as dirty when removing fees
Resolves an issue where removing coordinator/exchange fees
wasn't allowing users to save the OC.

Fixes #1165
2016-12-23 09:33:34 +11:00
Lynne
e0cb6ed60a Merge pull request #1349 from openfoodfoundation/tos
Adding UK ToS to repo
2016-12-22 18:31:30 +00:00
Maikel
8aeec74fed Auto-merged master into tos on deployment. 2016-12-22 23:19:27 +11:00
Lynne Davis
7cd7e7367b Adding UK TOS to repo 2016-12-22 12:09:44 +00:00
Continuous Integration
4f4fe90db4 Merge remote-tracking branch 'origin/master' into HEAD 2016-12-21 15:27:57 +11:00
Continuous Integration
7a7cd3a937 Merge remote-tracking branch 'origin/master' into HEAD 2016-12-21 14:16:08 +11:00
Continuous Integration
bfc01e7c89 Merge remote-tracking branch 'origin/master' into HEAD 2016-12-21 11:21:42 +11:00
Matt-Yorkley
bc5672b5eb Added translation 2016-12-20 13:30:24 +00:00
Lynne Davis
d77f775c4c Moving commits from 1241 to trigger build on UK staging 2016-12-19 15:06:43 +00:00
Matt-Yorkley
7531c8cbc9 Removed dashes 2016-12-19 11:10:12 +00:00
Matt-Yorkley
38fe0afc03 Changed p widths 2016-12-17 22:59:29 +00:00
Matt-Yorkley
252f876827 Fixed orders closed display for mobile view 2016-12-17 22:54:59 +00:00
Matt-Yorkley
6d9bae8ef9 Checkout layout adjustments for mobile view 2016-12-17 20:39:13 +00:00
Matt-Yorkley
0b2281dfe2 Adjustment for chrome browser 2016-12-17 16:07:39 +00:00
Continuous Integration
72cff0688a Merge remote-tracking branch 'origin/master' into HEAD 2016-12-16 15:24:52 +11:00
Rohan Mitchell
9793450ed0 Make mobile menu mimic the large menu 2016-12-16 14:40:13 +11:00
Rohan Mitchell
c8f0502e71 Apply connect_learn_homepage feature toggle to mobile menu 2016-12-16 14:32:48 +11:00
Continuous Integration
b075ed373a Merge remote-tracking branch 'origin/master' into HEAD 2016-12-16 13:46:08 +11:00
Rafael Braz
eef308c4f6 create a pr-br translate file (#1266) 2016-12-15 08:39:37 +11:00
Transifex-Openfoodnetwork
70225afa13 Updating translations for config/locales/fr.yml [skip ci] 2016-12-12 05:53:28 +11:00
Matt-Yorkley
0a67876815 Update angular-file-uploader-rails to v1.1.6 2016-12-09 18:47:16 +00:00
Lynne
b59e5ad248 Merge pull request #1243 from openfoodfoundation/uk/translations
Translation updates
2016-12-09 16:37:38 +00:00
Matt-Yorkley
287e0b5b55 Enterprise switcher and navigation check 2016-12-09 15:15:42 +00:00
Continuous Integration
c6a1560845 Auto-merge from CI [skip ci] 2016-12-10 01:42:26 +11:00
Lynne Davis
45dc1341d3 translation updates 2016-12-09 14:41:16 +00:00
Matt-Yorkley
7d7197da58 Reordered enterprises submenu 2016-12-09 14:31:34 +00:00
Matt-Yorkley
066f42070a Fixed confusing wysiwyg line breaks display discrepency 2016-12-09 14:12:00 +00:00
Lynne Davis
cad3464f56 Adjusted BOM spec to reflect currency symbol changes 2016-12-09 11:40:55 +00:00
Rohan Mitchell
bbcaef20a8 Add unit specs for Spree::Admin::NavigationHelper 2016-12-09 11:24:58 +11:00
Rohan Mitchell
43726a0b23 Fix inventory link not appearing on menu 2016-12-08 10:38:29 +11:00
Rohan Mitchell
6e6efea328 Fix groups link not appearing on menu 2016-12-08 10:38:23 +11:00
Maikel Linke
a2a6ce1b3e Revert "TEMP: Remove override for no-longer-present method"
This reverts commit a3b91dabe5.

Conflicts:
	app/helpers/spree/admin/navigation_helper_decorator.rb
2016-12-08 10:38:21 +11:00
Maikel Linke
3a69c958ef Hide super admin menu items for enterprise users
Imported temporarily missing Spree functionality. This patch becomes
obsolete with another Spree upgrade.
2016-12-08 10:38:21 +11:00
Continuous Integration
14ee7a06ae Merge remote-tracking branch 'origin/master' into HEAD 2016-12-07 17:03:27 +11:00
Maikel Linke
6cd8289b27 Correct more typos 2016-12-02 16:50:54 +11:00
Rob Harrington
d0509b54bf Disabling override the adds coupon field to cart page 2016-11-30 18:30:20 +11:00
Lynne Davis
ee905cad5f Translation updates 2016-11-29 15:07:35 +00:00
Transifex-Openfoodnetwork
01efb63ad3 Updating translations for config/locales/en_GB.yml [skip ci] 2016-11-30 01:07:53 +11:00
Matt-Yorkley
7981feefa1 Updated form to include help tip for clarity 2016-11-28 14:38:13 +00:00
Rohan Mitchell
d4fd66461e Add retry to flaky specs 2016-11-25 14:37:47 +11:00
Rohan Mitchell
071ba5285d Put timecop config in spec support 2016-11-25 14:28:05 +11:00
Rohan Mitchell
6795237a2d Put timecop into safe mode and fix leaky Timecop.freeze 2016-11-25 14:14:42 +11:00
Rohan Mitchell
57363e2da5 When a product is deleted, touch the supplier and distributors 2016-11-25 14:14:42 +11:00
Rohan Mitchell
da9a3ce9f3 Refresh products cache when product is deleted (cf. destroyed) 2016-11-25 14:14:42 +11:00
Rohan Mitchell
c4318030d3 Fix spec: Second visit doesn't actually reload the page 2016-11-25 14:14:42 +11:00
Rohan Mitchell
44a301edb1 When touching distributing enterprises, do not touch self -> infinite recursion 2016-11-25 14:14:42 +11:00
Rohan Mitchell
dabac50128 Replace Enterprise.distributing_product and Enterprise.distributing_any_product_of with Enterprise.distributing_products 2016-11-25 14:14:42 +11:00
Rohan Mitchell
6030e9a294 Cache enterprise supplied and distributed properties and producer properties 2016-11-25 14:14:42 +11:00
Rohan Mitchell
9b656eaf4f Property / ProducerProperty changes update distributor enterprise cache 2016-11-25 14:14:42 +11:00
Rohan Mitchell
22080a9a08 Property / ProducerProperty changes update supplier enterprise cache 2016-11-25 14:14:42 +11:00
Rohan Mitchell
d93fe3cf2c Cache enterprise supplied and distributed taxons 2016-11-25 14:14:42 +11:00
Rohan Mitchell
1ea4f4274c Add enterprise cache invalidation for order cycle changes 2016-11-25 14:14:42 +11:00
Rohan Mitchell
bd11c6ce14 New hash style 2016-11-25 14:14:42 +11:00
Rohan Mitchell
e8848451a5 Spacing 2016-11-25 14:14:42 +11:00
Rohan Mitchell
f4f38b4183 Re-apply shop property filters - including performance regression
This reverts commit 7d149ed198.
2016-11-25 14:14:42 +11:00
Rob Harrington
27283c50b8 Customers service clears array fo each #index request 2016-11-25 12:43:48 +11:00
Matt-Yorkley
3e77534dcf Product variant form script 2016-11-25 01:31:45 +00:00
Rob Harrington
5e214a32b3 Moving ShippingMethods service to admin.resource module 2016-11-25 11:59:00 +11:00
Rob Harrington
7498b7f098 Moving PaymentMethods service to admin.resource module 2016-11-25 11:57:59 +11:00
Rob Harrington
268c8dbcdd Moving Customers and CustomerResource services to admin.resource module 2016-11-25 11:46:51 +11:00
Rob Harrington
dbbd52cace Fixing broken taxons filter on bulk product edit
Was referencing Taxons.taxons instead of Taxons.all
2016-11-25 10:37:01 +11:00
Rob Harrington
1770a67cd9 Adding #load function to services for resources, for generic loading of data into byID and pristineByID 2016-11-25 10:37:01 +11:00
Rob Harrington
3678d4d018 Creating new 'resources' module for holding interdependent ngResource services 2016-11-25 10:37:01 +11:00
Rob Harrington
3de69987e6 Changing convention for angular resource services to generic 'byID' object and 'all' array 2016-11-25 10:37:01 +11:00
Rob Harrington
cbbb047fc1 Expunge all mentions of includeBlank and blankOption from angular services 2016-11-25 10:37:01 +11:00
Maikel Linke
338d3cbc38 Delete old commented code 2016-11-25 10:27:13 +11:00
Maikel Linke
4c438ff101 Merge branch 'master' of github.com:openfoodfoundation/openfoodnetwork into shop-navigation-directive 2016-11-25 10:24:42 +11:00
Rohan Mitchell
631b19084a Fix intermittent failure via FK when deleted taxon is primary taxon on p2 2016-11-25 09:37:05 +11:00
Levent Ali
63e815c7fc Correct spelling of further in translations 2016-11-24 08:31:01 +00:00
Rohan Mitchell
b7e9ffc9da Fix enterprise user being denied access to admin when spree dash configured (as on production) 2016-11-24 13:35:49 +11:00
Rohan Mitchell
d8ce0e7d58 A user without enterprises does not have access to the dashboard, so it's not meaningful to spec 2016-11-24 13:35:04 +11:00
Continuous Integration
a115f2a268 Merge remote-tracking branch 'origin/master' into HEAD 2016-11-23 15:00:02 +11:00
Maikel Linke
c0c8b07add Let shopping tabs listen to URL changes
When clicking on a shopping tab like "contact", it changed the URL. But
changing the URL did not change the tab. Listening to URL changes
enables manual manipulation of the URL and simple links to "#/contact"
to open the contact tab.
2016-11-11 17:11:39 +11:00
Rohan Mitchell
5913004e14 Fix datepicker error parsing date 2016-11-09 11:47:57 +11:00
Rohan Mitchell
f4034b1065 Fix spec 2016-11-04 09:39:17 +11:00
Rob Harrington
db93b74490 Refactoring ofnSelect2, works with multiple, and with promised data 2016-11-04 09:39:17 +11:00
Rohan Mitchell
d574b8943b WIP: Cherry-pick b2d82b6 - Using ofnSelect2 instead of plain select on BOM 2016-11-04 09:39:17 +11:00
Rohan Mitchell
46fcf7b62e Fix enterprise group save error - initialise address correctly 2016-11-04 09:39:17 +11:00
Rohan Mitchell
3e565ad7cb Mark admin enterprises form dirty when property removed 2016-11-04 09:39:17 +11:00
Rohan Mitchell
0e01350107 Use jquery-migrate instead of downgrading jQuery to access $.browser 2016-11-04 09:39:17 +11:00
Rohan Mitchell
7d79fffa33 Reinstate Spree::PaymentMethod::DISPLAY (removed in Spree but used by us) 2016-11-04 09:39:17 +11:00
Rohan Mitchell
4117b32ebd Fix specs: We had no permission to update the specified supplier (how did this ever work?) 2016-11-04 09:39:17 +11:00
Rohan Mitchell
7a68cc7da1 Remove spec for product distributions 2016-11-04 09:39:17 +11:00
Rohan Mitchell
20e6b703d9 Rewrite alias_method to alias_method_chain 2016-11-04 09:39:17 +11:00
Rohan Mitchell
a1535d6c04 Catch flash messages after fadeout 2016-11-04 09:39:17 +11:00
Rohan Mitchell
f33df883a0 Fix link_to_remove_fields - does not immediately delete the field 2016-11-04 09:39:17 +11:00
Rohan Mitchell
48acf80c85 Fix tabbing 2016-11-04 09:39:17 +11:00
Rohan Mitchell
d8f8c0df16 Fix API auth: Need Spree::Api::UsersController for authorise_api action to work 2016-11-04 09:39:17 +11:00
Rohan Mitchell
8ce917a422 Work around click obscuration 2016-11-04 09:39:17 +11:00
Rohan Mitchell
6546d2763b Add Spree::Money#to_html (from Spree 2.0) 2016-11-04 09:39:17 +11:00
Rohan Mitchell
d3a3b2da9a Pin jquery-rails to 2.1.4 (older version) to prevent missing $.browser errors 2016-11-04 09:39:17 +11:00
Rohan Mitchell
fdd6400cb8 Fix perms for API soft delete 2016-11-04 09:39:17 +11:00
Rohan Mitchell
225e436293 Update included tax param before loading resource 2016-11-04 09:39:17 +11:00
Rohan Mitchell
0e354f8fc1 Remove unused currency config vars: decimal_mark, thousands_separator 2016-11-04 09:39:17 +11:00
Rohan Mitchell
a6a0bdb063 Sanitize values before they're used 2016-11-04 09:39:17 +11:00
Rohan Mitchell
6753320336 Do not stomp address on create 2016-11-04 09:39:17 +11:00
Rohan Mitchell
a3b91dabe5 TEMP: Remove override for no-longer-present method 2016-11-04 09:39:17 +11:00
Rohan Mitchell
257441c9be Re-add object-level auth to Spree::Admin::ResourceController 2016-11-04 09:39:17 +11:00
Rohan Mitchell
1497d2c3bb Remove missing call 2016-11-04 09:39:17 +11:00
Rohan Mitchell
8f0bc367d0 Include missing helpers 2016-11-04 09:39:17 +11:00
Rohan Mitchell
764219b9ed Fix OrderMailer#find_order 2016-11-04 09:39:17 +11:00
Rohan Mitchell
7f7ee25e27 Money accessors changed to dollars/cents 2016-11-04 09:39:17 +11:00
Rohan Mitchell
1765ba0422 Fix spec dependent on product on_demand 2016-11-04 09:39:17 +11:00
Rohan Mitchell
32d2adc8a2 Fix mailers - provide from address 2016-11-04 09:39:17 +11:00
Rohan Mitchell
d890770104 Order state transition condition removed in Spree 2016-11-04 09:39:17 +11:00
Rohan Mitchell
376c4c3e0e Fix factories - base_product and base_variant removed 2016-11-04 09:39:17 +11:00
Rohan Mitchell
a0b740f52d Generalise fix for missing EnterpriseFee::Calculator to any use of calculated_adjustments 2016-11-04 09:39:17 +11:00
Rohan Mitchell
0d4c4f20df Fix missing EnterpriseFee::Calculator error
Conflicts:
	app/models/enterprise_fee.rb
2016-11-04 09:39:17 +11:00
Rohan Mitchell
ab707cf312 Bundle incremental Spree upgrade 2016-11-04 09:39:17 +11:00
Rohan Mitchell
9989b76b7d Integrate from Spree fork: Calculators work against LineItems 2016-11-04 09:39:17 +11:00
Rohan Mitchell
04a714426f Integrate from Spree fork: Fix spree issues #3531 and #2210 (patch provided by leiyangyou) 2016-11-04 09:39:17 +11:00
Maikel Linke
b66cf14bcb Merge remote-tracking branch 'origin/master' into transifex
Conflicts:
	config/locales/en_GB.yml
2016-10-28 15:21:03 +11:00
Transifex-Openfoodnetwork
b78739f777 Updating translations for config/locales/it.yml [skip ci] 2016-10-21 22:51:27 +11:00
Bing Xie
fb08759bec Add more tests 2016-10-21 14:45:04 +11:00
Bing Xie
a4755865ca Fix customer name 2016-10-21 11:58:50 +11:00
Bing Xie
5318aaedcf Fix country id and state in type bug 2016-10-21 11:42:13 +11:00
Rob Harrington
3e56571e59 Making checkout accordion work with new local storage library 2016-10-21 10:51:36 +11:00
Rob Harrington
e57a25d05f Replacing local storage library with actively maintained one: grevory/angular-local-storage 2016-10-21 10:51:36 +11:00
Rob Harrington
b59a1cc232 Using true/false instead of YES/NO for address defaults and billing same as shipping 2016-10-21 10:51:36 +11:00
Bing Xie
720ca17533 Fix the mistake 2016-10-21 10:51:36 +11:00
Bing Xie
d48b00c77c Fix failed user spec 2016-10-21 10:51:36 +11:00
Bing Xie
77f43e3ca7 Refactor setting default addresses 2016-10-21 10:51:36 +11:00
Bing Xie
23b8fbbbc7 Update customer's default address 2016-10-21 10:51:36 +11:00
Bing Xie
b0402daf32 Fix failed customers filter spec 2016-10-21 10:51:36 +11:00
Bing Xie
079788b4eb Add customer preferred bill and ship address 2016-10-21 10:51:36 +11:00
Bing Xie
21ed37189a Only search customers in user managed enterprises 2016-10-21 10:51:36 +11:00
Bing Xie
80d755da0d Convert state_id and country_id in serializer 2016-10-21 10:51:36 +11:00
Bing Xie
8d534041b2 Refactor js CurrentOrder 2016-10-21 10:51:36 +11:00
Bing Xie
e91c313f1e Fix state_id and country_id type bug 2016-10-21 10:51:36 +11:00
Bing Xie
2f241485a2 Set default addresses for user or customer 2016-10-21 10:51:36 +11:00
Bing Xie
f14ca87eb5 Set new address for user 2016-10-21 10:51:36 +11:00
Bing Xie
1caf648fe5 Move customer search to directive 2016-10-21 10:51:36 +11:00
Bing Xie
ac39c93bbf Fix failed js test 2016-10-21 10:51:36 +11:00
Bing Xie
63617f80c5 Add confirm when delete customer 2016-10-21 10:51:36 +11:00
Bing Xie
a94a30f422 Update the orders spec 2016-10-21 10:51:36 +11:00
Bing Xie
63dc48a075 Override customer search UI 2016-10-21 10:51:36 +11:00
Bing Xie
bc798504e0 Add new enterprise customers search API 2016-10-21 10:51:36 +11:00
Bing Xie
fd32152e88 Search customers in enterprises 2016-10-21 10:51:36 +11:00
Bing Xie
1877bea68d Customer serializer without tag_rule_mapping option 2016-10-21 10:51:36 +11:00
Bing Xie
f7523ad88c Create customer with default name and addresses 2016-10-21 10:51:36 +11:00
Bing Xie
ae2357d309 Edit customer address with first name and last name 2016-10-21 10:51:36 +11:00
Bing Xie
8afbdcaf79 Move phone down 2016-10-21 10:51:36 +11:00
Bing Xie
3e590f92ff Set default billing address and shipping address 2016-10-21 10:51:36 +11:00
Bing Xie
a6cfa061e4 Fix ship_address_same_as_billing checkbox value with string 2016-10-21 10:51:36 +11:00
Maikel Linke
d59db1cd97 Merge remote-tracking branch 'origin/master' into uk/delivery-address 2016-10-19 11:01:24 +11:00
Transifex-Openfoodnetwork
7cfb25ace9 Updating translations for config/locales/en_GB.yml [skip ci] 2016-10-15 01:48:24 +11:00
Continuous Integration
51f97f5b28 Merge remote-tracking branch 'origin/master' into HEAD 2016-10-12 13:02:27 +11:00
Transifex-Openfoodnetwork
33d940c736 Updating translations for config/locales/fr.yml [skip ci] 2016-10-12 01:03:42 +11:00
Maikel Linke
08b9b50f33 Re-phrase shop options 2016-10-07 13:17:28 +11:00
Maikel Linke
7c3968b64e Hide guest checkout if deactivated 2016-10-05 15:41:09 +11:00
Maikel Linke
c59cd21698 Add option 'allow guest orders' to enterprise
An enterprise manager can choose to allow guest orders (default) or
require a valid login for checkout.
2016-10-05 14:04:08 +11:00
Maikel Linke
92694c729f Move 'shopfront requires login' setting
Move 'shopfront requires login' setting to 'shop preferences' tab in
Profile Edit.

Solves issue #901.
2016-10-05 14:04:08 +11:00
Maikel Linke
7b2b285ba7 Rescue spec fails within enqueue_job matcher
Failing code tested by the enqueue_job matcher made it fail with:

  expected ConfirmOrderJob to be enqueued matching {} (??? others enqueued)

That was not helpful and masking the real failure. That failure is now
passed on. The hidden intermittent failure happened in 5% of runs on
Travis.
2016-10-05 14:04:08 +11:00
Maikel Linke
caeb8f08e7 Use link_to with mailto attribute to un-reverse email 2016-10-05 12:31:42 +11:00
Continuous Integration
499237715e Auto-merge from CI [skip ci] 2016-10-05 03:08:43 +11:00
Lynne Davis
7eb2dfba48 Update delivery report to use shipping address 2016-10-04 17:04:35 +01:00
Continuous Integration
815cf16822 Auto-merge from CI [skip ci] 2016-10-05 01:33:18 +11:00
Lynne Davis
a3722dee80 delete file - fix conflict 2016-10-04 15:29:57 +01:00
Lynne Davis
79ea2fd39d Reverse email address 2016-10-03 16:54:15 +01:00
Transifex-Openfoodnetwork
b349c28b9b Updating translations for config/locales/nb.yml [skip ci] 2016-10-02 00:38:02 +10:00
Lynne Davis
40ca2ccee4 Updating TOS url in confirmation email to refer to content_config 2016-09-25 15:14:44 +01:00
Lynne Davis
84b4a9bcbe update to internationalise email address in sell page 2016-09-25 14:00:11 +01:00
Maikel
1742367b36 Auto-merged master into issue_1134 on deployment. 2016-09-22 04:50:28 +10:00
Rhodri Karim
8a1d34e711 Fix for issue 1134 - 'Pack by supplier' report now groups by order rather than last name. 2016-09-21 19:41:43 +01:00
Maikel Linke
fba72498e3 Merge remote-tracking branch 'origin/master' into transifex 2016-09-21 16:36:22 +10:00
Lynne Davis
c533f6a15e Updates to UK translations 2016-09-19 20:33:58 +01:00
Transifex-Openfoodnetwork
23a216004e Updating translations for config/locales/en_GB.yml [skip ci] 2016-09-20 01:02:27 +10:00
Rob Harrington
7d149ed198 Revert shop property filters - causing 10x slowdown
This commit reverts commits 7eeee78c4e to e8f96e4818 (inclusive)
2016-09-18 17:46:43 +10:00
Rohan Mitchell
e8f96e4818 When a shop is open, only show taxon badges for currently open order cycles 2016-09-16 11:47:45 +10:00
Rohan Mitchell
3ca42ae055 Extract ids_to_objs to SerializerHelper 2016-09-16 11:36:27 +10:00
Rohan Mitchell
c0db23af90 Spree::Taxon.distributed_taxons can be scoped to taxons in open order cycles 2016-09-16 11:36:27 +10:00
Rohan Mitchell
db583df198 Use inner join for Spree::Taxon.distributed_taxons 2016-09-16 11:36:27 +10:00
Rohan Mitchell
306bd25dd9 EnterpriseSerialiser shows current properties for open shops and all properties for closed shops 2016-09-16 11:36:27 +10:00
Rohan Mitchell
f98b25b719 Add Spree::Property.ever_sold_by 2016-09-16 11:36:27 +10:00
Rohan Mitchell
1bc477f6b1 Add ProducerProperty.ever_sold_by 2016-09-16 11:36:26 +10:00
Rohan Mitchell
c37bf3d077 Rename Property#sold_by and ProducerProperty#sold_by to currently_sold_by 2016-09-16 11:36:26 +10:00
Rohan Mitchell
3a2e0b7eff Fix spacing 2016-09-16 11:36:26 +10:00
Rohan Mitchell
38c63fc88b Available producer filters update when taxon filter changed 2016-09-16 11:36:26 +10:00
Rohan Mitchell
8ec2ebbf94 Swap to using multi-line selectors for property filters - z-index issues with single-line-selectors 2016-09-16 11:36:26 +10:00
Rohan Mitchell
e00846776e Client-side, always show properties by their presentation, not their name 2016-09-16 11:36:26 +10:00
Rohan Mitchell
8339d247f8 Shops on groups page filter by property 2016-09-16 11:36:26 +10:00
Rohan Mitchell
ed2522f6d2 Explicitly specify supplied or distributed properties for ng filters: properties, propertiesOf 2016-09-16 11:36:26 +10:00
Rohan Mitchell
63ef5de0e5 Use short syntax for render partial 2016-09-16 11:28:45 +10:00
Rohan Mitchell
38d5682762 Add property filters for shops 2016-09-16 11:28:45 +10:00
Rohan Mitchell
4c40219352 Move hubs partials from home to shops, their rightful home 2016-09-16 11:28:45 +10:00
Rohan Mitchell
7eeee78c4e WIP: Move hubs partials from home to shops, their rightful home 2016-09-16 11:28:45 +10:00
Rob Harrington
0760d4cc1f Fixing property filters on shopfront 2016-09-08 12:15:36 +10:00
Rob Harrington
261a574da9 Tweaking styling on enterprise change form, and dashboard header row 2016-09-07 11:13:48 +10:00
Rob Harrington
da55eb6d27 Form for changing enterprise type specifies trial length 2016-09-07 11:13:05 +10:00
Rob Harrington
be51a55f16 Only display shopfront trial message on dashboard page. Fixes #1120 2016-09-02 13:45:49 +10:00
Transifex-Openfoodnetwork
528af8759d Updating translations for config/locales/nb.yml [skip ci] 2016-08-19 01:23:43 +10:00
Transifex-Openfoodnetwork
baeabdd668 Updating translations for config/locales/nb.yml [skip ci] 2016-08-12 19:53:12 +10:00
Transifex-Openfoodnetwork
1de2300099 Updating translations for config/locales/nb.yml [skip ci] 2016-08-12 19:07:43 +10:00
Transifex-Openfoodnetwork
53e8056450 Updating translations for config/locales/fr.yml [skip ci] 2016-08-12 18:56:13 +10:00
Transifex-Openfoodnetwork
5773876cbc Updating translations for config/locales/fr.yml [skip ci] 2016-08-12 17:26:28 +10:00
486 changed files with 17995 additions and 6933 deletions

View File

@@ -9,7 +9,7 @@ gem 'i18n', '~> 0.6.11'
gem 'nokogiri', '>= 1.6.7.1'
gem 'pg'
gem 'spree', github: 'openfoodfoundation/spree', branch: '1-3-stable'
gem 'spree', github: 'openfoodfoundation/spree', branch: 'spree-upgrade-step1c'
gem 'spree_i18n', github: 'spree/spree_i18n', branch: '1-3-stable'
gem 'spree_auth_devise', github: 'spree/spree_auth_devise', branch: '1-3-stable'
@@ -50,7 +50,7 @@ gem 'gmaps4rails'
gem 'spinjs-rails'
gem 'rack-ssl', :require => 'rack/ssl'
gem 'custom_error_message', :github => 'jeremydurham/custom-err-msg'
gem 'angularjs-file-upload-rails', '~> 1.1.0'
gem 'angularjs-file-upload-rails', '~> 1.1.6'
gem 'roadie-rails', '~> 1.0.3'
gem 'figaro'
gem 'blockenspiel'
@@ -63,6 +63,7 @@ gem 'wkhtmltopdf-binary'
gem 'foreigner'
gem 'immigrant'
gem 'roo', '~> 2.7.0'
gem 'whenever', require: false
@@ -87,8 +88,10 @@ gem "foundation-rails"
gem 'foundation_rails_helper', github: 'willrjmarshall/foundation_rails_helper', branch: "rails3"
gem 'jquery-rails'
gem 'jquery-migrate-rails'
gem 'css_splitter'
gem 'ofn-qz', github: 'openfoodfoundation/ofn-qz'
group :test, :development do
# Pretty printed test output

View File

@@ -22,46 +22,56 @@ GIT
spree_core (~> 1.3.4)
GIT
remote: git://github.com/openfoodfoundation/spree.git
revision: 6e3edfe40a5de8eba0095b2c5f3db9ea54c3afda
branch: 1-3-stable
remote: git://github.com/openfoodfoundation/ofn-qz.git
revision: 024680ccea429b2e5428d7b964fa67c52add34ec
specs:
spree (1.3.6.beta)
spree_api (= 1.3.6.beta)
spree_cmd (= 1.3.6.beta)
spree_core (= 1.3.6.beta)
spree_promo (= 1.3.6.beta)
spree_sample (= 1.3.6.beta)
spree_api (1.3.6.beta)
spree_core (= 1.3.6.beta)
ofn-qz (0.1.0)
railties (~> 3.1)
GIT
remote: git://github.com/openfoodfoundation/spree.git
revision: a4c439570b77afa50f9e36299811f293232bd281
branch: spree-upgrade-step1c
specs:
spree (1.3.99)
spree_api (= 1.3.99)
spree_cmd (= 1.3.99)
spree_core (= 1.3.99)
spree_dash (= 1.3.99)
spree_promo (= 1.3.99)
spree_sample (= 1.3.99)
spree_api (1.3.99)
spree_core (= 1.3.99)
versioncake (= 0.4.0)
spree_cmd (1.3.6.beta)
spree_cmd (1.3.99)
thor (>= 0.14.6)
spree_core (1.3.6.beta)
activemerchant (~> 1.34)
spree_core (1.3.99)
activemerchant (~> 1.50.0)
acts_as_list (= 0.1.4)
awesome_nested_set (= 2.1.5)
aws-sdk (~> 1.11.1)
cancan (= 1.6.8)
deface (>= 0.9.0)
ffaker (~> 1.15.0)
highline (= 1.6.18)
jquery-rails (~> 2.2.0)
highline (= 1.6.11)
jquery-rails (~> 2.0)
json (>= 1.5.5)
kaminari (= 0.14.1)
money (= 5.1.1)
kaminari (= 0.13.0)
money (= 5.0.0)
paperclip (~> 3.0)
rabl (= 0.7.2)
rails (~> 3.2.16)
rails (~> 3.2.13)
ransack (= 0.7.2)
select2-rails (= 3.5.9.3)
state_machine (= 1.1.2)
select2-rails (~> 3.2)
state_machine (= 1.2.0)
stringex (~> 1.3.2)
truncate_html (~> 0.5.5)
spree_promo (1.3.6.beta)
spree_core (= 1.3.6.beta)
spree_sample (1.3.6.beta)
spree_core (= 1.3.6.beta)
spree_dash (1.3.99)
httparty (~> 0.8.1)
spree_core (= 1.3.99)
spree_promo (1.3.99)
spree_core (= 1.3.99)
spree_sample (1.3.99)
spree_core (= 1.3.99)
GIT
remote: git://github.com/spree/deface.git
@@ -123,8 +133,8 @@ GEM
sprockets (~> 2.2.1)
active_model_serializers (0.8.3)
activemodel (>= 3.0)
activemerchant (1.57.0)
activesupport (>= 3.2.14, < 5.1)
activemerchant (1.50.0)
activesupport (>= 3.2.14, < 5.0.0)
builder (>= 2.1.2, < 4.0.0)
i18n (>= 0.6.9)
nokogiri (~> 1.4)
@@ -151,7 +161,7 @@ GEM
railties (>= 3.1)
sprockets (~> 2)
tilt
angularjs-file-upload-rails (1.1.0)
angularjs-file-upload-rails (1.1.6)
angularjs-rails (1.5.5)
ansi (1.4.2)
arel (3.0.3)
@@ -167,9 +177,7 @@ GEM
bcrypt-ruby (3.1.5)
bcrypt (>= 3.1.3)
blockenspiel (0.4.5)
bugsnag (1.5.2)
httparty (>= 0.6, < 1.0)
multi_json (~> 1.0)
bugsnag (4.1.0)
builder (3.0.4)
byebug (2.7.0)
columnize (~> 0.3)
@@ -189,7 +197,7 @@ GEM
climate_control (0.0.3)
activesupport (>= 3.0)
cliver (0.3.2)
cocaine (0.5.7)
cocaine (0.5.8)
climate_control (>= 0.0.3, < 1.0)
coderay (1.0.9)
coffee-rails (3.2.2)
@@ -404,12 +412,12 @@ GEM
zeus
haml (4.0.4)
tilt
highline (1.6.18)
highline (1.6.11)
hike (1.2.3)
http_parser.rb (0.5.3)
httparty (0.13.1)
json (~> 1.8)
multi_xml (>= 0.5.2)
httparty (0.8.3)
multi_json (~> 1.0)
multi_xml
i18n (0.6.11)
immigrant (0.1.6)
activerecord (>= 3.0)
@@ -417,16 +425,18 @@ GEM
inflecto (0.0.2)
ipaddress (0.8.0)
journey (1.0.4)
jquery-rails (2.2.2)
jquery-migrate-rails (1.2.1)
jquery-rails (2.3.0)
railties (>= 3.0, < 5.0)
thor (>= 0.14, < 2.0)
json (1.8.3)
json_spec (1.1.1)
multi_json (~> 1.0)
rspec (~> 2.0)
kaminari (0.14.1)
kaminari (0.13.0)
actionpack (>= 3.0.0)
activesupport (>= 3.0.0)
railties (>= 3.0.0)
kgio (2.9.3)
knapsack (1.5.1)
rake
@@ -449,8 +459,9 @@ GEM
mini_portile2 (2.0.0)
momentjs-rails (2.5.1)
railties (>= 3.1)
money (5.1.1)
i18n (~> 0.6.0)
money (5.0.0)
i18n (~> 0.4)
json
multi_json (1.12.1)
multi_xml (0.5.5)
newrelic_rpm (3.12.0.288)
@@ -494,7 +505,7 @@ GEM
activesupport (>= 2.3.14)
multi_json (~> 1.0)
rack (1.4.7)
rack-cache (1.2)
rack-cache (1.6.1)
rack (>= 0.4)
rack-livereload (0.3.15)
rack
@@ -521,7 +532,7 @@ GEM
rdoc (~> 3.4)
thor (>= 0.14.6, < 2.0)
raindrops (0.13.0)
rake (10.4.2)
rake (11.1.2)
ransack (0.7.2)
actionpack (~> 3.0)
activerecord (~> 3.0)
@@ -547,6 +558,9 @@ GEM
roadie-rails (1.0.3)
rails (>= 3.0, < 4.2)
roadie (~> 3.0)
roo (2.7.1)
nokogiri (~> 1)
rubyzip (~> 1.1, < 2.0.0)
rspec (2.14.1)
rspec-core (~> 2.14.0)
rspec-expectations (~> 2.14.0)
@@ -565,13 +579,14 @@ GEM
rspec-retry (0.4.2)
rspec-core
ruby-progressbar (1.7.1)
rubyzip (1.2.0)
safe_yaml (0.9.5)
sass (3.3.14)
sass-rails (3.2.6)
railties (~> 3.2.0)
sass (>= 3.1.10)
tilt (~> 1.3)
select2-rails (3.5.9.3)
select2-rails (3.5.10)
thor (~> 0.14)
shoulda-matchers (1.1.0)
activesupport (>= 3.0.0)
@@ -583,14 +598,14 @@ GEM
multi_json (~> 1.0)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
state_machine (1.1.2)
state_machine (1.2.0)
stringex (1.3.3)
therubyracer (0.12.0)
libv8 (~> 3.16.14.0)
ref
thor (0.19.1)
tilt (1.4.1)
timecop (0.6.2.2)
timecop (0.8.1)
timers (1.1.0)
treetop (1.4.15)
polyglot
@@ -601,7 +616,7 @@ GEM
sprockets (>= 2.0.0)
turn (0.8.3)
ansi
tzinfo (0.3.44)
tzinfo (0.3.49)
uglifier (2.7.1)
execjs (>= 0.3.0)
json (>= 1.8.0)
@@ -645,7 +660,7 @@ DEPENDENCIES
acts-as-taggable-on (~> 3.4)
andand
angular-rails-templates (~> 0.2.0)
angularjs-file-upload-rails (~> 1.1.0)
angularjs-file-upload-rails (~> 1.1.6)
angularjs-rails (= 1.5.5)
atomic
awesome_print
@@ -682,6 +697,7 @@ DEPENDENCIES
haml
i18n (~> 0.6.11)
immigrant
jquery-migrate-rails
jquery-rails
json_spec
knapsack
@@ -689,6 +705,7 @@ DEPENDENCIES
momentjs-rails
newrelic_rpm
nokogiri (>= 1.6.7.1)
ofn-qz!
oj
paper_trail (~> 3.0.8)
paperclip
@@ -704,6 +721,7 @@ DEPENDENCIES
redcarpet
representative_view
roadie-rails (~> 1.0.3)
roo (~> 2.7.0)
rspec-rails
rspec-retry
sass (~> 3.3)
@@ -728,5 +746,8 @@ DEPENDENCIES
wicked_pdf
wkhtmltopdf-binary
RUBY VERSION
ruby 2.1.5p273
BUNDLED WITH
1.12.5
1.14.3

View File

@@ -6,6 +6,7 @@
//
//= require jquery
//= require jquery-migrate-min
//= require jquery_ujs
//= require jquery-ui
//= require shared/jquery-ui-timepicker-addon
@@ -36,6 +37,7 @@
//= require ./order_cycles/order_cycles
//= require ./payment_methods/payment_methods
//= require ./products/products
//= require ./resources/resources
//= require ./shipping_methods/shipping_methods
//= require ./side_menu/side_menu
//= require ./tag_rules/tag_rules

View File

@@ -22,7 +22,7 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
$scope.producers = producers
$scope.taxons = Taxons.taxons
$scope.taxons = Taxons.all
$scope.tax_categories = tax_categories
$scope.filterProducers = [{id: "0", name: ""}].concat $scope.producers
$scope.filterTaxons = [{id: "0", name: ""}].concat $scope.taxons

View File

@@ -3,9 +3,8 @@ angular.module("admin.customers").controller "customersCtrl", ($scope, $q, $filt
$scope.availableCountries = availableCountries
$scope.RequestMonitor = RequestMonitor
$scope.submitAll = pendingChanges.submitAll
$scope.add = Customers.add
$scope.deleteCustomer = Customers.remove
$scope.customerLimit = 20
$scope.customers = Customers.all
$scope.columns = Columns.columns
$scope.confirmRefresh = (event) ->
@@ -17,10 +16,13 @@ angular.module("admin.customers").controller "customersCtrl", ($scope, $q, $filt
Customers.index({enterprise_id: $scope.shop_id}).then (data) ->
pendingChanges.removeAll()
$scope.customers_form.$setPristine()
$scope.customers = data
$scope.shop_id = shops[0].id if shops.length == 1
$scope.deleteCustomer = (customer) ->
if confirm(t('admin.customers.index.confirm_delete'))
Customers.remove(customer)
$scope.checkForDuplicateCodes = ->
delete this.customer.code unless this.customer.code
this.duplicate = $scope.isDuplicateCode(this.customer.code)

View File

@@ -11,7 +11,7 @@ angular.module("admin.enterprises")
$scope.StatusMessage = StatusMessage
$scope.$watch 'enterprise_form.$dirty', (newValue) ->
StatusMessage.display 'notice', 'You have unsaved changes' if newValue
StatusMessage.display 'notice', t('admin.unsaved_changes') if newValue
$scope.setFormDirty = ->
$scope.$apply ->
@@ -24,13 +24,12 @@ angular.module("admin.enterprises")
$scope.navClear()
enterprise_form.submit()
# Provide a callback for generating warning messages displayed before leaving the page. This is passed in
# from a directive "nav-check" in the page - if we pass it here it will be called in the test suite,
# and on all new uses of this contoller, and we might not want that .
# and on all new uses of this contoller, and we might not want that.
enterpriseNavCallback = ->
if $scope.Enterprise.$dirty
"Your changes to the enterprise are not saved yet."
if $scope.enterprise_form.$dirty
t('admin.unsaved_confirm_leave')
# Register the NavigationCheck callback
NavigationCheck.register(enterpriseNavCallback)
@@ -39,6 +38,8 @@ angular.module("admin.enterprises")
if manager.id?
for i, user of $scope.Enterprise.users when user.id == manager.id
$scope.Enterprise.users.splice i, 1
if $scope.enterprise_form?
$scope.enterprise_form.$setDirty()
$scope.addManager = (manager) ->
if manager.id? and manager.email?

View File

@@ -6,7 +6,6 @@ angular.module("admin.enterprises")
$scope.menu.setItems [
{ name: 'primary_details', label: t('primary_details'), icon_class: "icon-home" }
{ name: 'users', label: t('users'), icon_class: "icon-user" }
{ name: 'address', label: t('address'), icon_class: "icon-map-marker" }
{ name: 'contact', label: t('contact'), icon_class: "icon-phone" }
{ name: 'social', label: t('social'), icon_class: "icon-twitter" }
@@ -20,11 +19,11 @@ angular.module("admin.enterprises")
{ name: 'inventory_settings', label: t('inventory_settings'), icon_class: "icon-list-ol", show: "enterpriseIsShop()" }
{ name: 'tag_rules', label: t('tag_rules'), icon_class: "icon-random", show: "enterpriseIsShop()" }
{ name: 'shop_preferences', label: t('shop_preferences'), icon_class: "icon-shopping-cart", show: "enterpriseIsShop()" }
{ name: 'users', label: t('users'), icon_class: "icon-user" }
]
$scope.select(0)
$scope.showItem = (item) ->
if item.show?
$parse(item.show)($scope)

View File

@@ -0,0 +1,16 @@
angular.module('admin.enterprises').directive 'enterpriseSwitcher', (NavigationCheck) ->
restrict: 'A'
require: 'ngModel'
link: (scope, element, attr, ngModel) ->
initial = element[0].getAttribute('data-initial')
element.on 'change', ->
if not NavigationCheck.confirmLeave()
# Reset the current dropdown selection if staying on page
ngModel.$setViewValue initial
ngModel.$render()
element.select2 'val', initial
return
NavigationCheck.clear() # Don't ask twice if leaving
window.location = element[0].querySelector('option[selected]').getAttribute('data-url')

View File

@@ -3,19 +3,42 @@ angular.module("admin.indexUtils").directive "ofnSelect2", ($sanitize, $timeout,
restrict: 'C'
scope:
data: "="
minSearch: "@?"
text: "@?"
minSearch: "@"
text: "@"
blank: "=?"
filter: "=?"
onSelecting: "=?"
multiple: '@'
link: (scope, element, attrs, ngModel) ->
$timeout ->
scope.text ||= 'name'
scope.filter ||= -> true
scope.text ?= 'name'
scope.multiple ?= false
scope.filter ?= -> true
if scope.data.$promise
scope.data.$promise.then -> init()
else
init()
element.on "select2-opening", scope.onSelecting || angular.noop
attrs.$observe 'disabled', (value) ->
element.select2('enable', !value)
ngModel.$formatters.push (value) ->
element.select2('val', value)
value
ngModel.$parsers.push (value) ->
return value.split(",") if scope.multiple
value
init = ->
scope.data.unshift(scope.blank) if scope.blank? && typeof scope.blank is "object"
item.name = $sanitize(item.name) for item in scope.data
element.select2
multiple: scope.multiple
minimumResultsForSearch: scope.minSearch || 0
data: ->
filtered = $filter('filter')(scope.data,scope.filter)
@@ -24,12 +47,3 @@ angular.module("admin.indexUtils").directive "ofnSelect2", ($sanitize, $timeout,
item[scope.text]
formatResult: (item) ->
item[scope.text]
element.on "select2-opening", scope.onSelecting || angular.noop
attrs.$observe 'disabled', (value) ->
element.select2('enable', !value)
ngModel.$formatters.push (value) ->
element.select2('val', value)
value

View File

@@ -1 +1 @@
angular.module("admin.indexUtils", ['ngResource', 'ngSanitize', 'templates', 'admin.utils']).config ($httpProvider) ->
angular.module("admin.indexUtils", ['admin.resources', 'ngSanitize', 'templates', 'admin.utils']).config ($httpProvider) ->

View File

@@ -3,7 +3,8 @@ angular.module("admin.indexUtils").factory 'Dereferencer', ->
dereference: (array, data)->
if array
for object, i in array
array[i] = data[object.id]
match = data[object.id]
array[i] = match if match?
dereferenceAttr: (array, attr, data)->
if array

View File

@@ -1,4 +1,4 @@
angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout, $http, $q, StatusMessage, Columns, Dereferencer, Orders, LineItems, Enterprises, OrderCycles, blankOption, VariantUnitManager, RequestMonitor) ->
angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout, $http, $q, StatusMessage, Columns, Dereferencer, Orders, LineItems, Enterprises, OrderCycles, VariantUnitManager, RequestMonitor) ->
$scope.initialized = false
$scope.RequestMonitor = RequestMonitor
$scope.filteredLineItems = []
@@ -15,31 +15,31 @@ angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout,
LineItems.allSaved() || confirm(t("unsaved_changes_warning"))
$scope.resetSelectFilters = ->
$scope.distributorFilter = blankOption().id
$scope.supplierFilter = blankOption().id
$scope.orderCycleFilter = blankOption().id
$scope.distributorFilter = 0
$scope.supplierFilter = 0
$scope.orderCycleFilter = 0
$scope.quickSearch = ""
$scope.refreshData = ->
unless !$scope.orderCycleFilter? || $scope.orderCycleFilter == "0"
$scope.startDate = OrderCycles.orderCyclesByID[$scope.orderCycleFilter].first_order
$scope.endDate = OrderCycles.orderCyclesByID[$scope.orderCycleFilter].last_order
unless !$scope.orderCycleFilter? || $scope.orderCycleFilter == 0
$scope.startDate = OrderCycles.byID[$scope.orderCycleFilter].first_order
$scope.endDate = OrderCycles.byID[$scope.orderCycleFilter].last_order
RequestMonitor.load $scope.orders = Orders.index("q[state_not_eq]": "canceled", "q[completed_at_not_null]": "true", "q[completed_at_gt]": "#{parseDate($scope.startDate)}", "q[completed_at_lt]": "#{parseDate($scope.endDate)}")
RequestMonitor.load $scope.lineItems = LineItems.index("q[order][state_not_eq]": "canceled", "q[order][completed_at_not_null]": "true", "q[order][completed_at_gt]": "#{parseDate($scope.startDate)}", "q[order][completed_at_lt]": "#{parseDate($scope.endDate)}")
unless $scope.initialized
RequestMonitor.load $scope.distributors = Enterprises.index(includeBlank: true, action: "for_line_items", ams_prefix: "basic", "q[sells_in][]": ["own", "any"])
RequestMonitor.load $scope.orderCycles = OrderCycles.index(includeBlank: true, ams_prefix: "basic", as: "distributor", "q[orders_close_at_gt]": "#{daysFromToday(-90)}")
RequestMonitor.load $scope.suppliers = Enterprises.index(includeBlank: true, action: "for_line_items", ams_prefix: "basic", "q[is_primary_producer_eq]": "true")
RequestMonitor.load $scope.distributors = Enterprises.index(action: "for_line_items", ams_prefix: "basic", "q[sells_in][]": ["own", "any"])
RequestMonitor.load $scope.orderCycles = OrderCycles.index(ams_prefix: "basic", as: "distributor", "q[orders_close_at_gt]": "#{daysFromToday(-90)}")
RequestMonitor.load $scope.suppliers = Enterprises.index(action: "for_line_items", ams_prefix: "basic", "q[is_primary_producer_eq]": "true")
RequestMonitor.load $q.all([$scope.orders.$promise, $scope.distributors.$promise, $scope.orderCycles.$promise]).then ->
Dereferencer.dereferenceAttr $scope.orders, "distributor", Enterprises.enterprisesByID
Dereferencer.dereferenceAttr $scope.orders, "order_cycle", OrderCycles.orderCyclesByID
Dereferencer.dereferenceAttr $scope.orders, "distributor", Enterprises.byID
Dereferencer.dereferenceAttr $scope.orders, "order_cycle", OrderCycles.byID
RequestMonitor.load $q.all([$scope.orders.$promise, $scope.suppliers.$promise, $scope.lineItems.$promise]).then ->
Dereferencer.dereferenceAttr $scope.lineItems, "supplier", Enterprises.enterprisesByID
Dereferencer.dereferenceAttr $scope.lineItems, "order", Orders.ordersByID
Dereferencer.dereferenceAttr $scope.lineItems, "supplier", Enterprises.byID
Dereferencer.dereferenceAttr $scope.lineItems, "order", Orders.byID
$scope.bulk_order_form.$setPristine()
StatusMessage.clear()
unless $scope.initialized

View File

@@ -1,8 +1,8 @@
angular.module("admin.lineItems").filter "selectFilter", (blankOption, RequestMonitor) ->
angular.module("admin.lineItems").filter "selectFilter", (RequestMonitor) ->
return (lineItems,selectedSupplier,selectedDistributor,selectedOrderCycle) ->
filtered = []
unless RequestMonitor.loading
filtered.push lineItem for lineItem in lineItems when (angular.equals(selectedSupplier,"0") || lineItem.supplier.id == selectedSupplier) &&
(angular.equals(selectedDistributor,"0") || lineItem.order.distributor.id == selectedDistributor) &&
(angular.equals(selectedOrderCycle,"0") || lineItem.order.order_cycle.id == selectedOrderCycle)
filtered.push lineItem for lineItem in lineItems when (angular.equals(selectedSupplier,0) || lineItem.supplier.id == selectedSupplier) &&
(angular.equals(selectedDistributor,0) || lineItem.order.distributor.id == selectedDistributor) &&
(angular.equals(selectedOrderCycle,0) || lineItem.order.order_cycle.id == selectedOrderCycle)
filtered

View File

@@ -68,6 +68,7 @@ angular.module('admin.orderCycles')
$scope.removeCoordinatorFee = ($event, index) ->
$event.preventDefault()
OrderCycle.removeCoordinatorFee(index)
$scope.order_cycle_form.$dirty = true
$scope.addExchangeFee = ($event, exchange) ->
$event.preventDefault()
@@ -76,6 +77,7 @@ angular.module('admin.orderCycles')
$scope.removeExchangeFee = ($event, exchange, index) ->
$event.preventDefault()
OrderCycle.removeExchangeFee(exchange, index)
$scope.order_cycle_form.$dirty = true
$scope.removeDistributionOfVariant = (variant_id) ->
OrderCycle.removeDistributionOfVariant(variant_id)

View File

@@ -1,4 +1,4 @@
angular.module('admin.orderCycles', ['ngResource', 'admin.utils', 'admin.indexUtils', 'ngTagsInput'])
angular.module('admin.orderCycles', ['admin.utils', 'admin.indexUtils', 'ngTagsInput'])
.config ($httpProvider) ->
$httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content')

View File

@@ -0,0 +1,59 @@
angular.module("admin.orders").directive 'customerSearchOverride', ->
restrict: 'C'
link: (scope, element, attr) ->
formatCustomerResult = (customer) ->
customerTemplate
customer: customer
bill_address: customer.bill_address
ship_address: customer.ship_address
element.select2
placeholder: Spree.translations.choose_a_customer
ajax:
url: '/admin/search/customers.json'
datatype: 'json'
data: (term, page) ->
{
q: term
distributor_id: $('#distributor_id').val() # modified
}
results: (data, page) ->
{ results: data }
dropdownCssClass: 'customer_search'
formatResult: formatCustomerResult
formatSelection: (customer) ->
_.each [
'bill_address'
'ship_address'
], (address) ->
data = customer[address]
address_parts = [
'firstname'
'lastname'
'company'
'address1'
'address2'
'city'
'zipcode'
'phone'
]
attribute_wrapper = '#order_' + address + '_attributes_'
if data # modified
_.each address_parts, (part) ->
$(attribute_wrapper + part).val data[part]
return
$(attribute_wrapper + 'state_id').select2 'val', data['state_id']
$(attribute_wrapper + 'country_id').select2 'val', data['country_id']
else
_.each address_parts, (part) ->
$(attribute_wrapper + part).val ''
return
$(attribute_wrapper + 'state_id').select2 'val', ''
$(attribute_wrapper + 'country_id').select2 'val', ''
return
$('#order_email').val customer.email
$('#user_id').val customer.user_id # modified
$('#guest_checkout_true').prop 'checked', false
$('#guest_checkout_false').prop 'checked', true
$('#guest_checkout_false').prop 'disabled', false
customer.email

View File

@@ -1,3 +1,3 @@
angular.module("admin.paymentMethods").controller "paymentMethodsCtrl", ($scope, PaymentMethods) ->
$scope.findPaymentMethodByID = (id) ->
$scope.PaymentMethod = PaymentMethods.findByID(id)
$scope.PaymentMethod = PaymentMethods.byID[id]

View File

@@ -1,8 +0,0 @@
angular.module("admin.paymentMethods")
.factory "PaymentMethods", (paymentMethods) ->
new class PaymentMethods
paymentMethods: paymentMethods
findByID: (id) ->
for paymentMethod in @paymentMethods
return paymentMethod if paymentMethod.id is id

View File

@@ -0,0 +1,5 @@
angular.module("ofn.admin").controller "DropdownPanelsCtrl", ($scope) ->
$scope.active = false
$scope.togglePanel = ->
$scope.active = !$scope.active

View File

@@ -0,0 +1,15 @@
angular.module("ofn.admin").controller "ImportOptionsFormCtrl", ($scope, $rootScope, ProductImportService) ->
$scope.toggleResetAbsent = () ->
confirmed = confirm 'This will set stock level to zero on all products for this \n' +
'enterprise that are not present in the uploaded file.' if $scope.resetAbsent
if confirmed or !$scope.resetAbsent
ProductImportService.updateResetAbsent($scope.supplierId, $scope.resetCount, $scope.resetAbsent)
else
$scope.resetAbsent = false
$scope.resetTotal = ProductImportService.resetTotal
$rootScope.$watch 'resetTotal', (newValue) ->
$scope.resetTotal = newValue if newValue || newValue == 0

View File

@@ -0,0 +1,15 @@
angular.module("ofn.admin").factory "ProductImportService", ($rootScope) ->
new class ProductImportService
suppliers: {}
resetTotal: 0
updateResetAbsent: (supplierId, resetCount, resetAbsent) ->
if resetAbsent
@suppliers[supplierId] = resetCount
@resetTotal += resetCount
else
@suppliers[supplierId] = null
@resetTotal -= resetCount
$rootScope.resetTotal = @resetTotal

View File

@@ -1 +1 @@
angular.module("admin.products", [])
angular.module("admin.products", ["admin.utils"])

View File

@@ -0,0 +1 @@
angular.module("admin.resources", ['ngResource'])

View File

@@ -1,4 +1,4 @@
angular.module("admin.customers").factory 'CustomerResource', ($resource) ->
angular.module("admin.resources").factory 'CustomerResource', ($resource) ->
$resource('/admin/customers/:id.json', {}, {
'index':
method: 'GET'

View File

@@ -1,4 +1,4 @@
angular.module("admin.enterprises").factory 'EnterpriseResource', ($resource) ->
angular.module("admin.resources").factory 'EnterpriseResource', ($resource) ->
ignoredAttrs = ->
["$$hashKey", "producer", "package", "producerError", "packageError", "status"]

View File

@@ -1,4 +1,4 @@
angular.module("admin.lineItems").factory 'LineItemResource', ($resource) ->
angular.module("admin.resources").factory 'LineItemResource', ($resource) ->
$resource('/admin/:orders/:order_number/line_items/:id.json', {}, {
'index':
method: 'GET'

View File

@@ -1,4 +1,4 @@
angular.module("admin.orderCycles").factory 'OrderCycleResource', ($resource) ->
angular.module("admin.resources").factory 'OrderCycleResource', ($resource) ->
$resource('/admin/order_cycles/:id/:action.json', {}, {
'index':
method: 'GET'

View File

@@ -1,4 +1,4 @@
angular.module("admin.orders").factory 'OrderResource', ($resource) ->
angular.module("admin.resources").factory 'OrderResource', ($resource) ->
$resource('/admin/orders/:id/:action.json', {}, {
'index':
method: 'GET'

View File

@@ -1,19 +1,24 @@
angular.module("admin.customers").factory "Customers", ($q, InfoDialog, RequestMonitor, CustomerResource, CurrentShop) ->
angular.module("admin.resources").factory "Customers", ($q, InfoDialog, RequestMonitor, CustomerResource, CurrentShop) ->
new class Customers
customers: []
all: []
byID: {}
pristineByID: {}
add: (email) ->
params =
enterprise_id: CurrentShop.shop.id
email: email
CustomerResource.create params, (customer) =>
@customers.unshift customer if customer.id
if customer.id
@all.unshift customer
@byID[customer.id] = customer
@pristineByID[customer.id] = angular.copy(customer)
remove: (customer) ->
params = id: customer.id
CustomerResource.destroy params, =>
i = @customers.indexOf customer
@customers.splice i, 1 unless i < 0
i = @all.indexOf customer
@all.splice i, 1 unless i < 0
, (response) =>
errors = response.data.errors
if errors?
@@ -22,10 +27,17 @@ angular.module("admin.customers").factory "Customers", ($q, InfoDialog, RequestM
InfoDialog.open 'error', "Could not delete customer: #{customer.email}"
index: (params) ->
request = CustomerResource.index(params, (data) => @customers = data)
@clear()
request = CustomerResource.index(params, (data) => @load(data))
RequestMonitor.load(request.$promise)
request.$promise
load: (customers) ->
for customer in customers
@all.push customer
@byID[customer.id] = customer
@pristineByID[customer.id] = angular.copy(customer)
update: (address, customer, addressType) ->
params =
id: customer.id
@@ -33,3 +45,5 @@ angular.module("admin.customers").factory "Customers", ($q, InfoDialog, RequestM
"#{addressType}_attributes": address
CustomerResource.update params
clear: ->
@all.length = 0

View File

@@ -1,21 +1,18 @@
angular.module("admin.enterprises").factory 'Enterprises', ($q, EnterpriseResource, blankOption) ->
angular.module("admin.resources").factory 'Enterprises', ($q, EnterpriseResource) ->
new class Enterprises
enterprisesByID: {}
byID: {}
pristineByID: {}
index: (params={}, callback=null) ->
includeBlank = !!params['includeBlank']
delete params['includeBlank']
EnterpriseResource.index(params, (data) =>
for enterprise in data
@enterprisesByID[enterprise.id] = enterprise
@pristineByID[enterprise.id] = angular.copy(enterprise)
EnterpriseResource.index params, (data) =>
@load(data)
(callback || angular.noop)(data)
data.unshift(blankOption()) if includeBlank
data
)
load: (enterprises) ->
for enterprise in enterprises
@byID[enterprise.id] = enterprise
@pristineByID[enterprise.id] = angular.copy(enterprise)
save: (enterprise) ->
deferred = $q.defer()

View File

@@ -1,23 +1,25 @@
angular.module("admin.lineItems").factory 'LineItems', ($q, LineItemResource) ->
angular.module("admin.resources").factory 'LineItems', ($q, LineItemResource) ->
new class LineItems
lineItemsByID: {}
byID: {}
pristineByID: {}
index: (params={}, callback=null) ->
LineItemResource.index params, (data) =>
@resetData()
for lineItem in data
@lineItemsByID[lineItem.id] = lineItem
@pristineByID[lineItem.id] = angular.copy(lineItem)
@load(data)
(callback || angular.noop)(data)
resetData: ->
@lineItemsByID = {}
@byID = {}
@pristineByID = {}
load: (lineItems) ->
@resetData()
for lineItem in lineItems
@byID[lineItem.id] = lineItem
@pristineByID[lineItem.id] = angular.copy(lineItem)
saveAll: ->
for id, lineItem of @lineItemsByID
for id, lineItem of @byID
lineItem.errors = {} # removes errors when line_item has been returned to original state
@save(lineItem) if !@isSaved(lineItem)
@@ -34,7 +36,7 @@ angular.module("admin.lineItems").factory 'LineItems', ($q, LineItemResource) ->
deferred.promise
allSaved: ->
for id, lineItem of @lineItemsByID
for id, lineItem of @byID
return false unless @isSaved(lineItem)
true
@@ -54,7 +56,7 @@ angular.module("admin.lineItems").factory 'LineItems', ($q, LineItemResource) ->
deferred = $q.defer()
lineItem.$delete({id: lineItem.id, orders: "orders", order_number: lineItem.order.number})
.then( (data) =>
delete @lineItemsByID[lineItem.id]
delete @byID[lineItem.id]
delete @pristineByID[lineItem.id]
(callback || angular.noop)(data)
deferred.resolve(data)

View File

@@ -1,21 +1,24 @@
angular.module("admin.orderCycles").factory 'OrderCycles', ($q, OrderCycleResource, blankOption) ->
angular.module("admin.resources").factory 'OrderCycles', ($q, $injector, OrderCycleResource) ->
new class OrderCycles
orderCyclesByID: {}
all: []
byID: {}
pristineByID: {}
constructor: ->
if $injector.has('orderCycles')
@load($injector.get('orderCycles'))
index: (params={}, callback=null) ->
includeBlank = !!params['includeBlank']
delete params['includeBlank']
OrderCycleResource.index(params, (data) =>
for orderCycle in data
@orderCyclesByID[orderCycle.id] = orderCycle
@pristineByID[orderCycle.id] = angular.copy(orderCycle)
OrderCycleResource.index params, (data) =>
@load(data)
(callback || angular.noop)(data)
data.unshift(blankOption()) if includeBlank
data
)
load: (orderCycles) ->
for orderCycle in orderCycles
@all.push orderCycle
@byID[orderCycle.id] = orderCycle
@pristineByID[orderCycle.id] = angular.copy(orderCycle)
save: (order_cycle) ->
deferred = $q.defer()

View File

@@ -1,16 +1,18 @@
angular.module("admin.orders").factory 'Orders', ($q, OrderResource) ->
angular.module("admin.resources").factory 'Orders', ($q, OrderResource) ->
new class Orders
ordersByID: {}
byID: {}
pristineByID: {}
index: (params={}, callback=null) ->
OrderResource.index params, (data) =>
for order in data
@ordersByID[order.id] = order
@pristineByID[order.id] = angular.copy(order)
@load(data)
(callback || angular.noop)(data)
load: (orders) ->
for order in orders
@byID[order.id] = order
@pristineByID[order.id] = angular.copy(order)
save: (order) ->
deferred = $q.defer()
order.$update({id: order.number})

View File

@@ -0,0 +1,16 @@
angular.module("admin.resources")
.factory "PaymentMethods", ($injector) ->
new class PaymentMethods
paymentMethods: []
byID: {}
pristineByID: {}
constructor: ->
if $injector.has('paymentMethods')
@load($injector.get('paymentMethods'))
load: (paymentMethods) ->
for paymentMethod in paymentMethods
@paymentMethods.push paymentMethod
@byID[paymentMethod.id] = paymentMethod
@pristineByID[paymentMethod.id] = angular.copy(paymentMethod)

View File

@@ -0,0 +1,16 @@
angular.module("admin.resources")
.factory "ShippingMethods", ($injector) ->
new class ShippingMethods
shippingMethods: []
byID: {}
pristineByID: {}
constructor: ->
if $injector.has('shippingMethods')
@load($injector.get('shippingMethods'))
load: (shippingMethods) ->
for shippingMethod in shippingMethods
@shippingMethods.push shippingMethod
@byID[shippingMethod.id] = shippingMethod
@pristineByID[shippingMethod.id] = angular.copy(shippingMethod)

View File

@@ -1,3 +1,3 @@
angular.module("admin.shippingMethods").controller "shippingMethodsCtrl", ($scope, ShippingMethods) ->
$scope.findShippingMethodByID = (id) ->
$scope.ShippingMethod = ShippingMethods.findByID(id)
$scope.ShippingMethod = ShippingMethods.byID[id]

View File

@@ -1,8 +0,0 @@
angular.module("admin.shippingMethods")
.factory "ShippingMethods", (shippingMethods) ->
new class ShippingMethods
shippingMethods: shippingMethods
findByID: (id) ->
for shippingMethod in @shippingMethods
return shippingMethod if shippingMethod.id is id

View File

@@ -38,7 +38,6 @@ angular.module("admin.tagRules").controller "TagRulesCtrl", ($scope, $http, $fil
newRule.peferred_exchange_tags = []
newRule.preferred_matched_order_cycles_visibility = "visible"
tagGroup.rules.push(newRule)
$scope.enterprise_form.$setDirty()
$scope.updateRuleCounts()
$scope.addNewTag = ->
@@ -58,3 +57,4 @@ angular.module("admin.tagRules").controller "TagRulesCtrl", ($scope, $http, $fil
.success ->
tagGroup.rules.splice(index, 1)
$scope.updateRuleCounts()
$scope.enterprise_form.$setDirty()

View File

@@ -1,19 +1,20 @@
angular.module("admin.taxons").factory "Taxons", (taxons, $filter) ->
new class Taxons
taxons: taxons
taxonsByID: {}
all: []
byID: {}
constructor: ->
for taxon in @taxons
@taxonsByID[taxon.id] = taxon
for taxon in taxons
@all.push taxon
@byID[taxon.id] = taxon
# For finding a single Taxon
findByID: (id) ->
@taxonsByID[id]
@byID[id]
# For finding multiple Taxons represented by comma delimited string
findByIDs: (ids) ->
@taxonsByID[taxon_id] for taxon_id in ids.split(",") when @taxonsByID[taxon_id]
@byID[taxon_id] for taxon_id in ids.split(",") when @byID[taxon_id]
findByTerm: (term) ->
$filter('filter')(@taxons, term)
$filter('filter')(@all, term)

View File

@@ -30,8 +30,16 @@ show_flash_error = function(message) {
}
$(document).ready(function(){
$('a.close').click(function(event){
event.preventDefault();
$(this).parent().slideUp(250);
});
$('a.close').click(function(event){
event.preventDefault();
$(this).parent().slideUp(250);
});
// Spree locates hidden with prev(), which with our current version of jQuery
// does not locate the hidden field, resulting in the delete failing. This
// handler updates the hidden field, fixing the problem.
$('body').on('click', 'a.remove_fields', function() {
$(this).next("input[type=hidden]").val("1");
return false;
});
});

View File

@@ -1,2 +0,0 @@
angular.module("admin.utils").value "blankOption", ->
{ id: "0", name: "All" }

View File

@@ -10,7 +10,6 @@ angular.module("admin.utils")
$rootScope.$on "$locationChangeStart", @locationChangeStartHandler
# Action for regular browser navigation.
onBeforeUnloadHandler: ($event) =>
message = @getMessage()
@@ -21,13 +20,17 @@ angular.module("admin.utils")
# Action for angular navigation.
locationChangeStartHandler: ($event) =>
message = @getMessage()
if message and not $window.confirm(message)
if not @confirmLeave()
$event.stopPropagation() if $event.stopPropagation
$event.preventDefault() if $event.preventDefault
$event.cancelBubble = true
$event.returnValue = false
# Check if leaving is okay
confirmLeave: =>
message = @getMessage()
!message or $window.confirm(message)
# Runs callback functions to retreive most recently added non-empty message.
getMessage: ->
message = null

View File

@@ -1,11 +1,8 @@
Darkswarm.controller "AccordionCtrl", ($scope, storage, $timeout, $document, CurrentHub) ->
$scope.accordion =
details: true
billing: false
shipping: false
payment: false
Darkswarm.controller "AccordionCtrl", ($scope, localStorageService, $timeout, $document, CurrentHub) ->
key = "accordion_#{$scope.order.id}#{CurrentHub.hub.id}#{$scope.order.user_id}"
value = if localStorageService.get(key) then {} else { details: true, billing: false, shipping: false, payment: false }
localStorageService.bind $scope, "accordion", value, key
$scope.accordionSections = ["details", "billing", "shipping", "payment"]
storage.bind $scope, "accordion", {storeName: "accordion_#{$scope.order.id}#{CurrentHub.hub.id}#{$scope.order.user_id}"}
$scope.show = (section)->
$scope.accordion[section] = true

View File

@@ -1,4 +1,4 @@
Darkswarm.controller "CheckoutCtrl", ($scope, storage, Checkout, CurrentUser, CurrentHub) ->
Darkswarm.controller "CheckoutCtrl", ($scope, localStorageService, Checkout, CurrentUser, CurrentHub) ->
$scope.Checkout = Checkout
$scope.submitted = false
@@ -7,11 +7,11 @@ Darkswarm.controller "CheckoutCtrl", ($scope, storage, Checkout, CurrentUser, Cu
prefix = "order_#{Checkout.order.id}#{CurrentUser.id or ""}#{CurrentHub.hub.id}"
for field in $scope.fieldsToBind
storage.bind $scope, "Checkout.order.#{field}",
storeName: "#{prefix}_#{field}"
storage.bind $scope, "Checkout.ship_address_same_as_billing",
storeName: "#{prefix}_sameasbilling"
defaultValue: true
localStorageService.bind $scope, "Checkout.order.#{field}", Checkout.order[field], "#{prefix}_#{field}"
localStorageService.bind $scope, "Checkout.ship_address_same_as_billing", true, "#{prefix}_sameasbilling"
localStorageService.bind $scope, "Checkout.default_bill_address", false, "#{prefix}_defaultasbilladdress"
localStorageService.bind $scope, "Checkout.default_ship_address", false, "#{prefix}_defaultasshipaddress"
$scope.order = Checkout.order # Ordering is important
$scope.secrets = Checkout.secrets

View File

@@ -1,4 +1,4 @@
Darkswarm.controller "ShoppingTabsCtrl", ($scope, $controller, Navigation) ->
Darkswarm.controller "ShoppingTabsCtrl", ($scope, $controller, Navigation, $location) ->
angular.extend this, $controller('TabsCtrl', {$scope: $scope})
$scope.tabs =
@@ -6,3 +6,7 @@ Darkswarm.controller "ShoppingTabsCtrl", ($scope, $controller, Navigation) ->
producers: { active: Navigation.isActive('/producers') }
contact: { active: Navigation.isActive('/contact') }
groups: { active: Navigation.isActive('/groups') }
$scope.$on '$locationChangeStart', (event, url) ->
tab = $location.path().replace(/^\//, '')
$scope.tabs[tab]?.active = true

View File

@@ -1,6 +1,6 @@
window.Darkswarm = angular.module("Darkswarm", ["ngResource",
'mm.foundation',
'angularLocalStorage',
'LocalStorageModule',
'infinite-scroll',
'angular-flash.service',
'templates',

View File

@@ -1,4 +1,4 @@
Darkswarm.directive "ofnChangeOrderCycle", (OrderCycle, Cart, storage) ->
Darkswarm.directive "ofnChangeOrderCycle", (OrderCycle, Cart) ->
# Compares chosen order cycle with pre-set OrderCycle. Will trigger
# a confirmation if they are different, and Cart isn't empty
restrict: "A"

View File

@@ -15,7 +15,7 @@ Darkswarm.directive 'mapOsmTiles', ($timeout) ->
if x < 0
x = tilesPerGlobe + x
# Wrap y (latitude) in a like manner if you want to enable vertical infinite scroll
'http://tile.openstreetmap.org/' + zoom + '/' + x + '/' + coord.y + '.png'
'https://a.tile.openstreetmap.org/' + zoom + '/' + x + '/' + coord.y + '.png'
tileSize: new google.maps.Size(256, 256)
name: 'OpenStreetMap'
maxZoom: 18

View File

@@ -4,5 +4,5 @@ Darkswarm.filter 'products', (Matcher) ->
text ?= ""
return products if text == ""
products.filter (product) =>
propertiesToMatch = [product.name, product.supplier.name, product.primary_taxon.name]
propertiesToMatch = [product.name, product.variant_names, product.supplier.name, product.primary_taxon.name]
Matcher.match propertiesToMatch, text

View File

@@ -1,13 +1,17 @@
Darkswarm.filter 'properties', ->
# Filter anything that responds to object.supplied_properties
(objects, ids) ->
(objects, ids, source) ->
objects ||= []
ids ?= []
source ||= 'properties'
return [] unless source in ['properties', 'supplied_properties', 'distributed_properties']
if ids.length == 0
# No properties selected, pass all objects through.
objects
else
objects.filter (obj) ->
properties = obj.supplied_properties || obj.properties
properties = obj[source]
properties.some (property) ->
property.id in ids

View File

@@ -1,12 +1,12 @@
Darkswarm.filter 'propertiesOf', ->
(objects) ->
(objects, source) ->
source ||= 'properties'
return {} unless source in ['properties', 'supplied_properties', 'distributed_properties']
properties = {}
for object in objects
if object.supplied_properties?
for property in object.supplied_properties
properties[property.id] = property
else
for property of object.properties
if object[source]?
for property in object[source]
properties[property.id] = property
properties

View File

@@ -1,4 +1,4 @@
Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $rootScope, storage)->
Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $rootScope, localStorageService)->
# Handles syncing of current cart/order state to server
new class Cart
dirty: false
@@ -114,4 +114,4 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $roo
clear: ->
@line_items = []
storage.clearAll() # One day this will have to be moar GRANULAR
localStorageService.clearAll() # One day this will have to be moar GRANULAR

View File

@@ -3,7 +3,6 @@ Darkswarm.factory 'Checkout', (CurrentOrder, ShippingMethods, PaymentMethods, $h
errors: {}
secrets: {}
order: CurrentOrder.order
ship_address_same_as_billing: true
submit: ->
Loading.message = t 'submitting_order'
@@ -19,7 +18,10 @@ Darkswarm.factory 'Checkout', (CurrentOrder, ShippingMethods, PaymentMethods, $h
# Rails wants our Spree::Address data to be provided with _attributes
preprocess: ->
munged_order = {}
munged_order =
default_bill_address: !!@default_bill_address
default_ship_address: !!@default_ship_address
for name, value of @order # Clone all data from the order JSON object
switch name
when "bill_address"

View File

@@ -25,7 +25,6 @@ Darkswarm.factory 'Products', ($resource, Enterprises, Dereferencer, Taxons, Pro
prices = (v.price for v in product.variants)
product.price = Math.min.apply(null, prices)
product.hasVariants = product.variants?.length > 0
product.primaryImage = product.images[0]?.small_url if product.images
product.primaryImageOrMissing = product.primaryImage || "/assets/noimage/small.png"
product.largeImage = product.images[0]?.large_url if product.images
@@ -45,5 +44,7 @@ Darkswarm.factory 'Products', ($resource, Enterprises, Dereferencer, Taxons, Pro
if product.variants
product.variants = for variant in product.variants
variant = Variants.register variant
if product.name != variant.name_to_display
product.variant_names += variant.name_to_display
variant.product = product
variant

View File

@@ -1,171 +1,546 @@
/*
* Angular.js localStorage module
* https://github.com/agrublev/angularLocalStorage
/**
* An Angular module that gives you access to the browsers local storage
* @version v0.5.0 - 2016-08-29
* @link https://github.com/grevory/angular-local-storage
* @author grevory <greg@gregpike.ca>
* @license MIT License, http://www.opensource.org/licenses/MIT
*/
(function (window, angular) {
var isDefined = angular.isDefined,
isUndefined = angular.isUndefined,
isNumber = angular.isNumber,
isObject = angular.isObject,
isArray = angular.isArray,
extend = angular.extend,
toJson = angular.toJson;
(function (window, angular, undefined) {
'use strict';
angular
.module('LocalStorageModule', [])
.provider('localStorageService', function() {
// You should set a prefix to avoid overwriting any local storage variables from the rest of your app
// e.g. localStorageServiceProvider.setPrefix('yourAppName');
// With provider you can use config as this:
// myApp.config(function (localStorageServiceProvider) {
// localStorageServiceProvider.prefix = 'yourAppName';
// });
this.prefix = 'ls';
angular.module('angularLocalStorage', ['ngCookies']).factory('storage', ['$parse', '$cookieStore', '$window', '$log', function ($parse, $cookieStore, $window, $log) {
/**
* Global Vars
*/
var storage = (typeof $window.localStorage === 'undefined') ? undefined : $window.localStorage;
var supported = typeof storage !== 'undefined';
// You could change web storage type localstorage or sessionStorage
this.storageType = 'localStorage';
var privateMethods = {
/**
* Pass any type of a string from the localStorage to be parsed so it returns a usable version (like an Object)
* @param res - a string that will be parsed for type
* @returns {*} - whatever the real type of stored value was
*/
parseValue: function (res) {
var val;
try {
val = angular.fromJson(res);
if (typeof val === 'undefined') {
val = res;
}
if (val === 'true') {
val = true;
}
if (val === 'false') {
val = false;
}
if ($window.parseFloat(val) === val && !angular.isObject(val)) {
val = $window.parseFloat(val);
}
} catch (e) {
val = res;
}
return val;
}
};
// Cookie options (usually in case of fallback)
// expiry = Number of days before cookies expire // 0 = Does not expire
// path = The web path the cookie represents
// secure = Wether the cookies should be secure (i.e only sent on HTTPS requests)
this.cookie = {
expiry: 30,
path: '/',
secure: false
};
var publicMethods = {
/**
* Set - let's you set a new localStorage key pair set
* @param key - a string that will be used as the accessor for the pair
* @param value - the value of the localStorage item
* @returns {*} - will return whatever it is you've stored in the local storage
*/
set: function (key, value) {
if (!supported) {
try {
$cookieStore.put(key, value);
return value;
} catch(e) {
$log.log('Local Storage not supported, make sure you have angular-cookies enabled.');
}
}
var saver = angular.toJson(value);
storage.setItem(key, saver);
return privateMethods.parseValue(saver);
},
// Decides wether we should default to cookies if localstorage is not supported.
this.defaultToCookie = true;
/**
* Get - let's you get the value of any pair you've stored
* @param key - the string that you set as accessor for the pair
* @returns {*} - Object,String,Float,Boolean depending on what you stored
*/
get: function (key) {
if (!supported) {
try {
return privateMethods.parseValue($.cookie(key));
} catch (e) {
return null;
}
}
var item = storage.getItem(key);
return privateMethods.parseValue(item);
},
// Send signals for each of the following actions?
this.notify = {
setItem: true,
removeItem: false
};
/**
* Remove - let's you nuke a value from localStorage
* @param key - the accessor value
* @returns {boolean} - if everything went as planned
*/
remove: function (key) {
if (!supported) {
try {
$cookieStore.remove(key);
return true;
} catch (e) {
return false;
}
}
storage.removeItem(key);
return true;
},
// Setter for the prefix
this.setPrefix = function(prefix) {
this.prefix = prefix;
return this;
};
/**
* Bind - let's you directly bind a localStorage value to a $scope variable
* @param {Angular $scope} $scope - the current scope you want the variable available in
* @param {String} key - the name of the variable you are binding
* @param {Object} opts - (optional) custom options like default value or unique store name
* Here are the available options you can set:
* * defaultValue: the default value
* * storeName: add a custom store key value instead of using the scope variable name
* @returns {*} - returns whatever the stored value is
*/
bind: function ($scope, key, opts) {
var defaultOpts = {
defaultValue: '',
storeName: ''
};
// Backwards compatibility with old defaultValue string
if (angular.isString(opts)) {
opts = angular.extend({},defaultOpts,{defaultValue:opts});
} else {
// If no defined options we use defaults otherwise extend defaults
opts = (angular.isUndefined(opts)) ? defaultOpts : angular.extend(defaultOpts,opts);
}
// Setter for the storageType
this.setStorageType = function(storageType) {
this.storageType = storageType;
return this;
};
// Setter for defaultToCookie value, default is true.
this.setDefaultToCookie = function (shouldDefault) {
this.defaultToCookie = !!shouldDefault; // Double-not to make sure it's a bool value.
return this;
};
// Setter for cookie config
this.setStorageCookie = function(exp, path, secure) {
this.cookie.expiry = exp;
this.cookie.path = path;
this.cookie.secure = secure;
return this;
};
// Set the storeName key for the localStorage entry
// use user defined in specified
var storeName = opts.storeName || key;
// Setter for cookie domain
this.setStorageCookieDomain = function(domain) {
this.cookie.domain = domain;
return this;
};
// If a value doesn't already exist store it as is
if (!publicMethods.get(storeName)) {
publicMethods.set(storeName, $parse(key)($scope) || opts.defaultValue);
} else {
// If it does exist assign it to the $scope value
$parse(key).assign($scope, publicMethods.get(storeName));
// Setter for notification config
// itemSet & itemRemove should be booleans
this.setNotify = function(itemSet, itemRemove) {
this.notify = {
setItem: itemSet,
removeItem: itemRemove
};
return this;
};
this.$get = ['$rootScope', '$window', '$document', '$parse','$timeout', function($rootScope, $window, $document, $parse, $timeout) {
var self = this;
var prefix = self.prefix;
var cookie = self.cookie;
var notify = self.notify;
var storageType = self.storageType;
var webStorage;
// When Angular's $document is not available
if (!$document) {
$document = document;
} else if ($document[0]) {
$document = $document[0];
}
// If there is a prefix set in the config lets use that with an appended period for readability
if (prefix.substr(-1) !== '.') {
prefix = !!prefix ? prefix + '.' : '';
}
var deriveQualifiedKey = function(key) {
return prefix + key;
};
// Removes prefix from the key.
var underiveQualifiedKey = function (key) {
return key.replace(new RegExp('^' + prefix, 'g'), '');
};
// Check if the key is within our prefix namespace.
var isKeyPrefixOurs = function (key) {
return key.indexOf(prefix) === 0;
};
// Checks the browser to see if local storage is supported
var checkSupport = function () {
try {
var supported = (storageType in $window && $window[storageType] !== null);
// When Safari (OS X or iOS) is in private browsing mode, it appears as though localStorage
// is available, but trying to call .setItem throws an exception.
//
// "QUOTA_EXCEEDED_ERR: DOM Exception 22: An attempt was made to add something to storage
// that exceeded the quota."
var key = deriveQualifiedKey('__' + Math.round(Math.random() * 1e7));
if (supported) {
webStorage = $window[storageType];
webStorage.setItem(key, '');
webStorage.removeItem(key);
}
return supported;
} catch (e) {
// Only change storageType to cookies if defaulting is enabled.
if (self.defaultToCookie)
storageType = 'cookie';
$rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
return false;
}
};
var browserSupportsLocalStorage = checkSupport();
// Directly adds a value to local storage
// If local storage is not available in the browser use cookies
// Example use: localStorageService.add('library','angular');
var addToLocalStorage = function (key, value, type) {
setStorageType(type);
// Let's convert undefined values to null to get the value consistent
if (isUndefined(value)) {
value = null;
} else {
value = toJson(value);
}
// If this browser does not support local storage use cookies
if (!browserSupportsLocalStorage && self.defaultToCookie || self.storageType === 'cookie') {
if (!browserSupportsLocalStorage) {
$rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
}
// Register a listener for changes on the $scope value
// to update the localStorage value
$scope.$watch(key, function (val) {
if (angular.isDefined(val)) {
publicMethods.set(storeName, val);
}
}, true);
if (notify.setItem) {
$rootScope.$broadcast('LocalStorageModule.notification.setitem', {key: key, newvalue: value, storageType: 'cookie'});
}
return addToCookies(key, value);
}
return publicMethods.get(storeName);
},
/**
* Unbind - let's you unbind a variable from localStorage while removing the value from both
* the localStorage and the local variable and sets it to null
* @param $scope - the scope the variable was initially set in
* @param key - the name of the variable you are unbinding
* @param storeName - (optional) if you used a custom storeName you will have to specify it here as well
*/
unbind: function($scope,key,storeName) {
storeName = storeName || key;
$parse(key).assign($scope, null);
$scope.$watch(key, function () { });
publicMethods.remove(storeName);
},
/**
* Clear All - let's you clear out ALL localStorage variables, use this carefully!
*/
clearAll: function() {
storage.clear();
}
};
try {
if (webStorage) {
webStorage.setItem(deriveQualifiedKey(key), value);
}
if (notify.setItem) {
$rootScope.$broadcast('LocalStorageModule.notification.setitem', {key: key, newvalue: value, storageType: self.storageType});
}
} catch (e) {
$rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
return addToCookies(key, value);
}
return true;
};
return publicMethods;
}]);
// Directly get a value from local storage
// Example use: localStorageService.get('library'); // returns 'angular'
var getFromLocalStorage = function (key, type) {
setStorageType(type);
if (!browserSupportsLocalStorage && self.defaultToCookie || self.storageType === 'cookie') {
if (!browserSupportsLocalStorage) {
$rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
}
return getFromCookies(key);
}
var item = webStorage ? webStorage.getItem(deriveQualifiedKey(key)) : null;
// angular.toJson will convert null to 'null', so a proper conversion is needed
// FIXME not a perfect solution, since a valid 'null' string can't be stored
if (!item || item === 'null') {
return null;
}
try {
return JSON.parse(item);
} catch (e) {
return item;
}
};
// Remove an item from local storage
// Example use: localStorageService.remove('library'); // removes the key/value pair of library='angular'
//
// This is var-arg removal, check the last argument to see if it is a storageType
// and set type accordingly before removing.
//
var removeFromLocalStorage = function () {
// can't pop on arguments, so we do this
var consumed = 0;
if (arguments.length >= 1 &&
(arguments[arguments.length - 1] === 'localStorage' ||
arguments[arguments.length - 1] === 'sessionStorage')) {
consumed = 1;
setStorageType(arguments[arguments.length - 1]);
}
var i, key;
for (i = 0; i < arguments.length - consumed; i++) {
key = arguments[i];
if (!browserSupportsLocalStorage && self.defaultToCookie || self.storageType === 'cookie') {
if (!browserSupportsLocalStorage) {
$rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
}
if (notify.removeItem) {
$rootScope.$broadcast('LocalStorageModule.notification.removeitem', {key: key, storageType: 'cookie'});
}
removeFromCookies(key);
}
else {
try {
webStorage.removeItem(deriveQualifiedKey(key));
if (notify.removeItem) {
$rootScope.$broadcast('LocalStorageModule.notification.removeitem', {
key: key,
storageType: self.storageType
});
}
} catch (e) {
$rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
removeFromCookies(key);
}
}
}
};
// Return array of keys for local storage
// Example use: var keys = localStorageService.keys()
var getKeysForLocalStorage = function (type) {
setStorageType(type);
if (!browserSupportsLocalStorage) {
$rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
return [];
}
var prefixLength = prefix.length;
var keys = [];
for (var key in webStorage) {
// Only return keys that are for this app
if (key.substr(0, prefixLength) === prefix) {
try {
keys.push(key.substr(prefixLength));
} catch (e) {
$rootScope.$broadcast('LocalStorageModule.notification.error', e.Description);
return [];
}
}
}
return keys;
};
// Remove all data for this app from local storage
// Also optionally takes a regular expression string and removes the matching key-value pairs
// Example use: localStorageService.clearAll();
// Should be used mostly for development purposes
var clearAllFromLocalStorage = function (regularExpression, type) {
setStorageType(type);
// Setting both regular expressions independently
// Empty strings result in catchall RegExp
var prefixRegex = !!prefix ? new RegExp('^' + prefix) : new RegExp();
var testRegex = !!regularExpression ? new RegExp(regularExpression) : new RegExp();
if (!browserSupportsLocalStorage && self.defaultToCookie || self.storageType === 'cookie') {
if (!browserSupportsLocalStorage) {
$rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
}
return clearAllFromCookies();
}
if (!browserSupportsLocalStorage && !self.defaultToCookie)
return false;
var prefixLength = prefix.length;
for (var key in webStorage) {
// Only remove items that are for this app and match the regular expression
if (prefixRegex.test(key) && testRegex.test(key.substr(prefixLength))) {
try {
removeFromLocalStorage(key.substr(prefixLength));
} catch (e) {
$rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
return clearAllFromCookies();
}
}
}
return true;
};
// Checks the browser to see if cookies are supported
var browserSupportsCookies = (function() {
try {
return $window.navigator.cookieEnabled ||
("cookie" in $document && ($document.cookie.length > 0 ||
($document.cookie = "test").indexOf.call($document.cookie, "test") > -1));
} catch (e) {
$rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
return false;
}
}());
// Directly adds a value to cookies
// Typically used as a fallback if local storage is not available in the browser
// Example use: localStorageService.cookie.add('library','angular');
var addToCookies = function (key, value, daysToExpiry, secure) {
if (isUndefined(value)) {
return false;
} else if(isArray(value) || isObject(value)) {
value = toJson(value);
}
if (!browserSupportsCookies) {
$rootScope.$broadcast('LocalStorageModule.notification.error', 'COOKIES_NOT_SUPPORTED');
return false;
}
try {
var expiry = '',
expiryDate = new Date(),
cookieDomain = '';
if (value === null) {
// Mark that the cookie has expired one day ago
expiryDate.setTime(expiryDate.getTime() + (-1 * 24 * 60 * 60 * 1000));
expiry = "; expires=" + expiryDate.toGMTString();
value = '';
} else if (isNumber(daysToExpiry) && daysToExpiry !== 0) {
expiryDate.setTime(expiryDate.getTime() + (daysToExpiry * 24 * 60 * 60 * 1000));
expiry = "; expires=" + expiryDate.toGMTString();
} else if (cookie.expiry !== 0) {
expiryDate.setTime(expiryDate.getTime() + (cookie.expiry * 24 * 60 * 60 * 1000));
expiry = "; expires=" + expiryDate.toGMTString();
}
if (!!key) {
var cookiePath = "; path=" + cookie.path;
if (cookie.domain) {
cookieDomain = "; domain=" + cookie.domain;
}
/* Providing the secure parameter always takes precedence over config
* (allows developer to mix and match secure + non-secure) */
if (typeof secure === 'boolean') {
if (secure === true) {
/* We've explicitly specified secure,
* add the secure attribute to the cookie (after domain) */
cookieDomain += "; secure";
}
// else - secure has been supplied but isn't true - so don't set secure flag, regardless of what config says
}
else if (cookie.secure === true) {
// secure parameter wasn't specified, get default from config
cookieDomain += "; secure";
}
$document.cookie = deriveQualifiedKey(key) + "=" + encodeURIComponent(value) + expiry + cookiePath + cookieDomain;
}
} catch (e) {
$rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
return false;
}
return true;
};
// Directly get a value from a cookie
// Example use: localStorageService.cookie.get('library'); // returns 'angular'
var getFromCookies = function (key) {
if (!browserSupportsCookies) {
$rootScope.$broadcast('LocalStorageModule.notification.error', 'COOKIES_NOT_SUPPORTED');
return false;
}
var cookies = $document.cookie && $document.cookie.split(';') || [];
for(var i=0; i < cookies.length; i++) {
var thisCookie = cookies[i];
while (thisCookie.charAt(0) === ' ') {
thisCookie = thisCookie.substring(1,thisCookie.length);
}
if (thisCookie.indexOf(deriveQualifiedKey(key) + '=') === 0) {
var storedValues = decodeURIComponent(thisCookie.substring(prefix.length + key.length + 1, thisCookie.length));
try {
return JSON.parse(storedValues);
} catch(e) {
return storedValues;
}
}
}
return null;
};
var removeFromCookies = function (key) {
addToCookies(key,null);
};
var clearAllFromCookies = function () {
var thisCookie = null;
var prefixLength = prefix.length;
var cookies = $document.cookie.split(';');
for(var i = 0; i < cookies.length; i++) {
thisCookie = cookies[i];
while (thisCookie.charAt(0) === ' ') {
thisCookie = thisCookie.substring(1, thisCookie.length);
}
var key = thisCookie.substring(prefixLength, thisCookie.indexOf('='));
removeFromCookies(key);
}
};
var getStorageType = function() {
return storageType;
};
var setStorageType = function(type) {
if (type && storageType !== type) {
storageType = type;
browserSupportsLocalStorage = checkSupport();
}
return browserSupportsLocalStorage;
};
// Add a listener on scope variable to save its changes to local storage
// Return a function which when called cancels binding
var bindToScope = function(scope, key, def, lsKey, type) {
lsKey = lsKey || key;
var value = getFromLocalStorage(lsKey, type);
if (value === null && isDefined(def)) {
value = def;
} else if (isObject(value) && isObject(def)) {
value = extend(value, def);
}
$parse(key).assign(scope, value);
return scope.$watch(key, function(newVal) {
addToLocalStorage(lsKey, newVal, type);
}, isObject(scope[key]));
};
// Add listener to local storage, for update callbacks.
if (browserSupportsLocalStorage) {
if ($window.addEventListener) {
$window.addEventListener("storage", handleStorageChangeCallback, false);
$rootScope.$on('$destroy', function() {
$window.removeEventListener("storage", handleStorageChangeCallback);
});
} else if($window.attachEvent){
// attachEvent and detachEvent are proprietary to IE v6-10
$window.attachEvent("onstorage", handleStorageChangeCallback);
$rootScope.$on('$destroy', function() {
$window.detachEvent("onstorage", handleStorageChangeCallback);
});
}
}
// Callback handler for storage changed.
function handleStorageChangeCallback(e) {
if (!e) { e = $window.event; }
if (notify.setItem) {
if (isKeyPrefixOurs(e.key)) {
var key = underiveQualifiedKey(e.key);
// Use timeout, to avoid using $rootScope.$apply.
$timeout(function () {
$rootScope.$broadcast('LocalStorageModule.notification.changed', { key: key, newvalue: e.newValue, storageType: self.storageType });
});
}
}
}
// Return localStorageService.length
// ignore keys that not owned
var lengthOfLocalStorage = function(type) {
setStorageType(type);
var count = 0;
var storage = $window[storageType];
for(var i = 0; i < storage.length; i++) {
if(storage.key(i).indexOf(prefix) === 0 ) {
count++;
}
}
return count;
};
return {
isSupported: browserSupportsLocalStorage,
getStorageType: getStorageType,
setStorageType: setStorageType,
set: addToLocalStorage,
add: addToLocalStorage, //DEPRECATED
get: getFromLocalStorage,
keys: getKeysForLocalStorage,
remove: removeFromLocalStorage,
clearAll: clearAllFromLocalStorage,
bind: bindToScope,
deriveKey: deriveQualifiedKey,
underiveKey: underiveQualifiedKey,
length: lengthOfLocalStorage,
defaultToCookie: this.defaultToCookie,
cookie: {
isSupported: browserSupportsCookies,
set: addToCookies,
add: addToCookies, //DEPRECATED
get: getFromCookies,
remove: removeFromCookies,
clearAll: clearAllFromCookies
}
};
}];
});
})(window, window.angular);

View File

@@ -11,6 +11,18 @@
%table.no-borders
%tr
%td{style: 'width: 30%'}
= t('spree.firstname')
%span.required *
%td
%input{ type: 'text', name: 'firstname', required: true, ng: { model: 'address.firstname'} }
%tr
%td
= t('spree.lastname')
%span.required *
%td
%input{ type: 'text', name: 'lastname', required: true, ng: { model: 'address.lastname'} }
%tr
%td
= t('spree.street_address')
%span.required *
%td
@@ -20,12 +32,6 @@
= t('spree.street_address_1')
%td
%input{ type: 'text', name: 'address2', ng: { model: 'address.address2'} }
%tr
%td
= t('spree.phone')
%span.required *
%td
%input{ type: 'text', name: 'phone', required: true, ng: { model: 'address.phone'} }
%tr
%td
= t('spree.city')
@@ -43,19 +49,29 @@
= t('spree.country')
%span.required *
%td
%select{name: 'country', required: true, ng: {model: 'address.country_id', options: 'country.id as country.name for country in availableCountries'}}
%select{ name: 'country', required: true, ng: { model: 'address.country_id' } }
%option{value: ''}
= t('admin.customers.index.select_country')
%option{ ng: { repeat: 'country in availableCountries' }, value: '{{country.id}}' }
{{country.name}}
%tr
%td
= t('spree.state')
%span.required *
%td
%select{name: 'state', required: true, ng: {model: 'address.state_id', options: 'state.id as state.name for state in states'}}
%select{ name: 'state', required: true, ng: { model: 'address.state_id' } }
%option{value: ''}
= t('admin.customers.index.select_state')
%option{ ng: { repeat: 'state in states' }, value: '{{state.id}}' }
{{state.name}}
%tr
%td
= t('spree.phone')
%span.required *
%td
%input{ type: 'text', name: 'phone', required: true, ng: { model: 'address.phone'} }
.text-center
%input.button.red.icon-plus{ type: 'submit', value: 'Update Address'}
%input.button.red.icon-plus{ type: 'submit', value: t('admin.customers.index.update_address')}

View File

@@ -1,7 +1,7 @@
.ofn-drop-down
%span
%i.icon-check
Actions
= t('admin.actions')
%i{ 'ng-class' => "expanded && 'icon-caret-up' || !expanded && 'icon-caret-down'" }
%div.menu{ 'ng-show' => "expanded" }
%a.menu_item{ 'ng-repeat' => "link in links", href: '{{link.url}}', target: "{{link.target || '_self'}}", data: { method: "{{ link.method || 'get' }}", confirm: "{{link.confirm}}" } }

View File

@@ -1,18 +1,19 @@
#tag-rule-help
.margin-bottom-30.text-center
.text-big Tag Rules
.text-big
= t('js.admin.modals.tag_rule_help.title')
.margin-bottom-30
.text-normal Overview
%p Tag rules provide a way to describe which items are visible or otherwise to which customers. Items can be Shipping Methods, Payment Methods, Products and Order Cycles.
.text-normal= t('js.admin.modals.tag_rule_help.overview')
%p= t('js.admin.modals.tag_rule_help.overview_text')
.margin-bottom-30
.text-normal 'By Default...' Rules
%p Default rules allow you to hide items so that they are not visible by default. This behaviour can then be overriden by non-default rules for customers with particular tags.
.text-normal= t('js.admin.modals.tag_rule_help.by_default_rules')
%p= t('js.admin.modals.tag_rule_help.by_default_rules_text')
.margin-bottom-30
.text-normal 'Customers Tagged...' Rules
%p By creating rules related to a specific customer tag, you can override the default behaviour (whether it be to show or to hide items) for customers with the specified tag.
.text-normal= t('js.admin.modals.tag_rule_help.customer_tagged_rules')
%p= t('js.admin.modals.tag_rule_help.customer_tagged_rules_text')
.text-center
%input.button.red.icon-plus{ type: 'button', value: 'Got it', ng: { click: 'close()' } }
%input.button.red.icon-plus{ type: 'button', value: t('js.admin.modals.got_it'), ng: { click: 'close()' } }

View File

@@ -1,6 +1,6 @@
#new-tag-rule-dialog
.text-normal.margin-bottom-30.text-center
Select a rule type:
= t('js.admin.new_tag_rule_dialog.select_rule_type')
.text-center.margin-bottom-30
-# %select.fullwidth{ 'select2-min-search' => 5, 'ng-model' => 'newRuleType', 'ng-options' => 'ruleType.id as ruleType.name for ruleType in availableRuleTypes' }

View File

@@ -2,130 +2,128 @@
.alpha.eight.columns
%div{ ng: { if: "!enterprise.is_primary_producer", switch: "enterprise.sells" } }
.info{ ng: { switch: { when: "none" } } }
%h3 Hub Profile
%h3= t('js.admin.panels.enterprise_package.hub_profile')
%p
%strong COST: ALWAYS FREE
%strong= t('js.admin.panels.enterprise_package.hub_profile_cost')
%p People can find and contact you on the Open Food Network. Your enterprise will be visible on the map, and will be searchable in listings.
%p= t('js.admin.panels.enterprise_package.hub_profile_text1')
%p Having a profile, and making connections within your local food system through the Open Food Network will always be free.
%p= t('js.admin.panels.enterprise_package.hub_profile_text2')
.info{ ng: { switch: { when: "any" } } }
%h3 Hub Shop
%h3= t('js.admin.panels.enterprise_package.hub_shop')
%p
%strong
%monthly-pricing-description{ joiner: "comma" }
%p Your enterprise is the backbone of your local food system. You aggregate produce from other enterprises and can sell it through your shop on the Open Food Network.
%p= t('js.admin.panels.enterprise_package.hub_shop_text1')
%p Hubs can take many forms, whether they be a food co-op, a buying group, a veggie-box program, or a local grocery store.
%p= t('js.admin.panels.enterprise_package.hub_shop_text2')
%p If you also want to sell your own products, you will need to switch this enterprise to be a producer.
%p= t('js.admin.panels.enterprise_package.hub_shop_text3')
.info{ ng: { switch: { default: true } } }
%h3
Please Choose a Package
= t('js.admin.panels.enterprise_package.choose_package')
%i.icon-arrow-right
%p
%strong Your enterprise will not be fully activated until a package is selected from the options on the left.
%strong= t('js.admin.panels.enterprise_package.choose_package_text1')
%p
Click on an option to see more detailed information about each package, and hit the red SAVE button when you are done!
= t('js.admin.panels.enterprise_package.choose_package_text2')
%div{ ng: { if: "enterprise.is_primary_producer", switch: "enterprise.sells" } }
.info{ ng: { switch: { when: "none" } } }
%h3 Profile Only
%h3= t('js.admin.panels.enterprise_package.profile_only')
%p
%strong COST: ALWAYS FREE
%strong= t('js.admin.panels.enterprise_package.profile_only_cost')
%p A profile makes you visible and contactable to others and is a way to share your story.
%p= t('js.admin.panels.enterprise_package.profile_only_text1')
%p If you prefer to focus on producing food, and want to leave the work of selling it to someone else, you won't require a shop on the Open Food Network.
%p= t('js.admin.panels.enterprise_package.profile_only_text2')
%p Add your products to Open Food Network, allowing hubs to stock your products in their stores.
%p= t('js.admin.panels.enterprise_package.profile_only_text3')
.info{ ng: { switch: { when: "own" } } }
%h3 Producer Shop
%h3= t('js.admin.panels.enterprise_package.producer_shop')
%p
%strong
%monthly-pricing-description{ joiner: "comma" }
%p Sell your products directly to customers through your very own Open Food Network shopfront.
%p= t('js.admin.panels.enterprise_package.producer_shop_text1')
%p A Producer Shop is for your produce only, if you want to sell produce grown/produced off site, please select 'Producer Hub'.
%p= t('js.admin.panels.enterprise_package.producer_shop_text2')
.info{ ng: { switch: { when: "any" } } }
%h3 Producer Hub
%h3= t('js.admin.panels.enterprise_package.producer_hub')
%p
%strong
%monthly-pricing-description{ joiner: "comma" }
%p Your enterprise is the backbone of your local food system. You can sell your own produce as well as produce aggregated from other enterprises through your shopfront on the Open Food Network.
%p= t('js.admin.panels.enterprise_package.producer_hub_text1')
%p Producer Hubs can take many forms, whether they be a CSA, a veggie-box program, or a food co-op with a rooftop garden.
%p= t('js.admin.panels.enterprise_package.producer_hub_text2')
%p The Open Food Network aims to support as many hub models as possible, so no matter your situation, we want to provide the tools you need to run your organisation or local food business.
%p= t('js.admin.panels.enterprise_package.producer_hub_text3')
.info{ ng: { switch: { default: true } } }
%h3
Please Choose a Package
= t('js.admin.panels.enterprise_package.choose_package')
%i.icon-arrow-right
%p
%strong Your producer enterprise will not be fully activated until a package is selected from the options on the left.
%strong= t('js.admin.panels.enterprise_package.choose_package_text1')
%p
Click on an option to see more detailed information about each package, and hit the red SAVE button when you are done!
= t('js.admin.panels.enterprise_package.choose_package_text2')
.omega.eight.columns{ ng: { switch: "enterprise.is_primary_producer" } }
%div{ ng: { switch: { when: "false" } } }
%a.button.selector.hub-profile{ ng: { click: "enterprise.owned && (enterprise.sells='none')", class: "{selected: enterprise.sells=='none', disabled: !enterprise.owned}" } }
.top
%h3 Profile Only
%p Get a listing
.bottom ALWAYS FREE
%h3= t('js.admin.panels.enterprise_package.profile_only')
%p= t('js.admin.panels.enterprise_package.get_listing')
.bottom= t('js.admin.panels.enterprise_package.always_free')
%a.button.selector.hub{ ng: { click: "enterprise.owned && (enterprise.sells='any')", class: "{selected: enterprise.sells=='any', disabled: !enterprise.owned}" } }
.top
%h3 Hub Shop
%p Sell produce from others
%h3= t('js.admin.panels.enterprise_package.hub_shop')
%p= t('js.admin.panels.enterprise_package.sell_produce_others')
.bottom
%monthly-pricing-description{ joiner: "newline" }
%div{ ng: { switch: { when: "true" } } }
%a.button.selector.producer-profile{ ng: { click: "enterprise.owned && (enterprise.sells='none')", class: "{selected: enterprise.sells=='none', disabled: !enterprise.owned}" } }
.top
%h3 Profile Only
%p Get a listing
.bottom ALWAYS FREE
%h3= t('js.admin.panels.enterprise_package.profile_only')
%p= t('js.admin.panels.enterprise_package.get_listing')
.bottom= t('js.admin.panels.enterprise_package.always_free')
%a.button.selector.producer-shop{ ng: { click: "enterprise.owned && (enterprise.sells='own')", class: "{selected: enterprise.sells=='own', disabled: !enterprise.owned}" } }
.top
%h3 Producer Shop
%p Sell your own produce
%h3= t('js.admin.panels.enterprise_package.producer_shop')
%p= t('js.admin.panels.enterprise_package.sell_own_produce')
.bottom
%monthly-pricing-description{ joiner: "newline" }
%a.button.selector.producer-hub{ ng: { click: "enterprise.owned && (enterprise.sells='any')", class: "{selected: enterprise.sells=='any', disabled: !enterprise.owned}" } }
.top
%h3 Producer Hub
%p Sell produce from self and others
%h3= t('js.admin.panels.enterprise_package.producer_hub')
%p= t('js.admin.panels.enterprise_package.sell_both')
.bottom
%monthly-pricing-description{ joiner: "newline" }
%a.button.update.fullwidth{ ng: { show: "enterprise.owned", class: "{disabled: saved() && !saving, saving: saving}", click: "save()" } }
%span{ ng: {hide: "saved() || saving" } }
SAVE
= t('js.admin.panels.save')
%i.icon-save
%span{ ng: {show: "saved() && !saving" } }
SAVED
= t('js.admin.panels.saved')
%i.icon-ok-sign
%span{ ng: {show: "saving" } }
SAVING
= t('js.admin.panels.saving')
%i.icon-refresh

View File

@@ -1,39 +1,37 @@
.row.enterprise_producer_panel{ ng: { controller: 'indexProducerPanelCtrl' } }
.alpha.eight.columns
.info{ ng: { show: "enterprise.is_primary_producer==true" } }
%h3 Producer
%p Producers make yummy things to eat &amp;/or drink. You're a producer if you grow it, raise it, brew it, bake it, ferment it, milk it or mould it.
%p Producers can also perform other functions, such as aggregating food from other enterprises and selling it through a shop on the Open Food Network.
%h3= t('js.admin.panels.enterprise_producer.producer')
%p= t('js.admin.panels.enterprise_producer.producer_text1')
%p= t('js.admin.panels.enterprise_producer.producer_text2')
.info{ ng: { show: "enterprise.is_primary_producer==false" } }
%h3 Non-Producer
%p Non-producers do not produce any food themselves, meaning that they cannot create their own products for sale through the Open Food Network.
%h3= t('js.admin.panels.enterprise_producer.non_producer')
%p= t('js.admin.panels.enterprise_producer.non_producer_text1')
%p Instead, non-producers specialise in linking producers to the end eater, whether it be by aggregating, grading, packing, selling or delivering food.
%p= t('js.admin.panels.enterprise_producer.non_producer_text2')
.omega.eight.columns
%a.button.selector.producer{ ng: { click: 'enterprise.owned && changeToProducer()', class: "{selected: enterprise.is_primary_producer==true, disabled: !enterprise.owned}" } }
.top
%h3 PRODUCER
%p Producers of food
.bottom eg. GROWERS, BAKERS, BREWERS, MAKERS
%h3= t('js.admin.panels.enterprise_producer.producer')
%p= t('js.admin.panels.enterprise_producer.producer_desc')
.bottom= t('js.admin.panels.enterprise_producer.producer_example')
%a.button.selector.non-producer{ ng: { click: 'enterprise.owned && changeToNonProducer()', class: "{selected: enterprise.is_primary_producer==false, disabled: !enterprise.owned}" } }
.top
%h3 Non-Producer
%p All other food enterprises
.bottom eg. Grocery stores, Food co-ops, Buying groups
%h3= t('js.admin.panels.enterprise_producer.non_producer')
%p= t('js.admin.panels.enterprise_producer.non_producer_desc')
.bottom= t('js.admin.panels.enterprise_producer.non_producer_example')
%a.button.update.fullwidth{ ng: { show: "enterprise.owned", class: "{disabled: saved() && !saving, saving: saving}", click: "save()" } }
%span{ ng: {hide: "saved() || saving" } }
SAVE
= t('js.admin.panels.save')
%i.icon-save
%span{ ng: {show: "saved() && !saving" } }
SAVED
= t('js.admin.panels.saved')
%i.icon-ok-sign
%span{ ng: {show: "saving" } }
SAVING
= t('js.admin.panels.saving')
%i.icon-refresh

View File

@@ -1,18 +1,17 @@
.row.enterprise_status_panel{ ng: { controller: 'indexStatusPanelCtrl' } }
.alpha.omega.sixteen.columns
%h4.status-ok.text-center{ ng: { show: "issues.length == 0 && warnings.length == 0" } }
%i.icon-ok-sign
{{ object.name }} is set up and ready to go!
= t('js.admin.panels.enterprise_status.status_title', name: '{{ object.name }}')
%table{ ng: { show: "issues.length > 0 || warnings.length > 0" } }
%thead
%th.severity
Severity
= t('js.admin.panels.enterprise_status.severity')
%th.description
Description
= t('js.admin.panels.enterprise_status.description')
%th.resolve
Resolve
= t('js.admin.panels.enterprise_status.resolve')
%tr{ ng: { repeat: "issue in issues"} }
%td.severity
%i.icon-warning-sign.issue

View File

@@ -14,9 +14,6 @@
.exchange-product{'ng-repeat' => 'product in supplied_products | filter:productSuppliedToOrderCycle | visibleProducts:exchange:order_cycle.visible_variants_for_outgoing_exchanges | orderBy:"name"' }
.exchange-product-details
%label
-# MASTER_VARIANTS: No longer required
-# = check_box_tag 'order_cycle_outgoing_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}', 1, 1, 'ng-hide' => 'product.variants.length > 0', 'ng-model' => 'exchange.variants[product.master_id]', 'id' => 'order_cycle_outgoing_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}',
-# 'ng-disabled' => 'product.variants.length > 0 || !order_cycle.editable_variants_for_outgoing_exchanges.hasOwnProperty(exchange.enterprise_id) || order_cycle.editable_variants_for_outgoing_exchanges[exchange.enterprise_id].indexOf(product.master_id) < 0'
%img{'ng-src' => '{{ product.image_url }}'}
.name {{ product.name }}
.supplier {{ product.supplier_name }}

View File

@@ -1,4 +1,4 @@
%div{ ng: { show: "data.length > limit" } }
%input{ type: 'button', value: 'Show More', ng: { click: 'limit = limit + increment' } }
%input{ type: 'button', value: t(:show_more), ng: { click: 'limit = limit + increment' } }
or
%input{ type: 'button', value: "Show All ({{ data.length - limit }} More)", ng: { click: 'limit = data.length' } }
%input{ type: 'button', value: t(:show_more_with_more, num: '{{ data.length - limit }}'), ng: { click: 'limit = data.length' } }

View File

@@ -3,9 +3,9 @@
{{$getDisplayText()}}
%span.tag-with-rules{ ng: { if: "data.rules == 1" } }
&mdash;
= t 'admin.has_one_rule'
= t('admin.has_one_rule')
%span.tag-with-rules{ ng: { if: "data.rules > 1" } }
&mdash;
= t 'admin.has_n_rules', { num: '{{data.rules}}' }
= t('admin.has_n_rules', { num: '{{data.rules}}' })
%span{ ng: { if: "!data.rules" } }
{{$getDisplayText()}}

View File

@@ -1,13 +1,13 @@
%a.close-reveal-modal{"ng-click" => "$close()"}
%i.ofn-i_009-close
%h3 Reduced stock available
%h3= t('js.out_of_stock.reduced_stock_available')
%p While you've been shopping, the stock levels for one or more of the products in your cart have reduced. Here's what's changed:
%p= t('js.out_of_stock.out_of_stock_text')
%p{'ng-repeat' => "v in variants"}
%em {{ v.name_to_display }} - {{ v.unit_to_display }}
%span{'ng-if' => "v.count_on_hand == 0"}
is now out of stock.
= t('js.out_of_stock.now_out_of_stock')
%span{'ng-if' => "v.count_on_hand > 0"}
now only has {{ v.count_on_hand }} remaining.
= t('js.out_of_stock.only_n_remainging', num: '{{ v.count_on_hand }}')

View File

@@ -1,10 +0,0 @@
%div#registration-modal{"ng-controller" => "RegistrationCtrl"}
%div{ ng: { show: "currentStep() == 'introduction'" } }
%ng-include{ src: "'registration/introduction.html'" }
%div{ ng: { repeat: 'step in steps', show: "currentStep() == step" } }
%ng-include{ src: "'registration/'+ step + '.html'" }
%div{ ng: { show: "currentStep() == 'finished'" } }
%ng-include{ src: "'registration/finished.html'" }
%a.close-reveal-modal{"ng-click" => "$close()"}
%i.ofn-i_009-close

View File

@@ -1,57 +0,0 @@
.container#registration-about
%ng-include{ src: "'registration/steps.html'" }
.row
.small-12.columns
%header
%h2 {{'enterprise_about_headline' | t}}
%h5
{{'enterprise_about_message' | t}}
%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.info{ "ofn-inline-alert" => true, ng: { show: "visible" } }
%h6{ "ng-bind" => "'enterprise_success' | t:{enterprise: enterprise.name}" }
%span {{'enterprise_registration_exit_message' | t}}
%a.close{ ng: { click: "close()" } } &times;
.small-12.large-8.columns
.row
.small-12.columns
.field
%label{ for: 'enterprise_description' } {{'enterprise_description' | t}}:
%input.chunky{ id: 'enterprise_description', placeholder: "{{'enterprise_description_placeholder' | t}}", ng: { model: 'enterprise.description' } }
.row
.small-12.columns
.field
%label{ for: 'enterprise_long_desc' } {{'enterprise_long_desc' | t}}:
%textarea.chunky{ id: 'enterprise_long_desc', rows: 6, placeholder: "{{'enterprise_long_desc_placeholder' | t}}", ng: { model: 'enterprise.long_description' } }
%small{ "ng-bind" => "'enterprise_long_desc_length' | t:{num: enterprise.long_description.length}" }
.small-12.large-4.columns
.row
.small-12.columns
.field
%label{ for: 'enterprise_abn' } {{'enterprise_abn' | t}}:
%input.chunky{ id: 'enterprise_abn', placeholder: "{{'enterprise_abn_placeholder' | t}}", ng: { model: 'enterprise.abn' } }
.row
.small-12.columns
.field
%label{ for: 'enterprise_acn' } {{'enterprise_acn' | t}}:
%input.chunky{ id: 'enterprise_acn', placeholder: "{{'enterprise_acn_placeholder' | t}}", ng: { model: 'enterprise.acn' } }
.row
.small-12.columns
.field
%label{ for: 'enterprise_charges_sales_tax' }= t(:charges_sales_tax)
%input{ id: 'enterprise_charges_sales_tax_true', type: 'radio', name: 'charges_sales_tax', value: 'true', required: true, ng: { model: 'enterprise.charges_sales_tax' } }
%label{ for: 'enterprise_charges_sales_tax_true' } {{'say_yes' | t}}
%input{ id: 'enterprise_charges_sales_tax_false', type: 'radio', name: 'charges_sales_tax', value: 'false', required: true, ng: { model: 'enterprise.charges_sales_tax' } }
%label{ for: 'enterprise_charges_sales_tax_false' } {{'say_no' | t}}
%span.error.small-12.columns{ ng: { show: "about.charges_sales_tax.$error.required && submitted" } }
{{'enterprise_tax_required' | t}}
.row.buttons.pad-top
.small-12.columns
%input.button.primary.right{ type: "submit", value: "{{'continue' | t}}" }

View File

@@ -1,31 +0,0 @@
.container#registration-contact
%ng-include{ src: "'registration/steps.html'" }
.row
.small-12.columns
%header
%h2 {{'registration_greeting' | t}}
%h5{ "ng-bind" => "'who_is_managing_enterprise' | t:{enterprise: enterprise.name}" }
%form{ name: 'contact', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "selectIfValid('type',contact)" } }
.row.content
.small-12.medium-12.large-7.columns
.row
.small-12.columns.field
%label{ for: 'enterprise_contact' } {{'enterprise_contact' | t}}:
%input.chunky.small-12.columns{ id: 'enterprise_contact', name: 'contact', required: true, placeholder: "Contact Name", ng: { model: 'enterprise.contact' } }
%span.error.small-12.columns{ ng: { show: "contact.contact.$error.required && submitted" } }
{{'enterprise_contact_required' | t}}
.row
.small-12.columns.field
%label{ for: 'enterprise_email_address' } {{'enterprise_email_address' | t}}:
%input.chunky.small-12.columns{ id: 'enterprise_email_address', name: 'email_address', type: 'email', placeholder: "eg. charlie@thefarm.com", ng: { model: 'enterprise.email_address' } }
.row
.small-12.columns.field
%label{ for: 'enterprise_phone' } {{'enterprise_phone' | t}}:
%input.chunky.small-12.columns{ id: 'enterprise_phone', name: 'phone', placeholder: "eg. (03) 1234 5678", ng: { model: 'enterprise.phone' } }
.small-12.medium-12.large-5.hide-for-small-only
.row.buttons
.small-12.columns
%input.button.secondary{ type: "button", value: "{{'back' | t}}", ng: { click: "select('details')" } }
%input.button.primary.right{ type: "submit", value: "{{'continue' | t}}" }

View File

@@ -1,64 +0,0 @@
.container#registration-details
%ng-include{ src: "'registration/steps.html'" }
.row
.small-12.columns
%header
%h2 {{'registration_detail_headline' | t}}
%h5{ ng: { if: "::enterprise.type != 'own'" } } {{'registration_detail_enterprise' | t}}
%h5{ ng: { if: "::enterprise.type == 'own'" } } {{'registration_detail_producer' | t}}
%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', ng: { if: "::enterprise.type != 'own'" } } {{'registration_detail_name_enterprise' | t}}
%label{ for: 'enterprise_name', ng: { if: "::enterprise.type == 'own'" } } {{'registration_detail_name_producer' | t}}
%input.chunky{ id: 'enterprise_name', name: 'name', placeholder: "{{'registration_detail_name_placeholder' | t}}", required: true, ng: { model: 'enterprise.name' } }
%span.error{ ng: { show: "details.name.$error.required && submitted" } }
{{'registration_detail_name_error' | t}}
.row
.small-12.medium-9.large-6.columns
.field
%label{ for: 'enterprise_address' } {{'registration_detail_address1' | t}}
%input.chunky{ id: 'enterprise_address', name: 'address1', required: true, placeholder: "{{'registration_detail_address1_placeholder' | t}}", required: true, ng: { model: 'enterprise.address.address1' } }
%span.error{ ng: { show: "details.address1.$error.required && submitted" } }
{{'registration_detail_address1_error' | t}}
.field
%label{ for: 'enterprise_address2' } {{'registration_detail_address2' | t}}
%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.medium-8.large-8.columns
.field
%label{ for: 'enterprise_city' } {{'registration_detail_suburb' | t}}
%input.chunky{ id: 'enterprise_city', name: 'city', required: true, placeholder: "{{'registration_detail_suburb_placeholder' | t}}", ng: { model: 'enterprise.address.city' } }
%span.error{ ng: { show: "details.city.$error.required && submitted" } }
{{'registration_detail_suburb_error' | t}}
.small-12.medium-4.large-4.columns
.field
%label{ for: 'enterprise_zipcode' } {{'registration_detail_postcode' | t}}
%input.chunky{ id: 'enterprise_zipcode', name: 'zipcode', required: true, placeholder: "{{'registration_detail_postcode_placeholder' | t}}", ng: { model: 'enterprise.address.zipcode' } }
%span.error{ ng: { show: "details.zipcode.$error.required && submitted" } }
{{'registration_detail_postcode_error' | t}}
.row
.small-12.medium-4.large-4.columns
.field
%label{ for: 'enterprise_state' } {{'registration_detail_state' | t}}
%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" } }
{{'registration_detail_state_error' | t}}
.small-12.medium-8.large-8.columns
.field
%label{ for: 'enterprise_country' } {{'registration_detail_country' | t}}
%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" } }
{{'registration_detail_country_error' | t}}
.row.buttons
.small-12.columns
%hr
%input.button.primary.right{ type: "submit", value: "{{'continue' | t}}" }

View File

@@ -1,15 +0,0 @@
.container#registration-finished
.row
.small-12.columns.pad-top
%header
%h2 {{'registration_finished_headline' | t}}
.panel.callout
%p{ "ng-bind" => "'registration_finished_thanks' | t:{enterprise: enterprise.name}" }
%p {{'registration_finished_login' | t}}
.row
.small-12.columns.text-center
%h4{ "ng-bind" => "'registration_finished_activate' | t:{enterprise: enterprise.name}" }
%p{ "ng-bind-html" => "'registration_finished_activate_instruction_html' | t:{email: enterprise.email}"}
%a.button.primary{ type: "button", href: "/" } {{'registration_finished_action' | t}} &gt;

View File

@@ -1,22 +0,0 @@
.container#registration-images{ 'nv-file-drop' => true, uploader: "imageUploader", options:"{ alias: imageStep }", ng: { controller: "EnterpriseImageCtrl" } }
%ng-include{ src: "'registration/steps.html'" }
.row
.small-12.columns
%header
%h2 {{'registration_images_headline' | t}}
%h5 {{'registration_images_description' | t}}
%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.secondary{ type: "button", value: "Back", ng: { click: "select('about')" } }
&nbsp;
%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.secondary{ type: "button", value: "{{'back' | t}}", ng: { click: "imageSelect('logo')" } }
%input.button.primary.right{ type: "submit", value: "{{'continue' | t}}" }

View File

@@ -1,45 +0,0 @@
.small-12.medium-12.large-6.columns
.row
.small-12.columns.center
.row
.small-12.columns.center
%h4
{{'select_logo' | t}}
.row
.small-12.columns.center
%span.small
{{'logo_tip' | t}}
.row.pad-top
.small-12.columns
.image-select.small-12.columns
%label.small-12.columns.button{ for: 'image-select' } {{'logo_label' | t}}
%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
{{'action_or' | t}}
.row.show-for-large-up
.large-12.columns
#image-over{ 'nv-file-over' => true, uploader: "imageUploader" }
{{'logo_drag' | t}}
.small-12.medium-12.large-6.columns
.row
.small-12.columns.center
.row
.small-12.columns.center
%h4
{{'review_logo' | t}}
.row
.small-12.columns.center
%span.small
{{'review_logo_tip' | t}}
.row.pad-top
.small-12.columns.center
#image-placeholder.logo
%img{ ng: { show: "imageSrc() && !imageUploader.isUploading", src: '{{ imageSrc() }}' } }
.message{ ng: { hide: "imageSrc() || imageUploader.isUploading" } }
{{'logo_placeholder' | t}}
.loading{ ng: { hide: "!imageUploader.isUploading" } }
%img.spinner{ src: "/assets/spinning-circles.svg" }
%br/
{{'uploading' | t}}

View File

@@ -1,43 +0,0 @@
.small-12.medium-12.large-12.columns
.row
.small-12.columns.center
%h4
{{'select_promo_image' | t}}
.row
.small-12.medium-12.large-5.columns.center
.row
.small-12.columns.center
%span.small
{{'promo_image_tip' | t}}
.row.pad-top
.small-12.columns
.image-select.small-12.columns
%label.small-12.columns.button{ for: 'image-select' } {{'promo_image_label' | t}}
%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
{{'action_or' | t}}
.large-5.columns
#image-over{ 'nv-file-over' => true, uploader: "imageUploader" }
{{'promo_image_drag' | t}}
.small-12.medium-12.large-12.columns.pad-top
.row
.small-12.columns.center
%h4
{{'review_promo_image' | t}}
.row
.small-12.columns.center
.row
.small-12.columns.center
%span.small
{{'review_promo_image_tip' | t}}
.row.pad-top
.small-12.columns.center
#image-placeholder.promo
%img{ ng: { show: "imageSrc() && !imageUploader.isUploading", src: '{{ imageSrc() }}' } }
.message{ ng: { hide: "imageSrc() || imageUploader.isUploading" } }
{{'promo_image_placeholder' | t}}
.loading{ ng: { hide: "!imageUploader.isUploading" } }
%img.spinner{ src: "/assets/spinning-circles.svg" }
%br/
{{'uploading' | t}}

View File

@@ -1,41 +0,0 @@
.row
.small-12.columns
%header
%h2 {{'registration_greeting' | t}}
%h4
%small
%i.ofn-i_040-hub
{{'registration_intro' | t}}
.hide-for-large-up
%hr
%input.button.small.primary{ type: "button", value: "{{'registration_action' | t}}", ng: { click: "select('details')" } }
%hr
.row{ 'data-equalizer' => true }
.small-12.medium-12.large-6.columns.pad-top{ 'data-equalizer-watch' => true }
%h5 {{'registration_checklist' | t}}:
%ul.check-list
%li
{{'registration_time' | t}}
%li
{{'registration_enterprise_address' | t}}
%li
{{'registration_contact_details' | t}}
%li
{{'registration_logo' | t}}
%li
{{'registration_promo_image' | t}}
%li
{{'registration_about_us' | t}}
.small-9.medium-8.large-5.columns.pad-top.end{ 'data-equalizer-watch' => true}
%h5
{{'registration_outcome_headline' | t}}
%p{ "ng-bind-html" => "t('registration_outcome1_html')" }
%p {{'registration_outcome2' | t}}
%p {{'registration_outcome3' | t}}
.row.show-for-large-up
.small-12.columns
%hr
%input.button.primary.right{ type: "button", value: "{{'registration_action' | t}}", ng: { click: "select('details')" } }

View File

@@ -1,16 +0,0 @@
.row
.small-12.columns
%header
%h2 {{'limit_reached_headline' | t}}
%h4 {{'limit_reached_message' | t}}
.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
{{'limit_reached_text' | t}}
%strong Open Food Network.
.row
.small-12.columns
%hr
%input.button.primary{ type: "button", value: "{{'limit_reached_action' | t}}", ng: { click: "close()" } }

View File

@@ -1,45 +0,0 @@
.container#registration-social
%ng-include{ src: "'registration/steps.html'" }
.row
.small-12.columns
%header
%h2 {{'enterprise_final_step' | t}}
%h5{ "ng-bind" => "'enterprise_social_text' | t:{enterprise: enterprise.name}" }
%form{ name: 'social', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "update('finished',social)" } }
.row.content
.small-12.large-7.columns
.row
.small-12.columns
.field
%label{ for: 'enterprise_website' } {{'website' | t}}:
%input.chunky{ id: 'enterprise_website', placeholder: "{{'website_placeholder' | t}}", ng: { model: 'enterprise.website' } }
.row
.small-12.columns
.field
%label{ for: 'enterprise_facebook' } {{'facebook' | t}}:
%input.chunky{ id: 'enterprise_facebook', placeholder: "{{'facebook_placeholder' | t}}", ng: { model: 'enterprise.facebook' } }
.row
.small-12.columns
.field
%label{ for: 'enterprise_linkedin' } {{'linkedin' | t}}:
%input.chunky{ id: 'enterprise_linkedin', placeholder: "{{'linkedin_placeholder' | t}}", ng: { model: 'enterprise.linkedin' } }
.small-12.large-5.columns
.row
.small-12.columns
.field
%label{ for: 'enterprise_twitter' } {{'twitter' | t}}:
%input.chunky{ id: 'enterprise_twitter', placeholder: "{{'twitter_placeholder' | t}}", ng: { model: 'enterprise.twitter' } }
.row
.small-12.columns
.field
%label{ for: 'enterprise_instagram' } {{'instagram' | t}}:
%input.chunky{ id: 'enterprise_instagram', placeholder: "{{'instagram_placeholder' | t}}", ng: { model: 'enterprise.instagram' } }
.row.buttons
.small-12.columns
%input.button.secondary{ type: "button", value: "{{'back' | t}}", ng: { click: "select('images')" } }
%input.button.primary.right{ type: "submit", value: "{{'continue' | t}}" }

View File

@@ -1,3 +0,0 @@
.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

@@ -1,47 +0,0 @@
.container#registration-type
%ng-include{ src: "'registration/steps.html'" }
.row
.small-12.columns
%header
%h2{ "ng-bind" => "'registration_type_headline' | t:{enterprise: enterprise.name}" }
%h4
{{'registration_type_question' | t}}
%form{ name: 'type', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "create(type)" } }
.row#enterprise-types{ 'data-equalizer' => true, ng: { 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 {{'registration_type_producer' | t}}
.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 {{'registration_type_no_producer' | t}}
.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" } }
{{'registration_type_error' | t}}
.row
.small-12.columns
.panel.callout
.left
%i.ofn-i_013-help
&nbsp;
%p {{'registration_type_producer_help' | t}}
.panel.callout
.left
%i.ofn-i_013-help
&nbsp;
%p {{'registration_type_no_producer_help' | t}}
.row.buttons
.small-12.columns
%input.button.secondary{ type: "button", value: "{{'back' | t}}", ng: { click: "select('contact')" } }
%input.button.primary.right{ type: "submit", value: "{{'create_profile' | t}}" }

View File

@@ -1,15 +0,0 @@
.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

@@ -0,0 +1,24 @@
.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

@@ -1,10 +1,14 @@
@-webkit-keyframes slideInUp
0%
-webkit-transform: translateY(20px)
transform: translateY(20px)
100%
-webkit-transform: translateY(0)
transform: translateY(0)
@-webkit-keyframes slideInUp {
0% {
-webkit-transform: translateY(20px);
transform: translateY(20px);
}
100% {
-webkit-transform: translateY(0);
transform: translateY(0);
}
}
// @-webkit-keyframes slideOutDown
// 0%
@@ -14,13 +18,14 @@
// -webkit-transform: translateY(20px)
// transform: translateY(20px)
.animate-show
-webkit-animation-name: slideInUp
animation-name: slideInUp
-webkit-animation-duration: 0.3s
animation-duration: 0.3s
-webkit-animation-fill-mode: both
animation-fill-mode: both
.animate-show {
-webkit-animation-name: slideInUp;
animation-name: slideInUp;
-webkit-animation-duration: 0.3s;
animation-duration: 0.3s;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
// line-height: 20px
// opacity: 1
@@ -33,3 +38,4 @@
// animation-fill-mode: both
// // line-height: 20px
// // opacity: 1
}

View File

@@ -1,72 +0,0 @@
@import ../darkswarm/branding
@import ../darkswarm/mixins
#change_type
section
margin: 2em 0 0 0
&, & *
color: #5498da
.description
background-color: #eff5fc
margin-top: -2em
padding: 4em 2em 2em 1em
@media all and (max-width: 786px)
margin-bottom: 2em
.admin-cta
border: 1px solid #5498da
@include border-radius(3px)
text-align: center
padding: 1em
.error
display: block
color: #f57e80
border: 1px solid #f57e80
background-color: #fde6e7
@include border-radius(3px)
margin-bottom: 1em
padding: 0.5em
a.selector
position: relative
border: 2px solid black
text-align: center
width: 100%
cursor: pointer
&, & *
color: white
&:after, &:before
top: 100%
left: 50%
border: solid transparent
content: " "
height: 0
width: 0
position: absolute
pointer-events: none
&:after
border-color: rgba(136, 183, 213, 0)
border-top-color: #5498da
border-width: 12px
margin-left: -12px
&:hover
&:after
border-top-color: #9fc820
&:before
border-color: rgba(84, 152, 218, 0)
border-top-color: black
border-width: 15px
margin-left: -15px
.bottom
background: repeating-linear-gradient(60deg, rgba(84, 152, 218, 0), rgba(84, 152, 218, 0) 5px, rgba(255, 255, 255, 0.25) 5px, rgba(255, 255, 255, 0.25) 10px)
margin-top: 1em
margin-left: -15px
margin-right: -15px
padding: 5px
text-transform: uppercase
&.selected
background-color: black
&:after, &:hover &:after
border-top-color: black

View File

@@ -0,0 +1,103 @@
@import "../darkswarm/branding";
@import "../darkswarm/mixins";
#change_type {
section {
margin: 2em 0 0 0;
&, & * {
color: #5498da;
}
}
.description {
background-color: #eff5fc;
margin-top: -2em;
padding: 4em 2em 2em 1em;
@media all and (max-width: 786px) {
margin-bottom: 2em;
}
}
.admin-cta {
border: 1px solid #5498da;
@include border-radius(3px);
text-align: center;
padding: 1em;
}
.error {
display: block;
color: #f57e80;
border: 1px solid #f57e80;
background-color: #fde6e7;
@include border-radius(3px);
margin-bottom: 1em;
padding: 0.5em;
}
a.selector {
position: relative;
border: 2px solid black;
text-align: center;
width: 100%;
cursor: pointer;
&, & * {
color: white;
}
&:after, &:before {
top: 100%;
left: 50%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
}
&:after {
border-color: rgba(136, 183, 213, 0);
border-top-color: #5498da;
border-width: 12px;
margin-left: -12px;
}
&:hover {
&:after {
border-top-color: #9fc820;
}
}
&:before {
border-color: rgba(84, 152, 218, 0);
border-top-color: black;
border-width: 15px;
margin-left: -15px;
}
.bottom {
background: repeating-linear-gradient(60deg, rgba(84, 152, 218, 0), rgba(84, 152, 218, 0) 5px, rgba(255, 255, 255, 0.25) 5px, rgba(255, 255, 255, 0.25) 10px);
margin-top: 1em;
margin-left: -15px;
margin-right: -15px;
padding: 5px;
text-transform: uppercase;
}
&.selected {
background-color: black;
&:after, &:hover &:after {
border-top-color: black;
}
}
}
}

View File

@@ -1,14 +0,0 @@
#save-bar
position: fixed
width: 100%
z-index: 100
bottom: 0px
left: 0
padding: 8px 8px
font-weight: bold
background-color: #eff5fc
color: #5498da
h5
color: #5498da
input
margin-right: 5px

View File

@@ -0,0 +1,19 @@
#save-bar {
position: fixed;
width: 100%;
z-index: 100;
bottom: 0px;
left: 0;
padding: 8px 8px;
font-weight: bold;
background-color: #eff5fc;
color: #5498da;
h5 {
color: #5498da;
}
input {
margin-right: 5px;
}
}

View File

@@ -1,8 +0,0 @@
#trial_progress_bar
position: fixed
bottom: 0px
width: 100%
padding: 8px 10px
font-weight: bold
background-color: #5498da
color: white

View File

@@ -0,0 +1,10 @@
#trial_progress_bar {
position: fixed;
left: 0px;
bottom: 0px;
width: 100vw;
padding: 8px 10px;
font-weight: bold;
background-color: #5498da;
color: white;
}

View File

@@ -1,33 +0,0 @@
@import ../darkswarm/mixins
.alert-box
position: relative
display: block
background-color: #eff5dc
border: 1px solid #9fc820
color: #666
margin-top: 1em
margin-bottom: 1em
@include border-radius(3px)
transition: opacity 300ms ease-out
padding: 0.77778em 1.33333em 0.77778em 0.77778em
a.close
position: absolute
right: 5px
top: 0px
font-size: 1.5em
.dashboard_item.single-ent
.header
padding: 0.77778em 1.33333em 0.77778em 0.77778em
height: auto !important
.list
.button.bottom
width: 100%
.button.big
width: 100%
font-size: 1rem
@include border-radius(25px)
padding: 15px

View File

@@ -0,0 +1,45 @@
@import "../darkswarm/mixins";
.alert-box {
position: relative;
display: block;
background-color: #eff5dc;
border: 1px solid #9fc820;
color: #666;
margin-top: 1em;
margin-bottom: 1em;
@include border-radius(3px);
transition: opacity 300ms ease-out;
padding: 0.77778em 1.33333em 0.77778em 0.77778em;
a.close {
position: absolute;
right: 5px;
top: 0px;
font-size: 1.5em;
}
}
.dashboard_item.single-ent {
.header {
padding: 0.77778em 1.33333em 0.77778em 0.77778em;
height: auto !important;
}
.list {
.button.bottom {
width: 100%;
}
}
}
.button.big {
width: 100%;
font-size: 1rem;
@include border-radius(25px);
padding: 15px;
}

View File

@@ -1,159 +0,0 @@
div.dashboard_item
margin-bottom: 30px
.centered
text-align: center
.text-icon
margin-top: 8px
display: block
font-size: 16px
font-weight: bold
color: #fff
padding: 0px 6px
border-radius: 10px
&.green
background-color: #9fc820
&.red
background-color: #DA5354
&.orange
background-color: #DA7F52
div.header
height: 50px
border-radius: 6px 6px 0px 0px
border: 1px solid #5498da
position: relative
a[ofn-with-tip]
position: absolute
right: 5px
bottom: 5px
&.red
border-color: #DA5354
border-width: 3px
h3
color: #DA5354
&.orange
border-color: #DA7F52
border-width: 3px
h3
color: #DA7F52
h3.alpha
height: 100%
padding: 10px 5px 0px 3%
a
border-radius: 0px 4px 0px 0px
margin-left: 8px
height: 100%
padding: 15px 2px 0px 2px
.tabs
height: 30px
border: solid #5498da
border-width: 0px 0px 1px 0px
margin-top: 3px
div.dashboard_tab
cursor: pointer
height: 30px
color: #fff
background-color: #5498da
padding: 5px 5px 0px 5px
text-align: center
font-weight: bold
border: solid #5498da
border-width: 1px 1px 0px 1px
&:hover
background-color: #9fc820
&.selected
color: #5498da
background-color: #fff
.list
max-height: 250px
overflow-y: auto
overflow-x: hidden
.list-title
border: solid #5498da
border-width: 0px 1px 0px 1px
span
font-size: 105%
padding: 10px 0px
font-weight: bold
span.alpha
padding: 10px 2px 10px 5%
.list-item
border: solid #5498da
border-width: 0px 1px 0px 1px
height: 38px
span.alpha
font-weight: bold
margin-left: -3px
padding: 10px 2px 0px 5%
span.omega
padding-right: 13px
margin-right: -3px
text-align: right
.icon-arrow-right
padding-top: 6px
font-size: 20px
.icon-warning-sign
color: #DA7F52
font-size: 30px
.icon-remove-sign
color: #DA5354
font-size: 30px
.icon-ok-sign
color: #9fc820
font-size: 30px
&.orange
color: #DA7F52
border: solid #DA7F52
&.red
color: #DA5354
border: solid #DA5354
&.orange, &.red
border-width: 0px 3px 0px 3px
&.even
background-color: #fff
&.odd
background-color: #eff5fc
&.even, &.odd
&:hover
color: #ffffff
background-color: #9fc820
.icon-arrow-right
color: #fff
.icon-remove-sign
color: #fff
.icon-warning-sign
color: #fff
.icon-ok-sign
color: #fff
.text-icon
&.green
color: #9fc820
background-color: #fff
a.button
color: #fff
font-size: 110%
font-weight: bold
text-align: center
&.orange
background-color: #DA7F52
&.blue
background-color: #5498da
&.red
background-color: #DA5354
&:hover
background-color: #9fc820
&.bottom
border-radius: 0px 0px 6px 6px
padding: 15px 15px

View File

@@ -0,0 +1,239 @@
div.dashboard_item {
margin-bottom: 30px;
.centered {
text-align: center;
}
.text-icon {
margin-top: 8px;
display: block;
font-size: 16px;
font-weight: bold;
color: #fff;
padding: 0px 6px;
border-radius: 10px;
&.green {
background-color: #9fc820;
}
&.red {
background-color: #DA5354;
}
&.orange {
background-color: #DA7F52;
}
}
div.header {
height: 50px;
border-radius: 6px 6px 0px 0px;
border: 1px solid #5498da;
position: relative;
a[ofn-with-tip] {
position: absolute;
right: 5px;
bottom: 5px;
}
&.red {
border-color: #DA5354;
border-width: 3px;
h3 {
color: #DA5354;
}
}
&.orange {
border-color: #DA7F52;
border-width: 3px;
h3 {
color: #DA7F52;
}
}
h3.alpha {
height: 100%;
padding: 10px 5px 0px 3%;
}
a {
border-radius: 0px 4px 0px 0px;
margin-left: 8px;
height: 100%;
padding: 15px 2px 0px 2px;
}
}
.tabs {
height: 30px;
border: solid #5498da;
border-width: 0px 0px 1px 0px;
margin-top: 3px;
div.dashboard_tab {
cursor: pointer;
height: 30px;
color: #fff;
background-color: #5498da;
padding: 5px 5px 0px 5px;
text-align: center;
font-weight: bold;
border: solid #5498da;
border-width: 1px 1px 0px 1px;
&:hover {
background-color: #9fc820;
}
&.selected {
color: #5498da;
background-color: #fff;
}
}
}
.list {
max-height: 250px;
overflow-y: auto;
overflow-x: hidden;
}
.list-title {
border: solid #5498da;
border-width: 0px 1px 0px 1px;
span {
font-size: 105%;
padding: 10px 0px;
font-weight: bold;
}
span.alpha {
padding: 10px 2px 10px 5%;
}
}
.list-item {
border: solid #5498da;
border-width: 0px 1px 0px 1px;
height: 38px;
span.alpha {
font-weight: bold;
margin-left: -3px;
padding: 10px 2px 0px 5%;
}
span.omega {
padding-right: 13px;
margin-right: -3px;
text-align: right;
}
.icon-arrow-right {
padding-top: 6px;
font-size: 20px;
}
.icon-warning-sign {
color: #DA7F52;
font-size: 30px;
}
.icon-remove-sign {
color: #DA5354;
font-size: 30px;
}
.icon-ok-sign {
color: #9fc820;
font-size: 30px;
}
&.orange {
color: #DA7F52;
border: solid #DA7F52;
}
&.red {
color: #DA5354;
border: solid #DA5354;
}
&.orange, &.red {
border-width: 0px 3px 0px 3px;
}
&.even {
background-color: #fff;
}
&.odd {
background-color: #eff5fc;
}
&.even, &.odd {
&:hover {
color: #ffffff;
background-color: #9fc820;
.icon-arrow-right {
color: #fff;
}
.icon-remove-sign {
color: #fff;
}
.icon-warning-sign {
color: #fff;
}
.icon-ok-sign {
color: #fff;
}
.text-icon {
&.green {
color: #9fc820;
background-color: #fff;
}
}
}
}
}
a.button {
color: #fff;
font-size: 110%;
font-weight: bold;
text-align: center;
&.orange {
background-color: #DA7F52;
}
&.blue {
background-color: #5498da;
}
&.red {
background-color: #DA5354;
}
&:hover {
background-color: #9fc820;
}
&.bottom {
border-radius: 0px 0px 6px 6px;
padding: 15px 15px;
}
}
}

View File

@@ -111,3 +111,27 @@
}
}
}
tags-input .tags li.tag-item {
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
-ms-border-radius: 3px;
-o-border-radius: 3px;
border-radius: 3px;
margin: 2px 0 2px 3px;
background-image: none;
background-color: #5fa5e8;
border: none;
box-shadow: none;
color: white !important;
font-size: 85%;
height: 25px;
}
tags-input .tags .tag-item .remove-button {
color: white;
}
table th.actions .no-text[class*="icon-"], table td.actions .no-text[class*="icon-"] {
cursor: pointer;
}

View File

@@ -203,6 +203,10 @@ text-angular {
.ta-scroll-window > .ta-bind {
max-height: 400px;
min-height: 100px;
outline: none;
p {
margin-bottom: 1.5rem;
}
}
.ta-scroll-window.form-control {
min-height: 100px;

View File

@@ -0,0 +1,225 @@
div.panel-section {
.neutral {
color: #bfbfbf;
}
.warning {
color: #da5354;
}
.success {
color: #86d83a;
}
.info {
color: #68b7c0;
}
div.panel-header {
width: 100%;
//font-size: 1.5em;
clear: both;
//border: 1px solid #ccc;
float: left;
padding: 0.5em;
div {
font-size: 1.25em;
float: left;
}
div.header-caret {
width: 2em;
text-align: center;
min-height: 0.1em; //Empty div fix
}
div.header-icon {
width: 2.5em;
text-align: center;
padding-top: 0.18em;
i {
font-size: 1.5em;
line-height: 0.9em;
}
}
div.header-count {
min-width: 2em;
text-align: right;
padding-right: 0.5em;
}
div.header-description {
width: auto;
}
}
div.panel-header:hover {
cursor: pointer;
background-color: #f7f7f7;
}
div.panel-header.active {
background-color: #efefef;
text-shadow: 1px 1px 0px rgba(255,255,255,0.75);
}
div.panel-content {
width: 100%;
clear: both;
//border: 1px solid #ccc;
margin-bottom: 0.5em;
background-color: #f9f9f9;
padding: 1.5em;
div.table-wrap {
width: 100%;
overflow: auto;
border-right: 1px solid #ceede3;
max-height: 23em;
}
table {
background-color: white;
margin-bottom: 0;
td, th {
white-space: nowrap;
}
tr.error {
//background-color: #ffe6e4;
//color: #ee4728;
color: #c84C4c;
}
tr:hover td.invalid {
background-color: #ed5135;
}
tr i {
display: block;
margin-bottom: -0.2em;
font-size: 1.4em !important;
}
td.invalid {
background-color: #f05c51;
box-shadow: inset 0px 0px 1px red;
color: white;
}
}
div.import-errors {
margin-bottom: 0.85em;
p.line {
font-size: 1.15em;
margin-bottom: 0.2em;
color: #577084;
}
p.error {
color: #cb1b1b;
margin-bottom: 0.2em;
}
}
}
}
br.panels.clearfix {
clear: both;
}
table.import-settings {
background-color: transparent !important;
width: auto;
//select {
// width: 100%;
//}
tr {
}
tbody tr:hover td {
background-color: #f3f3f3;
}
td {
border: 0;
border-bottom: 1px solid #eee;
text-align: left;
input {
width: 15em;
}
input[type="checkbox"] {
width: auto;
}
}
td.description {
font-weight: bold;
padding-right: 2.5em;
}
tr:first-child td {
//border-top: 1px solid #eee;
border-top: 0;
}
tr:last-child td {
//border-top: 1px solid #eee;
border-bottom: 0;
}
}
.panel-section.import-settings {
.header-description {
padding-left: 1em;
}
span.header-error {
font-size: 0.85em;
color: #da5354;
}
.select2-search {
display: none;
}
.select2-results {
margin: 0;
}
}
.post-save-results {
p {
font-size: 1.25em;
margin-bottom: 0.5em;
strong {
margin-right: 0.2em;
min-width: 1.8em;
display: inline-block;
text-align: right;
}
i {
font-size: 1.4em;
vertical-align: middle;
position: relative;
}
i.fa-check-circle {
color: #86d83a;
}
i.fa-info-circle {
color: #68b7c0;
}
}
p.save-error {
color: #ee4728;
font-size: 1.05em;
margin-top: 0.4em;
}
}

View File

@@ -1,23 +0,0 @@
// TODO: Provide -moz- and -o- directives
@-webkit-keyframes alert-flash
0%
background-color: #f9f1ae
100%
background-color: #fff
table#enterprise-relationships, table#enterprise-roles
ul
list-style-type: none
th.actions, td.actions
width: 16%
.errors
color: #f00
tr.ng-enter
-webkit-animation-name: alert-flash
-webkit-animation-duration: 1200ms
-webkit-animation-iteration-count: 1
-webkit-animation-timing-function: ease-in-out

View File

@@ -0,0 +1,31 @@
// TODO: Provide -moz- and -o- directives
@-webkit-keyframes alert-flash {
0% {
background-color: #f9f1ae;
}
100% {
background-color: #fff;
}
}
table#enterprise-relationships, table#enterprise-roles {
ul {
list-style-type: none;
}
th.actions, td.actions {
width: 16%;
.errors {
color: #f00;
}
}
tr.ng-enter {
-webkit-animation-name: alert-flash;
-webkit-animation-duration: 1200ms;
-webkit-animation-iteration-count: 1;
-webkit-animation-timing-function: ease-in-out;
}
}

View File

@@ -1,18 +0,0 @@
.side_menu
border-right: 2px solid #f6f6f6
border-top: 2px solid #f6f6f6
.menu_item
display: block
padding: 8px 15px
font-size: 120%
cursor: pointer
text-transform: uppercase
&:nth-child(odd)
background-color: #ebf3fb
&:nth-child(even)
background-color: #ffffff
&:hover
background-color: #eaf0f5
&.selected
background-color: #5498da
color: #ffffff

View File

@@ -0,0 +1,29 @@
.side_menu {
border-right: 2px solid #f6f6f6;
border-top: 2px solid #f6f6f6;
.menu_item {
display: block;
padding: 8px 15px;
font-size: 120%;
cursor: pointer;
text-transform: uppercase;
&:nth-child(odd) {
background-color: #ebf3fb;
}
&:nth-child(even) {
background-color: #ffffff;
}
&:hover {
background-color: #eaf0f5;
}
&.selected {
background-color: #5498da;
color: #ffffff;
}
}
}

View File

@@ -1,77 +0,0 @@
div.sidebar_item
margin-bottom: 30px
.centered
text-align: center
div.header
font-size: 105%
color: #fff
padding: 10px 0px
position: relative
&.blue
background-color: #5498da
&.red
background-color: #DA5354
.list
max-height: 400px
overflow-y: auto
overflow-x: hidden
&.red
color: #DA5354
.list-item
border: solid #DA5354
border-width: 0px 3px 0px 3px
a.alpha, span.alpha
margin-left: -3px
&.odd
background-color: #fcf6ef
&:hover
background-color: #9fc820
a
color: #DA5354
.list-item
.icon-arrow-right
padding-top: 6px
font-size: 20px
border: solid #5498da
border-width: 0px 1px 0px 1px
a.alpha, span.alpha
font-weight: bold
margin-left: -1px
padding: 10px 2px 10px 5%
overflow: hidden
text-overflow: ellipsis
span.omega
padding: 8px 18px 8px 0px
margin-right: -3px
text-align: right
.icon-remove-sign
color: #DA5354
font-size: 18px
&.even
background-color: #fff
&.odd
background-color: #eff5fc
&.even, &.odd
&:hover
color: #ffffff
background-color: #9fc820
a
color: #ffffff
a.button
color: #fff
padding: 15px 15px
font-weight: bold
text-align: center
border-radius: 0px
&.blue
background-color: #5498da
&.red
background-color: #DA5354
&:hover
background-color: #9fc820

Some files were not shown because too many files have changed in this diff Show More