Compare commits

...

123 Commits

Author SHA1 Message Date
Filipe
3c7337b53a Merge pull request #10836 from jibees/10835-on-small-width-screen-the-cart-element-is-missplaced
Fix bad indentation (and hierarchy) of DOM elements causing bad rendering on small width screens
2023-05-12 11:24:49 +01:00
Jean-Baptiste Bellet
60edb4363e Fix bad indentation (and hierarchy)
`%section` must be siblings each others

introduced by https://github.com/openfoodfoundation/openfoodnetwork/pull/10772
2023-05-12 09:30:37 +02:00
Maikel
93c0a06403 Merge pull request #10829 from filipefurtad0/flaky_order_spec_error
Splits assertions to allow JS table populate
2023-05-12 11:49:06 +10:00
Filipe
1bdb668cd3 Merge pull request #10769 from Matt-Yorkley/visible-line-items-query
Improve `Permissions::Order#visible_line_items` querying
2023-05-11 15:36:32 +01:00
filipefurtad0
d035d4bb87 Update all locales with the latest Transifex translations 2023-05-11 15:25:39 +01:00
filipefurtad0
f5eb72c804 Adds sleep(1) 2023-05-11 11:29:24 +01:00
Konrad
2836751698 Merge pull request #10805 from jibees/10717-bo-orders-changing-customer-does-not-update-customer_id
Admin, Edit customer details for an order: when changing to another customer, update `customer_id` as well
2023-05-10 19:08:57 +02:00
Filipe
bf7a559a32 Merge pull request #10772 from Matt-Yorkley/view-caching
Locale-aware Fragment Caching
2023-05-10 11:18:08 +01:00
Matt-Yorkley
d90653c682 Merge pull request #10793 from jibees/fix-webpack-configuration-use-the-default-one
Use the default webpack configuration for dev env
2023-05-10 10:09:28 +01:00
jibees
ca5300284c Merge pull request #10820 from Matt-Yorkley/js-dependencies
Remove indirect JS dependencies
2023-05-10 09:57:05 +02:00
Matt-Yorkley
406cb572ea Remove indirect JS dependencies 2023-05-10 09:27:00 +02:00
jibees
ca90b5cee2 Merge pull request #10810 from openfoodfoundation/dependabot/bundler/aws-sdk-s3-1.122.0
Bump aws-sdk-s3 from 1.121.0 to 1.122.0
2023-05-10 09:23:44 +02:00
jibees
760860a06d Merge pull request #10811 from openfoodfoundation/dependabot/bundler/knapsack_pro-3.11.0
Bump knapsack_pro from 3.10.0 to 3.11.0
2023-05-10 09:21:46 +02:00
jibees
189207f751 Merge pull request #10822 from openfoodfoundation/dependabot/bundler/debug-1.8.0
Bump debug from 1.7.2 to 1.8.0
2023-05-10 09:20:34 +02:00
Matt-Yorkley
1bd9182cea Update menu cache blocks 2023-05-09 16:46:09 +01:00
dependabot[bot]
969d0b6687 Bump debug from 1.7.2 to 1.8.0
Bumps [debug](https://github.com/ruby/debug) from 1.7.2 to 1.8.0.
- [Release notes](https://github.com/ruby/debug/releases)
- [Commits](https://github.com/ruby/debug/compare/v1.7.2...v1.8.0)

---
updated-dependencies:
- dependency-name: debug
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-09 10:03:20 +00:00
David Cook
8fe20ecfbe Merge pull request #10794 from openfoodfoundation/dependabot/npm_and_yarn/babel/core-7.21.8
Bump @babel/core from 7.21.5 to 7.21.8
2023-05-09 16:37:42 +10:00
Maikel
83141ec05c Merge pull request #10818 from mkllnk/schema-order
Fixup order of statements in db schema
2023-05-09 14:21:03 +10:00
Matt-Yorkley
4b707b9310 Extract locale file digest logic to a separate class and add tests 2023-05-08 14:09:00 +01:00
Matt-Yorkley
1c277e5547 Cache some html fragments 2023-05-08 14:07:50 +01:00
Matt-Yorkley
be48a6c295 Implement cache_with_locale helper for fragment caching with locales 2023-05-08 14:07:50 +01:00
Matt-Yorkley
11f45dc2f8 Give ContentConfig an updated_at attribute and a usable cache_key 2023-05-08 14:07:50 +01:00
Konrad
4303cabe56 Merge pull request #10792 from mkllnk/feature-deletion
Remove unknown (deleted) feature toggles at boot
2023-05-08 14:49:42 +02:00
Maikel Linke
f1f3ecc4f7 Fixup order of statements in db schema
It looks like the resolution of a merge conflict introduced the wrong
ordering of schema statements. Rails wants to sort tables alphabetically
and running `./bin/rails db:migrate` on a fresh database altered the
schema.rb file. This should be fixed here.

Rails also omits the default setting of `precision: 6` since Rails 7.
The vouchers feature was developed during the upgrade to Rails 7.
2023-05-08 14:37:33 +10:00
Maikel
ad033e8d44 Merge pull request #10767 from Matt-Yorkley/remove-session-cookie-upgrader
Remove SessionCookieUpgrader from middleware
2023-05-08 12:50:42 +10:00
Gaetan Craig-Riou
f25a3650bd Merge pull request #10802 from openfoodfoundation/dependabot/bundler/ddtrace-1.11.1
Bump ddtrace from 1.11.0 to 1.11.1
2023-05-08 11:45:07 +10:00
Konrad
e4d8dd9f87 Merge pull request #10780 from dacook/enable-prettier-css
Enable prettier for Admin SCSS
2023-05-06 18:24:58 +02:00
dependabot[bot]
b29d38f3fb Bump knapsack_pro from 3.10.0 to 3.11.0
Bumps [knapsack_pro](https://github.com/KnapsackPro/knapsack_pro-ruby) from 3.10.0 to 3.11.0.
- [Changelog](https://github.com/KnapsackPro/knapsack_pro-ruby/blob/master/CHANGELOG.md)
- [Commits](https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v3.10.0...v3.11.0)

---
updated-dependencies:
- dependency-name: knapsack_pro
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-05 10:01:08 +00:00
dependabot[bot]
1c52fe1648 Bump aws-sdk-s3 from 1.121.0 to 1.122.0
Bumps [aws-sdk-s3](https://github.com/aws/aws-sdk-ruby) from 1.121.0 to 1.122.0.
- [Release notes](https://github.com/aws/aws-sdk-ruby/releases)
- [Changelog](https://github.com/aws/aws-sdk-ruby/blob/version-3/gems/aws-sdk-s3/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-ruby/commits)

---
updated-dependencies:
- dependency-name: aws-sdk-s3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-05 09:59:02 +00:00
David Cook
a170b93cc1 Simplify further
Co-authored-by: Maikel <maikel@email.org.au>
2023-05-05 15:34:23 +10:00
Maikel Linke
2a943ecafb Spec setting up all feature toggle names 2023-05-05 11:09:10 +10:00
Jean-Baptiste Bellet
3a1579104f Submit customer_id as params when updating customer details on order 2023-05-04 16:40:58 +02:00
jibees
ec4c7b79bf Merge pull request #10803 from openfoodfoundation/dependabot/bundler/rspec-rails-6.0.2
Bump rspec-rails from 6.0.1 to 6.0.2
2023-05-04 13:55:37 +02:00
dependabot[bot]
9f12295a89 Bump rspec-rails from 6.0.1 to 6.0.2
Bumps [rspec-rails](https://github.com/rspec/rspec-rails) from 6.0.1 to 6.0.2.
- [Release notes](https://github.com/rspec/rspec-rails/releases)
- [Changelog](https://github.com/rspec/rspec-rails/blob/main/Changelog.md)
- [Commits](https://github.com/rspec/rspec-rails/compare/v6.0.1...v6.0.2)

---
updated-dependencies:
- dependency-name: rspec-rails
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-04 09:58:54 +00:00
dependabot[bot]
46fd6b1a3a Bump ddtrace from 1.11.0 to 1.11.1
Bumps [ddtrace](https://github.com/DataDog/dd-trace-rb) from 1.11.0 to 1.11.1.
- [Release notes](https://github.com/DataDog/dd-trace-rb/releases)
- [Changelog](https://github.com/DataDog/dd-trace-rb/blob/master/CHANGELOG.md)
- [Commits](https://github.com/DataDog/dd-trace-rb/compare/v1.11.0...v1.11.1)

---
updated-dependencies:
- dependency-name: ddtrace
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-04 09:58:25 +00:00
Jean-Baptiste Bellet
8a5608435c Update all locales with the latest Transifex translations 2023-05-03 17:30:48 +02:00
Konrad
d02d0b8847 Merge pull request #10763 from openfoodfoundation/dependabot/bundler/ddtrace-1.11.0
Bump ddtrace from 1.10.1 to 1.11.0
2023-05-03 17:27:13 +02:00
Konrad
4b6ef7796e Merge pull request #10762 from mkllnk/report-encoding
Preserve encoding of stored reports
2023-05-03 17:08:44 +02:00
Konrad
b60a6fbd05 Merge pull request #10329 from thejwuscript/9861-improve-input-validation
Improve input validation on new and edit Payment Method pages
2023-05-03 16:11:21 +02:00
jibees
2e267091f6 Merge pull request #10795 from openfoodfoundation/dependabot/bundler/knapsack_pro-3.10.0
Bump knapsack_pro from 3.9.0 to 3.10.0
2023-05-03 14:31:11 +02:00
dependabot[bot]
eb3fe1b7a5 Bump knapsack_pro from 3.9.0 to 3.10.0
Bumps [knapsack_pro](https://github.com/KnapsackPro/knapsack_pro-ruby) from 3.9.0 to 3.10.0.
- [Release notes](https://github.com/KnapsackPro/knapsack_pro-ruby/releases)
- [Changelog](https://github.com/KnapsackPro/knapsack_pro-ruby/blob/master/CHANGELOG.md)
- [Commits](https://github.com/KnapsackPro/knapsack_pro-ruby/compare/v3.9.0...v3.10.0)

---
updated-dependencies:
- dependency-name: knapsack_pro
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-03 10:06:11 +00:00
dependabot[bot]
61f34a23a7 Bump @babel/core from 7.21.5 to 7.21.8
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.21.5 to 7.21.8.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.21.8/packages/babel-core)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-03 09:57:57 +00:00
Jean-Baptiste Bellet
2d7356f2bb Use the default webpack configuration for dev env
We used to override the output filename but this was a misunderstanding of an error (due to webpacke(r) incompatibles versions)

https://medium.com/@web_developer/hash-vs-chunkhash-vs-contenthash-e94d38a32208

https://github.com/webpack/webpack.js.org/issues/2096

Context: https://github.com/openfoodfoundation/openfoodnetwork/pull/10631#pullrequestreview-1410083331
2023-05-03 10:10:17 +02:00
jibees
62c2d9a290 Merge pull request #10782 from openfoodfoundation/dependabot/bundler/sidekiq-7.1.0
Bump sidekiq from 7.0.9 to 7.1.0
2023-05-03 09:56:07 +02:00
jibees
a329aab007 Merge pull request #10774 from openfoodfoundation/dependabot/npm_and_yarn/babel/core-7.21.5
Bump @babel/core and @babel/preset-env from 7.21.4 to 7.21.5
2023-05-03 09:26:10 +02:00
Maikel Linke
e24198fe85 Bump @babel/preset-env from 7.21.4 to 7.21.5
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.21.4 to 7.21.5.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.21.5/packages/babel-preset-env)

I did this manually:

```
$ yarn upgrade "@babel/preset-env"
yarn upgrade v1.22.19
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
warning " > stimulus_reflex@3.5.0-rc2" has unmet peer dependency "@hotwired/stimulus@>= 3.0".
[4/4] Rebuilding all packages...
success Saved lockfile.
success Saved 35 new dependencies.
info Direct dependencies
└─ @babel/preset-env@7.21.5
info All dependencies
├─ @babel/code-frame@7.21.4
├─ @babel/helper-builder-binary-assignment-operator-visitor@7.21.5
├─ @babel/helper-function-name@7.21.0
├─ @babel/helper-module-imports@7.21.4
├─ @babel/helper-replace-supers@7.21.5
├─ @babel/helper-string-parser@7.21.5
├─ @babel/helper-wrap-function@7.20.5
├─ @babel/highlight@7.18.6
├─ @babel/parser@7.21.5
├─ @babel/plugin-transform-arrow-functions@7.21.5
├─ @babel/plugin-transform-computed-properties@7.21.5
├─ @babel/plugin-transform-for-of@7.21.5
├─ @babel/plugin-transform-modules-commonjs@7.21.5
├─ @babel/plugin-transform-regenerator@7.21.5
├─ @babel/plugin-transform-unicode-escapes@7.21.5
├─ @babel/preset-env@7.21.5
├─ @babel/regjsgen@0.8.0
├─ @babel/template@7.20.7
├─ @babel/traverse@7.21.5
├─ @jridgewell/resolve-uri@3.1.0
├─ color-convert@1.9.3
├─ escape-string-regexp@1.0.5
├─ is-core-module@2.12.0
├─ js-tokens@4.0.0
├─ jsesc@2.5.2
├─ ms@2.1.2
├─ regenerate-unicode-properties@10.1.0
├─ regenerator-runtime@0.13.11
├─ regexpu-core@5.3.2
├─ regjsparser@0.9.1
├─ to-fast-properties@2.0.0
├─ unicode-canonical-property-names-ecmascript@2.0.0
├─ unicode-match-property-ecmascript@2.0.0
├─ unicode-match-property-value-ecmascript@2.1.0
└─ unicode-property-aliases-ecmascript@2.1.0
Done in 16.54s.
```
2023-05-03 15:33:57 +10:00
Maikel Linke
b30e962cdd Remove unknown (deleted) feature toggles at boot 2023-05-03 15:20:26 +10:00
Maikel Linke
5f1f717974 Spec FeatureToggle.setup! 2023-05-03 15:02:08 +10:00
Maikel Linke
b6f2fe0e92 Avoid defining modules in specs
We avoid some indent and show how code outside of the module works.
2023-05-03 14:58:59 +10:00
dependabot[bot]
a9bf7a2498 Bump @babel/core from 7.21.4 to 7.21.5
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.21.4 to 7.21.5.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.21.5/packages/babel-core)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-03 12:18:41 +10:00
David Cook
e11518938f Prettify admin components scss
Largely whitespace, but some other updates too, including uppercase colour codes and standardising numbers.

Best viewed with whitespace ignored.
2023-05-03 12:10:58 +10:00
David Cook
c4dc5e0718 Prettier: use double quotes by default
Unfortunately Prettier won't let you do one rule at a time (https://stackoverflow.com/q/63813336/421243), so I'll break it into file chunks.
2023-05-03 12:10:58 +10:00
David Cook
c67d61a376 Don't ignore admin scss for prettying
...and watch the changes flow in!
2023-05-03 12:09:22 +10:00
David Cook
0b4556e72b Allow line length up to 100char
Same as we have for Ruby code: https://github.com/openfoodfoundation/openfoodnetwork/blob/master/.rubocop_styleguide.yml#L78-L80

This will avoid unnecessary reformatting.
2023-05-03 12:09:22 +10:00
David Cook
8c7f92d42e Explicitly ignore each css folder
With the goal to progressively un-ignore them.
2023-05-03 12:09:22 +10:00
Konrad
21a0017352 Merge pull request #10756 from jibees/10743-admin-add-unregistered-users-modal-some-html-is-rendered-as-plain-text-instead-of-being
Admin, Add unregistered user: Fix a reflex-morph issue that lead to a HTML escaping error
2023-05-02 19:28:48 +02:00
Konrad
d115c4ce2c Merge pull request #10733 from jibees/9782-shops-list-overlapping-and-overflowing-texts-on-mobile2
Shops list: fix some overlapping and overflowing texts on mobile
2023-05-02 12:15:19 +02:00
dependabot[bot]
b05d46c3e3 Bump sidekiq from 7.0.9 to 7.1.0
Bumps [sidekiq](https://github.com/sidekiq/sidekiq) from 7.0.9 to 7.1.0.
- [Release notes](https://github.com/sidekiq/sidekiq/releases)
- [Changelog](https://github.com/sidekiq/sidekiq/blob/main/Changes.md)
- [Commits](https://github.com/sidekiq/sidekiq/compare/v7.0.9...v7.1.0)

---
updated-dependencies:
- dependency-name: sidekiq
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-02 09:57:28 +00:00
jibees
aae0fc59fb Merge pull request #10768 from Matt-Yorkley/query-logs
Improve query logging in development
2023-05-02 11:44:19 +02:00
Gaetan Craig-Riou
d1f7cc1b2a Merge pull request #10764 from Matt-Yorkley/remove-data-hooks
Remove `data-hook` attributes
2023-05-02 16:35:46 +10:00
Gaetan Craig-Riou
964481f188 Merge pull request #10765 from Matt-Yorkley/update-webpack-packages
Update webpack packages
2023-05-02 15:19:37 +10:00
Maikel
9bca22ae3b Merge pull request #10775 from openfoodfoundation/dependabot/bundler/mini_portile2-2.8.2
Bump mini_portile2 from 2.8.1 to 2.8.2
2023-05-02 11:54:37 +10:00
dependabot[bot]
064c843c90 Bump mini_portile2 from 2.8.1 to 2.8.2
Bumps [mini_portile2](https://github.com/flavorjones/mini_portile) from 2.8.1 to 2.8.2.
- [Release notes](https://github.com/flavorjones/mini_portile/releases)
- [Changelog](https://github.com/flavorjones/mini_portile/blob/main/CHANGELOG.md)
- [Commits](https://github.com/flavorjones/mini_portile/compare/v2.8.1...v2.8.2)

---
updated-dependencies:
- dependency-name: mini_portile2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-01 10:02:13 +00:00
Maikel
482d438ec9 Merge pull request #10766 from filipefurtad0/remove_asertion_on_js_element_loading_orders
Removes assertions on transient JS element - "Loading orders"
2023-05-01 13:36:44 +10:00
Maikel Linke
9f0a66659a Delete now unused SessionCookieUpgrader 2023-05-01 13:35:52 +10:00
Konrad
1176ea2a5f Merge pull request #9941 from basilawwad/conditionally-send-cancellation-email
Conditionally send cancellation email when cancelling order.
2023-04-28 21:54:42 +02:00
Matt-Yorkley
dfc651ed2c Convert Permissions::Order#visible_line_items to a relation with or query
This change looks innocuous but the result of converting this into a nice relation instead of two queries stuck together with the pipe operator (|) can make a huge difference when chaining this into subqueries. The result set is ultimately the same, but the queries can be built without first returning all the ids and then sticking those ids in an array.
2023-04-28 19:13:22 +01:00
Matt-Yorkley
f42a9e3a66 Add query_count gem in development
A very simple gem that counts the total number of queries triggered by each request and displays a little number in the log. Nice.
2023-04-28 15:02:02 +01:00
Matt-Yorkley
8d9a8d8db5 Enable verbose query logs in development
This is a new feature in Rails 7. Whenever a query is triggered it not only show you the query (as before), but also tells you (directly in the logs) exactly which line of code was responsible for triggering the query. It's unbelievably useful for debugging and performance work.
2023-04-28 14:35:16 +01:00
Matt-Yorkley
84df1bfeab Remove SessionCookieUpgrader from middleware
This was a transitional bit of code to allow us to rename our session cookies without killing active sessions and logging users out. It's done it's job, the transition is finished, and it isn't doing anything useful now. It can be removed from the middleware stack.
2023-04-28 14:01:15 +01:00
Matt-Yorkley
b9431cd121 Remove data-hook attributes 2023-04-28 13:03:13 +01:00
filipefurtad0
74d18fb6ff Removes assertions on transient JS element 2023-04-28 12:48:59 +01:00
Matt-Yorkley
5e26e49764 Update webpack packages
`webpack-cli` is a dependency of `@rails/webpacker` but needs to be at version 3.x, we can just cut it from the explicit dependecy list and the correct version will be installed.

`webpack-dev-server` version 3.x corresponds (unhelpfully) to `webpacker` 4.x, and needs to be left that way. Dependabot tries to change it occasionally, but it should not be updated to 4.x
2023-04-28 12:48:21 +01:00
dependabot[bot]
c9dada4215 Bump ddtrace from 1.10.1 to 1.11.0
Bumps [ddtrace](https://github.com/DataDog/dd-trace-rb) from 1.10.1 to 1.11.0.
- [Release notes](https://github.com/DataDog/dd-trace-rb/releases)
- [Changelog](https://github.com/DataDog/dd-trace-rb/blob/master/CHANGELOG.md)
- [Commits](https://github.com/DataDog/dd-trace-rb/compare/v1.10.1...v1.11.0)

---
updated-dependencies:
- dependency-name: ddtrace
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-28 10:00:28 +00:00
Maikel Linke
630169f8bb Preserve encoding of stored reports
Active Storage reads stored strings as ASCII and that can clash with
Rails' default UTF-8 encoding when special characters are present.
2023-04-28 16:38:06 +10:00
Gaetan Craig-Riou
152af5e105 Merge pull request #10751 from mkllnk/mail-config
Remove unused feature to intercept emails
2023-04-28 16:28:41 +10:00
David Cook
918425fd93 Remove customised error message
We're now handling these values on the frontend, so can keep this simple.

fixes up:
 Add numericality validation for *
 Add translation for Active Record error message
2023-04-28 14:02:12 +10:00
David Cook
a46eef291c Remove localized number logic from calculators
The browser is now responsible for dealing with the decimal separator, for all numeric preferences (as input[type=number]; see Spree::Admin::BaseHelper::preference_field_tag). Calculators are the only place that numeric preferences are used.

It will enforce that only one comma or dot (depending on user's locale) is entered, thus avoiding any ambiguity, and mis-interpretation (eg 100,001 could be interpreted as more than 100 thousand or 100 with a decimal place).
2023-04-28 13:54:16 +10:00
Jean-Baptiste Bellet
959dcb82e1 Morph the form itself instead of morphing a parent DOM element
This seems to avoid HTML parsing error
2023-04-26 17:41:28 +02:00
Jean-Baptiste Bellet
30ba29382a Avoid name collision by renaming some classes with a prefix flex-
This classes should only be used with `.flex`
2023-04-26 09:52:24 +02:00
Jean-Baptiste Bellet
9584205a8e Use .flex class in utilities.scss file
No need to have multiple definition as already included
2023-04-26 09:51:28 +02:00
Jean-Baptiste Bellet
3644dbc0fd Small fix of a prettier formatter error 2023-04-26 09:51:17 +02:00
Jean-Baptiste Bellet
05a7276c9c Create an utilities.scss file that contains some utility classes
Finally Tailwind is coming? ;)
2023-04-26 09:47:23 +02:00
Maikel Linke
dae8703b02 Remove unused feature to intercept emails
This option came from Spree and we never used it. The config input field
is disabled in the admin interface and I checked our managed databases.

I don't think that we will want this feature in the future either.
Staging sends unmodified emails which is more realistic and we haven't
had a use case to intercept those emails. There's still the BCC option
if we need additional access.
2023-04-26 13:50:31 +10:00
Jean-Baptiste Bellet
1730c9eb60 Fix one warning: Modal window with text has been opened, ...
```
Modal window with text `An invoice for this order will be sent to the customer. Are you sure you want to continue?` has been opened, but you didn't wrap your code into (`accept_prompt` | `dismiss_prompt` | `accept_confirm` | `dismiss_confirm` | `accept_alert`), accepting by default
```
2023-04-24 15:18:35 +02:00
Jean-Baptiste Bellet
5b9815f4a3 Test that restock has been called or not, depending on checkbox checked 2023-04-24 15:03:14 +02:00
Jean-Baptiste Bellet
2cc509de15 Do not check Metrics/BlockLength for shared_examples_for block
They can contains a lot of `it` tests
2023-04-21 11:59:24 +02:00
Jean-Baptiste Bellet
b17b25516f Use a UTF-8 character 2023-04-21 10:37:20 +02:00
Jean-Baptiste Bellet
8444fca19a Fix syntax error 2023-04-21 10:36:47 +02:00
Jean-Baptiste Bellet
18d90114fe Be more responsive: use flex, ellipsis, less columns 2023-04-21 10:36:21 +02:00
Jean-Baptiste Bellet
81606e841a Canceling an order: clicking on cancel btn or cancel action in dropdown 2023-04-20 14:38:59 +02:00
basilawwad
e633670e01 Use a shared_examples for the order cancellation tests 2023-04-20 14:38:59 +02:00
basilawwad
fa373518fb applied modal function
Update variant_autocomplete.js.erb

Applied modal function

refactored function

fix indentation and removed old function
2023-04-20 11:46:02 +02:00
David Cook
43e51cb592 Simplify login spec helpers, avoid long lines
Follow on from 5c6d9a092e
2023-04-18 10:01:23 +10:00
David Cook
6570891349 Fix linter issues
Although I don't think the size was an issue here, small hashes can easily fit on one line.
2023-04-18 09:50:08 +10:00
David Cook
0f3e2ae572 Use browser validation for calculator values
They're all numbers, so we can reliably validate in the browser, removing the need for additional validation logic.
They will still be validated server-side, and in the unlikely even that there is an error, the generic 'Calculator is invalid' message will appear, with the relevant fields highlighted red. I think that's fine.
2023-04-18 09:50:08 +10:00
David Cook
f0110d20a2 Move config to base helper
This config is relevant for all specs, including system specs.
2023-04-18 09:50:08 +10:00
David Cook
353acfd6ae Validate associated calculator with built in error handling
Except that pesky generic message was appearing. I still don't know how to control that so just deleted it.
2023-04-18 09:39:39 +10:00
David Cook
e43a018dc7 [wip] Copy each calculator error
But we still have the duplicate problem.
Wait a minute, it copies them in the same format that I am copying them. So.. I don't need to copy them at all!

Now I see that we just needed the right format in the translation file.
2023-04-18 09:39:39 +10:00
David Cook
f6fac018ea [wip] Use a custom message format for associated errors
This is much simpler. Multiple messages get combined onto one line though, which is not perfect.

And.. it still seems to duplicate the errors. Weird, it's fine on my frontend though.
2023-04-18 09:39:39 +10:00
David Cook
ce1bd12760 Consolidate specs
It takes time to set up this test case. Given that there's no interactions in the expectations, we should save time to generate it only once.
2023-04-18 09:39:39 +10:00
David Cook
364ccc2146 Add comment 2023-04-18 09:39:39 +10:00
James Wu
2a7cb50fa9 Keep and display submitted data on new payment method page 2023-04-18 09:39:39 +10:00
James Wu
29ddc68d20 Fix duplicate validation error message 2023-04-18 09:39:39 +10:00
James Wu
d40f3414ea fixup! Add translation for Active Record error message 2023-04-18 09:39:39 +10:00
James Wu
f5e2edb028 fixup! Modify Calculator validation error messages [wip]
DC: the error message has now become "Amount Invalid input".
2023-04-18 09:39:39 +10:00
James Wu
7af26e6579 Add errors for invalid input with number localization enabled 2023-04-18 09:39:39 +10:00
James Wu
824d4adf21 Rename spec file 2023-04-18 09:39:39 +10:00
James Wu
00cc8da2fc Fix rubocop class length error 2023-04-18 09:39:39 +10:00
James Wu
ae5f2cc19d Fix error saving data on new Calculator 2023-04-18 09:39:39 +10:00
James Wu
41ce4fbc16 Fix cache issue with invalid form data 2023-04-18 09:39:39 +10:00
James Wu
48753df5f0 Improve input validation and error notification 2023-04-18 09:39:39 +10:00
James Wu
1f3e66316b Modify Calculator validation error messages 2023-04-18 09:39:39 +10:00
James Wu
6b1426d0c6 Add numericality validation for PriceSack 2023-04-18 09:39:39 +10:00
James Wu
c68987c0f2 Add numericality validation for PerItem 2023-04-18 09:39:39 +10:00
James Wu
2cb25e6366 Add numericality validation for FlexiRate 2023-04-18 09:39:39 +10:00
James Wu
073f46e590 Add numericality validation for FlatRate 2023-04-18 09:39:39 +10:00
James Wu
23beea8a13 Add numericality validation for FlatPercentPerItem 2023-04-18 09:39:39 +10:00
James Wu
096e388fdf Add numericality validation for FlatPercentItemTotal 2023-04-18 09:39:39 +10:00
James Wu
3dfaf882a3 Add translation for Active Record error message 2023-04-18 09:39:39 +10:00
James Wu
7b51f45b4d Fix spelling in test description 2023-04-18 09:39:39 +10:00
James Wu
b9b2fa7c94 Fix error converting String to BigDecimal 2023-04-18 09:39:39 +10:00
James Wu
ee30d3d139 Fix PaymentMethodFactory creating extra Calculator 2023-04-18 09:39:39 +10:00
209 changed files with 2669 additions and 2702 deletions

View File

@@ -5,6 +5,8 @@
#
# cp .env.development .env.local
VERBOSE_QUERY_LOGS=true
SECRET_TOKEN="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
OFN_REDIS_URL="redis://localhost:6379/1"

View File

@@ -1,8 +1,5 @@
# Basically, ignore everythings expect app/webpacker/controllers/*.js and app/webpacker/packs/*.js
*.css
*.scss
# Except v2
!/app/webpacker/css/admin/v2/**/*.scss
*.md
*.yml
*.yaml
@@ -12,6 +9,10 @@
babel.config.js
postcss.config.js
/app/webpacker/css/darkswarm/
/app/webpacker/css/mail/
/app/webpacker/css/shared/
/app/assets/
/config/
/coverage/

View File

@@ -1 +1,3 @@
{}
{
"printWidth": 100
}

View File

@@ -40,6 +40,7 @@ Metrics/BlockLength:
"resources",
"scenario",
"shared_examples",
"shared_examples_for",
"xdescribe",
]

View File

@@ -178,6 +178,7 @@ group :development do
gem 'foreman'
gem 'listen'
gem 'pry', '~> 0.13.0'
gem 'query_count'
gem 'rails-erd'
gem 'rubocop'
gem 'rubocop-rails'

View File

@@ -157,16 +157,16 @@ GEM
awesome_nested_set (3.5.0)
activerecord (>= 4.0.0, < 7.1)
aws-eventstream (1.2.0)
aws-partitions (1.750.0)
aws-sdk-core (3.171.0)
aws-partitions (1.760.0)
aws-sdk-core (3.171.1)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.5)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.63.0)
aws-sdk-kms (1.64.0)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.121.0)
aws-sdk-s3 (1.122.0)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
@@ -235,13 +235,13 @@ GEM
database_cleaner-core (~> 2.0.0)
database_cleaner-core (2.0.1)
date (3.3.3)
ddtrace (1.10.1)
ddtrace (1.11.1)
debase-ruby_core_source (>= 0.10.16, <= 3.2.0)
libdatadog (~> 2.0.0.1.0)
libddwaf (~> 1.6.2.0.0)
libddwaf (~> 1.8.2.0.0)
msgpack
debase-ruby_core_source (3.2.0)
debug (1.7.2)
debug (1.8.0)
irb (>= 1.5.0)
reline (>= 0.3.1)
debugger-linecache (1.2.0)
@@ -349,7 +349,7 @@ GEM
activerecord (>= 3.0)
io-console (0.6.0)
ipaddress (0.8.3)
irb (1.6.3)
irb (1.6.4)
reline (>= 0.3.0)
jmespath (1.6.2)
jquery-rails (4.4.0)
@@ -373,14 +373,14 @@ GEM
jsonapi-serializer (2.2.0)
activesupport (>= 4.2)
jwt (2.7.0)
knapsack_pro (3.9.0)
knapsack_pro (3.11.0)
rake
launchy (2.5.0)
addressable (~> 2.7)
letter_opener (1.8.1)
launchy (>= 2.2, < 3)
libdatadog (2.0.0.1.0)
libddwaf (1.6.2.0.0)
libddwaf (1.8.2.0.0)
ffi (~> 1.0)
libv8-node (16.10.0.0)
listen (3.8.0)
@@ -405,7 +405,7 @@ GEM
rake
mini_magick (4.11.0)
mini_mime (1.1.2)
mini_portile2 (2.8.1)
mini_portile2 (2.8.2)
mini_racer (0.6.3)
libv8-node (~> 16.10.0.0)
minitest (5.18.0)
@@ -413,7 +413,7 @@ GEM
money (~> 6.12)
money (6.16.0)
i18n (>= 0.6.4, <= 2)
msgpack (1.6.1)
msgpack (1.7.0)
multi_json (1.15.0)
multi_xml (0.6.0)
net-imap (0.3.4)
@@ -487,6 +487,9 @@ GEM
public_suffix (5.0.1)
puma (6.2.2)
nio4r (~> 2.0)
query_count (1.1.1)
activerecord (>= 4.2)
railties (>= 4.2)
raabro (1.4.0)
racc (1.6.2)
rack (2.2.7)
@@ -585,20 +588,20 @@ GEM
rspec-mocks (~> 3.12.0)
rspec-core (3.12.2)
rspec-support (~> 3.12.0)
rspec-expectations (3.12.2)
rspec-expectations (3.12.3)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.12.0)
rspec-mocks (3.12.3)
rspec-mocks (3.12.5)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.12.0)
rspec-rails (6.0.1)
rspec-rails (6.0.2)
actionpack (>= 6.1)
activesupport (>= 6.1)
railties (>= 6.1)
rspec-core (~> 3.11)
rspec-expectations (~> 3.11)
rspec-mocks (~> 3.11)
rspec-support (~> 3.11)
rspec-core (~> 3.12)
rspec-expectations (~> 3.12)
rspec-mocks (~> 3.12)
rspec-support (~> 3.12)
rspec-retry (0.6.2)
rspec-core (> 3.3)
rspec-support (3.12.0)
@@ -652,11 +655,11 @@ GEM
semantic_range (3.0.0)
shoulda-matchers (5.3.0)
activesupport (>= 5.2.0)
sidekiq (7.0.9)
sidekiq (7.1.0)
concurrent-ruby (< 2)
connection_pool (>= 2.3.0)
rack (>= 2.2.4)
redis-client (>= 0.11.0)
redis-client (>= 0.14.0)
sidekiq-scheduler (5.0.2)
rufus-scheduler (~> 3.2)
sidekiq (>= 6, < 8)
@@ -765,7 +768,7 @@ GEM
xml-simple (1.1.8)
xpath (3.2.0)
nokogiri (~> 1.8)
zeitwerk (2.6.7)
zeitwerk (2.6.8)
PLATFORMS
ruby
@@ -857,6 +860,7 @@ DEPENDENCIES
private_address_check
pry (~> 0.13.0)
puma
query_count
rack-mini-profiler (< 3.0.0)
rack-rewrite
rack-timeout

View File

@@ -15,7 +15,7 @@ $(document).ready(function() {
console.log(msg);
});
}
$('[data-hook=admin_order_edit_form] a.ship').click(handle_ship_click);
$('.admin-order-edit-form a.ship').click(handle_ship_click);
//handle shipping method edit click
$('a.edit-method').click(toggleMethodEdit);
@@ -37,7 +37,7 @@ $(document).ready(function() {
console.log(msg);
});
}
$('[data-hook=admin_order_edit_form] a.save-method').click(handle_shipping_method_save);
$('.admin-order-edit-form a.save-method').click(handle_shipping_method_save);
//handle tracking info edit/delete
@@ -64,8 +64,8 @@ $(document).ready(function() {
return Spree.url( Spree.routes.orders_api + "/" + order_number + "/shipments/" + shipmentNumber + ".json");
}
$('[data-hook=admin_order_edit_form] a.save-tracking').click(saveTrackingInfo);
$('[data-hook=admin_order_edit_form] a.delete-tracking').click(deleteTrackingInfo);
$('.admin-order-edit-form a.save-tracking').click(saveTrackingInfo);
$('.admin-order-edit-form a.delete-tracking').click(deleteTrackingInfo);
// handle note edit/delete
@@ -96,8 +96,8 @@ $(document).ready(function() {
});
}
$('[data-hook=admin_order_edit_form] a.save-note').click(saveNote);
$('[data-hook=admin_order_edit_form] a.delete-note').click(deleteNote);
$('.admin-order-edit-form a.save-note').click(saveNote);
$('.admin-order-edit-form a.delete-note').click(deleteNote);
// Makes API call for notes/tracking info
makeApiCall = function(url, params) {

View File

@@ -4,7 +4,8 @@ $(document).ready(function() {
initAlert()
initConfirm()
initCancelOrder()
initButtonCancel()
initLinkCancel()
if ($('#variant_autocomplete_template').length > 0) {
window.variantTemplate = Handlebars.compile($('#variant_autocomplete_template').text());
@@ -276,17 +277,23 @@ ofnConfirm = function(callback) {
$('#custom-confirm').show();
}
initCancelOrder = function() {
$('#cancel_order_form').submit(function(e){
ofnCancelOrderAlert((confirm, sendEmailCancellation, restock_items) => {
if (confirm) {
var redirectTo = new URL(Spree.routes.cancel_order.toString());
redirectTo.searchParams.append("send_cancellation_email", sendEmailCancellation);
redirectTo.searchParams.append("restock_items", restock_items);
window.location.href = redirectTo.toString();
}
});
e.preventDefault();
return false;
initCancelAction = function(e){
ofnCancelOrderAlert((confirm, sendEmailCancellation, restock_items) => {
if (confirm) {
var redirectTo = new URL(Spree.routes.cancel_order.toString());
redirectTo.searchParams.append("send_cancellation_email", sendEmailCancellation);
redirectTo.searchParams.append("restock_items", restock_items);
window.location.href = redirectTo.toString();
}
});
e.preventDefault();
return false;
};
initButtonCancel = function() {
$('#cancel_order_form').submit(initCancelAction)
}
initLinkCancel = function() {
$('#links-dropdown a[href$="cancel"]').click(initCancelAction);
}

View File

@@ -18,6 +18,8 @@ module Admin
end
end
ContentConfig.updated_at = Time.zone.now
flash[:success] =
t(:successfully_updated, resource: I18n.t('admin.contents.edit.your_content'))

View File

@@ -65,6 +65,7 @@ module Spree
params.require(:order).permit(
:email,
:use_billing,
:customer_id,
bill_address_attributes: ::PermittedAttributes::Address.attributes,
ship_address_attributes: ::PermittedAttributes::Address.attributes
)

View File

@@ -7,7 +7,6 @@ module Spree
before_action :load_data
before_action :validate_payment_method_provider, only: [:create]
before_action :load_hubs, only: [:new, :edit, :update]
before_action :validate_calculator_preferred_value, only: [:update]
respond_to :html
@@ -17,6 +16,10 @@ module Spree
@payment_method = payment_method_class.constantize.new(base_params)
@object = @payment_method
if !base_params["calculator_type"] && gateway_params["calculator_type"]
@payment_method.calculator_type = gateway_params["calculator_type"]
end
load_hubs
if @payment_method.save
@@ -44,6 +47,7 @@ module Spree
redirect_to spree.edit_admin_payment_method_path(@payment_method)
else
respond_with(@payment_method)
clear_preference_cache
end
end
@@ -182,33 +186,23 @@ module Spree
end
end
# Ensure the calculator to be updated is the correct type
if params_for_update["calculator_type"] && params_for_update["calculator_attributes"]
add_type_to_calculator_attributes(params_for_update)
end
params_for_update
end
end
def validate_calculator_preferred_value
return if calculator_preferred_values.all? do |value|
preferred_value_from_params = gateway_params.dig(:calculator_attributes, value)
preferred_value_from_params.nil? || Float(preferred_value_from_params,
exception: false)
def clear_preference_cache
@payment_method.calculator.preferences.each_key do |key|
Rails.cache.delete(@payment_method.calculator.preference_cache_key(key))
end
flash[:error] = I18n.t(:calculator_preferred_value_error)
redirect_to spree.edit_admin_payment_method_path(@payment_method)
end
def calculator_preferred_values
[
:preferred_amount,
:preferred_flat_percent,
:preferred_flat_percent,
:preferred_first_item,
:preferred_additional_item,
:preferred_max_items,
:preferred_normal_amount,
:preferred_discount_amount,
:preferred_minimal_amount
]
def add_type_to_calculator_attributes(hash)
hash["calculator_attributes"]["type"] = hash["calculator_type"]
end
end
end

View File

@@ -68,4 +68,14 @@ module ApplicationHelper
wicked_pdf_stylesheet_pack_tag(source)
end
end
def cache_with_locale(key = nil, options = {}, &block)
cache(cache_key_with_locale(key, I18n.locale), options) do
yield(block)
end
end
def cache_key_with_locale(key, locale)
Array.wrap(key) + [locale.to_s, I18nDigests.for_locale(locale)]
end
end

View File

@@ -29,8 +29,8 @@ module Spree
def preference_field_tag(name, value, options)
case options[:type]
when :integer
text_field_tag(name, value, preference_field_options(options))
when :integer, :decimal
number_field_tag(name, value, preference_field_options(options))
when :boolean
hidden_field_tag(name, 0) +
check_box_tag(name, 1, value, preference_field_options(options))
@@ -49,8 +49,8 @@ module Spree
def preference_field_for(form, field, options, object)
case options[:type]
when :integer
form.text_field(field, preference_field_options(options))
when :integer, :decimal
form.number_field(field, preference_field_options(options))
when :boolean
form.check_box(field, preference_field_options(options))
when :string
@@ -80,26 +80,24 @@ module Spree
end
def preference_field_options(options)
field_options = case options[:type]
when :integer
{ size: 10,
class: 'input_integer' }
when :boolean
{}
when :string
{ size: 10,
class: 'input_string fullwidth' }
when :password
{ size: 10,
class: 'password_string fullwidth' }
when :text
{ rows: 15,
cols: 85,
class: 'fullwidth' }
else
{ size: 10,
class: 'input_string fullwidth' }
end
field_options =
case options[:type]
when :integer
{ size: 10, class: 'input_integer', step: 1 }
when :decimal
# Allow any number of decimal places
{ size: 10, class: 'input_integer', step: :any }
when :boolean
{}
when :string
{ size: 10, class: 'input_string fullwidth' }
when :password
{ size: 10, class: 'password_string fullwidth' }
when :text
{ rows: 15, cols: 85, class: 'fullwidth' }
else
{ size: 10, class: 'input_string fullwidth' }
end
field_options.merge!(
readonly: options[:readonly],

View File

@@ -105,8 +105,7 @@ module Spree
def cancel_order_link
{ name: t(:cancel_order),
url: spree.fire_admin_order_path(@order.number, e: 'cancel'),
icon: 'icon-trash',
confirm: t(:are_you_sure) }
icon: 'icon-trash' }
end
def cancel_event_link

View File

@@ -1,14 +1,11 @@
# frozen_string_literal: false
require 'spree/localized_number'
module Calculator
class FlatPercentItemTotal < Spree::Calculator
extend Spree::LocalizedNumber
preference :flat_percent, :decimal, default: 0
localize_number :preferred_flat_percent
validates :preferred_flat_percent,
numericality: true
def self.description
Spree.t(:flat_percent)

View File

@@ -1,18 +1,15 @@
# frozen_string_literal: true
require 'spree/localized_number'
class Calculator::FlatPercentPerItem < Spree::Calculator
# Spree's FlatPercentItemTotal calculator sums all amounts, and then calculates a percentage
# on them.
# In the cart, we display line item individual amounts rounded, so to have consistent
# calculations we do the same internally. Here, we round adjustments at the individual
# item level first, then multiply by the item quantity.
extend Spree::LocalizedNumber
preference :flat_percent, :decimal, default: 0
localize_number :preferred_flat_percent
validates :preferred_flat_percent,
numericality: true
def self.description
I18n.t(:flat_percent_per_item)

View File

@@ -1,14 +1,11 @@
# frozen_string_literal: false
require 'spree/localized_number'
module Calculator
class FlatRate < Spree::Calculator
extend Spree::LocalizedNumber
preference :amount, :decimal, default: 0
localize_number :preferred_amount
validates :preferred_amount,
numericality: true
def self.description
I18n.t(:flat_rate_per_order)

View File

@@ -1,17 +1,14 @@
# frozen_string_literal: false
require 'spree/localized_number'
module Calculator
class FlexiRate < Spree::Calculator
extend Spree::LocalizedNumber
preference :first_item, :decimal, default: 0.0
preference :additional_item, :decimal, default: 0.0
preference :max_items, :integer, default: 0
localize_number :preferred_first_item,
:preferred_additional_item
validates :preferred_first_item,
:preferred_additional_item,
numericality: true
def self.description
I18n.t(:flexible_rate)

View File

@@ -1,14 +1,11 @@
# frozen_string_literal: false
require 'spree/localized_number'
module Calculator
class PerItem < Spree::Calculator
extend Spree::LocalizedNumber
preference :amount, :decimal, default: 0
localize_number :preferred_amount
validates :preferred_amount,
numericality: true
def self.description
I18n.t(:flat_rate_per_item)

View File

@@ -1,18 +1,15 @@
# frozen_string_literal: false
require 'spree/localized_number'
module Calculator
class PriceSack < Spree::Calculator
extend Spree::LocalizedNumber
preference :minimal_amount, :decimal, default: 0
preference :normal_amount, :decimal, default: 0
preference :discount_amount, :decimal, default: 0
localize_number :preferred_minimal_amount,
:preferred_normal_amount,
:preferred_discount_amount
validates :preferred_minimal_amount,
:preferred_normal_amount,
:preferred_discount_amount,
numericality: true
def self.description
I18n.t(:price_sack)

View File

@@ -83,4 +83,19 @@ class ContentConfiguration < Spree::Preferences::Configuration
# User Guide
preference :user_guide_link, :string, default: 'https://guide.openfoodnetwork.org/'
# ContentConfig Caching
preference :updated_at_timestamp, :integer, default: Time.zone.today.to_time.to_i
def updated_at
Time.zone.at updated_at_timestamp
end
def updated_at=(time)
self.updated_at_timestamp = time.to_i
end
def cache_key
"ContentConfig:#{updated_at_timestamp}"
end
end

View File

@@ -31,6 +31,6 @@ class ReportBlob < ActiveStorage::Blob
end
def result
@result ||= download
@result ||= download.force_encoding(Encoding::UTF_8)
end
end

View File

@@ -88,7 +88,6 @@ module Spree
# Default mail headers settings
preference :mails_from, :string, default: 'ofn@example.com'
preference :mail_bcc, :string, default: 'ofn@example.com'
preference :intercept_email, :string, default: nil
# Default smtp settings
preference :mail_host, :string, default: 'localhost'

View File

@@ -17,6 +17,7 @@ module Spree
validates :name, presence: true
validate :distributor_validation
validates_associated :calculator
after_initialize :init
@@ -40,9 +41,8 @@ module Spree
where(id: non_unique_matches.map(&:id))
}
scope :for_distributor, lambda { |distributor|
joins(:distributors).
where('enterprises.id = ?', distributor)
scope :for_distributor, ->(distributor) {
joins(:distributors).where('enterprises.id = ?', distributor)
}
scope :for_subscriptions, -> { where(type: Subscription::ALLOWED_PAYMENT_METHOD_TYPES) }

View File

@@ -22,7 +22,8 @@ module Spree
when :password
self[:value].to_s
when :decimal
BigDecimal(self[:value].to_s).round(2, BigDecimal::ROUND_HALF_UP)
BigDecimal(self[:value].to_s, exception: false)&.round(2, BigDecimal::ROUND_HALF_UP) ||
self[:value]
when :integer
self[:value].to_i
when :boolean

View File

@@ -117,7 +117,7 @@ module Spree
value.to_s
when :decimal
value = 0 if value.blank?
BigDecimal(value.to_s).round(2, BigDecimal::ROUND_HALF_UP)
BigDecimal(value.to_s, exception: false)&.round(2, BigDecimal::ROUND_HALF_UP) || value
when :integer
value.to_i
when :boolean

View File

@@ -22,7 +22,6 @@ class MailConfiguration
secure_connection_type: ENV.fetch('MAIL_SECURE_CONNECTION', 'None'),
mails_from: ENV.fetch('MAILS_FROM', "no-reply@#{ENV.fetch('MAIL_DOMAIN')}"),
mail_bcc: ENV.fetch('MAIL_BCC', ''),
intercept_email: ''
}
end

View File

@@ -31,9 +31,7 @@ module Permissions
end
def visible_line_items
Spree::LineItem.where(id:
editable_line_items.select(:id) |
produced_line_items.select("spree_line_items.id"))
editable_line_items.or(produced_line_items)
end
# Any line items that I can edit

View File

@@ -8,6 +8,6 @@
- @preference_sections.each do |preference_section|
= render 'fieldset', name: preference_section[:name], preferences: preference_section[:preferences]
.form-buttons.filter-actions.actions{"data-hook" => "buttons"}
.form-buttons.filter-actions.actions
= button t(:update), 'icon-refresh'
= link_to_with_icon 'icon-remove', t(:cancel), main_app.edit_admin_contents_path, class: 'button'

View File

@@ -10,7 +10,7 @@
%col{style: "width: 18%;"}/
%col{style: "width: 25%;"}/
%thead
%tr{"data-hook" => "enterprises_header"}
%tr
%th= t('.name')
%th= t('.role')
- if spree_current_user.admin?
@@ -32,7 +32,7 @@
%td= enterprise_form.check_box :visible, {}, 'public', 'hidden'
- if spree_current_user.admin?
%td= enterprise_form.select :owner_id, enterprise.users.map{ |e| [ e.email, e.id ] }, {}, class: "select2 fullwidth"
%td{"data-hook" => "admin_users_index_row_actions"}
%td
= render 'actions', enterprise: enterprise
- if @enterprises.empty?
%tr

View File

@@ -1,22 +1,21 @@
%div#add_manager_modal
%form{ "data-reflex": "submit->InviteManager#invite", "data-reflex-serialize-form": true }
.margin-bottom-30.text-center
.text-big
= t('js.admin.modals.invite_title')
%form#add_manager_modal{ 'data-reflex': 'submit->InviteManager#invite', 'data-reflex-serialize-form': true }
.margin-bottom-30.text-center
.text-big
= t('js.admin.modals.invite_title')
- if success
%p.alert-box.ok= t('user_invited', email: email)
- if error
%p.alert-box.error= error
= text_field_tag :email, nil, class: 'fullwidth margin-bottom-20'
= hidden_field_tag :enterprise_id, @enterprise&.id || enterprise.id
.modal-actions
- if success
%p.alert-box.ok= t('user_invited', email: email)
- if error
%p.alert-box.error= error
= text_field_tag :email, nil, class: 'fullwidth margin-bottom-20'
= hidden_field_tag :enterprise_id, @enterprise&.id || enterprise.id
.modal-actions
- if success
%input{ class: "button icon-plus secondary", type: 'button', value: t('js.admin.modals.close'), "data-action": "click->help-modal#close" }
- else
%input{ class: "button icon-plus secondary", type: 'button', value: t('js.admin.modals.cancel'), "data-action": "click->help-modal#close" }
= submit_tag "#{t('js.admin.modals.invite')}"
%input{ class: "button icon-plus secondary", type: 'button', value: t('js.admin.modals.close'), "data-action": "click->help-modal#close" }
- else
%input{ class: "button icon-plus secondary", type: 'button', value: t('js.admin.modals.cancel'), "data-action": "click->help-modal#close" }
= submit_tag "#{t('js.admin.modals.invite')}"

View File

@@ -20,5 +20,5 @@
= check_box_tag 'preferences[enterprise_number_required_on_invoices?]', '1', Spree::Config[:enterprise_number_required_on_invoices?]
= label_tag nil, t('.enterprise_number_required_on_invoices?')
.form-buttons{"data-hook" => "buttons"}
.form-buttons
= button t(:update), 'icon-refresh'

View File

@@ -23,5 +23,5 @@
= preference_field_tag("preferences[#{:matomo_tag_manager_url}]", Spree::Config[:matomo_tag_manager_url], type: Spree::Config.preference_type(:matomo_tag_manager_url))
.warning.note= t('.config_instructions_tag_manager_html')
.form-buttons{"data-hook" => "buttons"}
.form-buttons
= button t(:update), 'icon-refresh'

View File

@@ -1,12 +1,12 @@
%fieldset.no-border-top
.add_producer_properties{"data-hook" => "add_producer_properties"}
.add_producer_properties
= image_pack_tag 'spinner.gif', :plugin => 'spree', :style => 'display:none;', :id => 'busy_indicator'
%table.index.sortable{"data-hook" => "", "data-sortable-link" => main_app.update_positions_admin_enterprise_producer_properties_url(@enterprise)}
%table.index.sortable{"data-sortable-link" => main_app.update_positions_admin_enterprise_producer_properties_url(@enterprise)}
%thead
%tr{"data-hook" => "producer_properties_header"}
%tr
%th{colspan: "2"}= t('admin.products.properties.property_name')
%th= t('admin.description')
%th.actions
%tbody#producer_properties{"data-hook" => ""}
%tbody#producer_properties
= f.fields_for :producer_properties do |pp_form|
= render 'admin/producer_properties/producer_property_fields', f: pp_form

View File

@@ -1,5 +1,5 @@
-# admin/admin.js.erb in spree requires id to start with "spree_" for sortable tables
%tr.product_property.fields{"data-hook" => "producer_property", id: "spree_#{dom_id(f.object)}"}
%tr.product_property.fields{id: "spree_#{dom_id(f.object)}"}
%td.no-border
%span.handle
= f.hidden_field :id

View File

@@ -1,5 +1,5 @@
- content_for :sub_menu do
%ul#sub_nav.inline-menu{"data-hook" => "admin_enterprise_sub_tabs"}
%ul#sub_nav.inline-menu
= tab :enterprises, url: main_app.admin_enterprises_path
= tab :enterprise_relationships, url: main_app.admin_enterprise_relationships_path
- if ENV["OPENID_APP_ID"].present? && ENV["OPENID_APP_SECRET"].present?

View File

@@ -1,4 +1,4 @@
- content_for :sub_menu do
%ul#sub_nav.inline-menu{"data-hook" => "admin_user_sub_tabs"}
%ul#sub_nav.inline-menu
= tab :users, url: spree.admin_users_path
= tab :roles, url: main_app.admin_enterprise_roles_path, match_path: '/enterprise_roles'

View File

@@ -14,7 +14,7 @@
= f.label :stripe_connect_enabled, t('.stripe_connect_enabled')
= f.check_box :stripe_connect_enabled, disabled: disabled
.row
.twelve.columns.alpha.omega.form-buttons{"data-hook" => "buttons"}
.twelve.columns.alpha.omega.form-buttons
= button t(:update), 'icon-refresh', value: "update"
%fieldset.no-border-bottom

View File

@@ -77,7 +77,7 @@
%td.price.align-center {{ item.price_estimate | localizeCurrency }}
%td.quantity {{ item.quantity }}
%td.total.align-center {{ (item.price_estimate * item.quantity) | localizeCurrency }}
%tbody#subtotal.no-border-top{"data-hook" => "admin_order_form_subtotal"}
%tbody#subtotal.no-border-top
%tr#subtotal-row
%td{:colspan => "3"}
%b
@@ -85,7 +85,7 @@
\:
%td.total.align-center
%span {{ subscription.estimatedSubtotal() | localizeCurrency }}
%tbody#order-total.grand-total.no-border-top{"data-hook" => "admin_order_form_total"}
%tbody#order-total.grand-total.no-border-top
%tr
%td{:colspan => "3"}
%b

View File

@@ -25,7 +25,7 @@
%td.total.align-center {{ (item.price_estimate * item.quantity) | localizeCurrency }}
%td.actions
%a.delete-item.icon-trash.no-text{ ng: { click: 'removeSubscriptionLineItem(item)'}, :href => "javascript:void(0)" }
%tbody#subtotal.no-border-top{"data-hook" => "admin_order_form_subtotal"}
%tbody#subtotal.no-border-top
%tr#subtotal-row
%td{:colspan => "3"}
%b
@@ -43,7 +43,7 @@
%td.total.align-center
%span#order_fees {{ subscription.estimatedFees() | localizeCurrency }}
%td.actions
%tbody#order-total.grand-total.no-border-top{"data-hook" => "admin_order_form_total"}
%tbody#order-total.grand-total.no-border-top
%tr
%td{:colspan => "3"}
%b

View File

@@ -1 +1,2 @@
%img.spinner{ src: image_pack_path("spinning-circles.svg"), style: "max-width: 100%" }
= cache do
%img.spinner{ src: image_pack_path("spinning-circles.svg"), style: "max-width: 100%" }

View File

@@ -1,8 +1,9 @@
#tagline
.row
.small-12.text-center.columns
%h1
%img{src: image_pack_path("logo-white-notext.png"), title: Spree::Config.site_name}
%br/
%a.button.transparent{href: "/shops"}
= t :home_shop
= cache_with_locale "sitename:#{Spree::Config.site_name}" do
#tagline
.row
.small-12.text-center.columns
%h1
%img{src: image_pack_path("logo-white-notext.png"), title: Spree::Config.site_name}
%br/
%a.button.transparent{href: "/shops"}
= t :home_shop

View File

@@ -1,91 +1,92 @@
.row.active_table_row{"ng-if" => "open()", "ng-click" => "toggle($event)", "ng-class" => "{'open' : open()}"}
.columns.small-12.fat.text-center{"ng-show" => "open() && shopfront_loading"}
%p.fullwidth
= render partial: "components/spinner"
= cache_with_locale do
.row.active_table_row{"ng-if" => "open()", "ng-click" => "toggle($event)", "ng-class" => "{'open' : open()}"}
.columns.small-12.fat.text-center{"ng-show" => "open() && shopfront_loading"}
%p.fullwidth
= render partial: "components/spinner"
.columns.small-12.medium-7.large-7.fat{"ng-show" => "open() && !shopfront_loading"}
/ Will add in long description available once clean up HTML formatting producer.long_description
%div{"ng-if" => "::producer.description"}
%label
= t :producers_about
%img.right.show-for-medium-up{"ng-src" => "{{::producer.logo}}" }
%p.text-small{ "ng-bind" => "::producer.description"}
%div.show-for-medium-up{"ng-if" => "::producer.description.length==0"}
%label &nbsp;
%img.right.show-for-medium-up{"ng-src" => "{{::producer.logo}}" }
.columns.small-12.medium-7.large-7.fat{"ng-show" => "open() && !shopfront_loading"}
/ Will add in long description available once clean up HTML formatting producer.long_description
%div{"ng-if" => "::producer.description"}
%label
= t :producers_about
%img.right.show-for-medium-up{"ng-src" => "{{::producer.logo}}" }
%p.text-small{ "ng-bind" => "::producer.description"}
%div.show-for-medium-up{"ng-if" => "::producer.description.length==0"}
%label &nbsp;
%img.right.show-for-medium-up{"ng-src" => "{{::producer.logo}}" }
.columns.small-12.medium-5.large-5.fat{"ng-show" => "open() && !shopfront_loading"}
.columns.small-12.medium-5.large-5.fat{"ng-show" => "open() && !shopfront_loading"}
%div{"ng-if" => "::producer.supplied_taxons"}
%label
= t :producers_buy
%p.trans-sentence
%div
%span.fat-taxons{"ng-repeat" => "taxon in producer.supplied_taxons"}
%span{"ng-bind" => "::taxon.name"}
%div
%span.fat-properties{"ng-repeat" => "property in producer.supplied_properties"}
%span{"ng-bind" => "property.presentation"}
%div{"ng-if" => "::producer.supplied_taxons"}
%label
= t :producers_buy
%p.trans-sentence
%div
%span.fat-taxons{"ng-repeat" => "taxon in producer.supplied_taxons"}
%span{"ng-bind" => "::taxon.name"}
%div
%span.fat-properties{"ng-repeat" => "property in producer.supplied_properties"}
%span{"ng-bind" => "property.presentation"}
%div.show-for-medium-up{"ng-if" => "producer.supplied_taxons.length==0"}
&nbsp;
%div.show-for-medium-up{"ng-if" => "producer.supplied_taxons.length==0"}
&nbsp;
%div{"ng-if" => "::producer.email_address || producer.website || producer.phone"}
%label
= t :producers_contact
%div{"ng-if" => "::producer.email_address || producer.website || producer.phone"}
%label
= t :producers_contact
%p.word-wrap{"ng-if" => "::producer.phone"}
= t :producers_contact_phone
%span{"ng-bind" => "::producer.phone"}
%p.word-wrap{"ng-if" => "::producer.phone"}
= t :producers_contact_phone
%span{"ng-bind" => "::producer.phone"}
%p.word-wrap{"ng-if" => "::producer.whatsapp_phone"}
%a{"ng-href" => "{{::producer.whatsapp_url}}", target: "_blank"}
%img{ src: image_pack_path("social-logos/whatsapp.svg") }
%span{"ng-bind" => "::producer.whatsapp_phone"}
%p.word-wrap{"ng-if" => "::producer.whatsapp_phone"}
%a{"ng-href" => "{{::producer.whatsapp_url}}", target: "_blank"}
%img{ src: image_pack_path("social-logos/whatsapp.svg") }
%span{"ng-bind" => "::producer.whatsapp_phone"}
%p.word-wrap{"ng-if" => "::producer.email_address"}
%a{"ng-href" => "{{::producer.email_address | stripUrl}}", target: "_blank", mailto: true}
%span.obfuscatedEmail.email{"ng-bind" => "::producer.email_address | stripUrl"}
%p.word-wrap{"ng-if" => "::producer.email_address"}
%a{"ng-href" => "{{::producer.email_address | stripUrl}}", target: "_blank", mailto: true}
%span.obfuscatedEmail.email{"ng-bind" => "::producer.email_address | stripUrl"}
%p.word-wrap{"ng-if" => "::producer.website"}
%a{"ng-href" => "http://{{::producer.website | stripUrl}}", target: "_blank" }
%span{"ng-bind" => "::producer.website | stripUrl"}
%p.word-wrap{"ng-if" => "::producer.website"}
%a{"ng-href" => "http://{{::producer.website | stripUrl}}", target: "_blank" }
%span{"ng-bind" => "::producer.website | stripUrl"}
%div{"ng-if" => "::producer.twitter || producer.facebook || producer.linkedin || producer.instagram"}
%label
= t :producers_social
.follow-icons
%span{"ng-if" => "::producer.twitter"}
%a{"ng-href" => "http://twitter.com/{{::producer.twitter}}", target: "_blank"}
%i.ofn-i_041-twitter
%div{"ng-if" => "::producer.twitter || producer.facebook || producer.linkedin || producer.instagram"}
%label
= t :producers_social
.follow-icons
%span{"ng-if" => "::producer.twitter"}
%a{"ng-href" => "http://twitter.com/{{::producer.twitter}}", target: "_blank"}
%i.ofn-i_041-twitter
%span{"ng-if" => "::producer.facebook"}
%a{"ng-href" => "http://{{::producer.facebook | stripUrl}}", target: "_blank"}
%i.ofn-i_044-facebook
%span{"ng-if" => "::producer.facebook"}
%a{"ng-href" => "http://{{::producer.facebook | stripUrl}}", target: "_blank"}
%i.ofn-i_044-facebook
%span{"ng-if" => "::producer.linkedin"}
%a{"ng-href" => "http://{{::producer.linkedin | stripUrl}}", target: "_blank"}
%i.ofn-i_042-linkedin
%span{"ng-if" => "::producer.linkedin"}
%a{"ng-href" => "http://{{::producer.linkedin | stripUrl}}", target: "_blank"}
%i.ofn-i_042-linkedin
%span{"ng-if" => "::producer.instagram"}
%a{"ng-href" => "http://instagram.com/{{::producer.instagram}}", target: "_blank"}
%i.ofn-i_043-instagram
%span{"ng-if" => "::producer.instagram"}
%a{"ng-href" => "http://instagram.com/{{::producer.instagram}}", target: "_blank"}
%i.ofn-i_043-instagram
.row.active_table_row.pad-top{"ng-if" => "open() && producer.hubs && !shopfront_loading"}
.columns.small-12{"ng-if" => "producer.hubs.length > 0"}
.row
.columns.small-12.fat
%div{"ng-if" => "::producer.name"}
%label
= t :producers_buy_at_html, enterprise: '<span class="turquoise" ng-bind="::producer.name"></span>'.html_safe
%div.show-for-medium-up{"ng-if" => "::!producer.name"}
&nbsp;
.row.cta-container
.columns.small-12
%a.cta-hub{"ng-repeat" => "hub in producer.hubs | orderBy:'-active'",
"ng-href" => "{{::hub.path}}", "ng-attr-target" => "{{ embedded_layout ? '_blank' : undefined }}",
"ng-class" => "::{primary: hub.active, secondary: !hub.active}", "ofn-change-hub" => "hub"}
%i.ofn-i_068-shop-reversed{"ng-if" => "::hub.active"}
%i.ofn-i_068-shop-reversed{"ng-if" => "::!hub.active"}
.hub-name{"ng-bind" => "::hub.name"}
.button-address{"ng-bind" => "::[hub.address.city, hub.address.state_name] | printArray"}
.row.active_table_row.pad-top{"ng-if" => "open() && producer.hubs && !shopfront_loading"}
.columns.small-12{"ng-if" => "producer.hubs.length > 0"}
.row
.columns.small-12.fat
%div{"ng-if" => "::producer.name"}
%label
= t :producers_buy_at_html, enterprise: '<span class="turquoise" ng-bind="::producer.name"></span>'.html_safe
%div.show-for-medium-up{"ng-if" => "::!producer.name"}
&nbsp;
.row.cta-container
.columns.small-12
%a.cta-hub{"ng-repeat" => "hub in producer.hubs | orderBy:'-active'",
"ng-href" => "{{::hub.path}}", "ng-attr-target" => "{{ embedded_layout ? '_blank' : undefined }}",
"ng-class" => "::{primary: hub.active, secondary: !hub.active}", "ofn-change-hub" => "hub"}
%i.ofn-i_068-shop-reversed{"ng-if" => "::hub.active"}
%i.ofn-i_068-shop-reversed{"ng-if" => "::!hub.active"}
.hub-name{"ng-bind" => "::hub.name"}
.button-address{"ng-bind" => "::[hub.address.city, hub.address.state_name] | printArray"}

View File

@@ -1,115 +1,119 @@
%footer
.footer-global
.row
.small-12.columns.text-center
.logo
%img{src: image_pack_path("logo-white-notext.png") }
.row
.small-12.medium-8.medium-offset-2.columns.text-center
.alert-box
= render 'shared/register_call'
= cache_with_locale "global" do
.row
.small-12.columns.text-center
.logo
%img{src: image_pack_path("logo-white-notext.png") }
.row
.small-12.medium-8.medium-offset-2.columns.text-center
.alert-box
= render 'shared/register_call'
.footer-local
.row
.small-12.medium-2.medium-offset-2.columns.text-center
%p.secure-icon
%i.ofn-i_017-locked
.small-12.medium-6.columns.text-center
%p.text-big.secure-text
= t '.footer_secure'
%p.secure-text
= t '.footer_secure_text'
.small-12.medium-2.columns
= cache_with_locale "local" do
.row
.small-12.medium-2.medium-offset-2.columns.text-center
%p.secure-icon
%i.ofn-i_017-locked
.small-12.medium-6.columns.text-center
%p.text-big.secure-text
= t '.footer_secure'
%p.secure-text
= t '.footer_secure_text'
.small-12.medium-2.columns
.row
.small-12.medium-8.medium-offset-2.columns.text-center
%hr.hr-light
%br
.row
.small-12.medium-8.medium-offset-2.columns.text-center
%hr.hr-light
%br
.row
.small-6.medium-3.medium-offset-2.columns.text-left
// This is the instance-managed set of links:
%h4
= t '.footer_contact_headline'
- if show_social_icons?
%p.social-icons
- if ContentConfig.footer_facebook_url.present?
%a{href: ContentConfig.footer_facebook_url}
%i.ofn-i_044-facebook
- if ContentConfig.footer_twitter_url.present?
%a{href: ContentConfig.footer_twitter_url}
%i.ofn-i_041-twitter
- if ContentConfig.footer_instagram_url.present?
%a{href: ContentConfig.footer_instagram_url}
%i.ofn-i_043-instagram
- if ContentConfig.footer_linkedin_url.present?
%a{href: ContentConfig.footer_linkedin_url}
%i.ofn-i_042-linkedin
- if ContentConfig.footer_googleplus_url.present?
%a{href: ContentConfig.footer_googleplus_url}
%i.ofn-i_046-g
- if ContentConfig.footer_pinterest_url.present?
%a{href: ContentConfig.footer_pinterest_url}
%i.ofn-i_045-pintrest
- if ContentConfig.footer_email.present?
= cache_with_locale ContentConfig.cache_key do
.row
.small-6.medium-3.medium-offset-2.columns.text-left
// This is the instance-managed set of links:
%h4
= t '.footer_contact_headline'
- if show_social_icons?
%p.social-icons
- if ContentConfig.footer_facebook_url.present?
%a{href: ContentConfig.footer_facebook_url}
%i.ofn-i_044-facebook
- if ContentConfig.footer_twitter_url.present?
%a{href: ContentConfig.footer_twitter_url}
%i.ofn-i_041-twitter
- if ContentConfig.footer_instagram_url.present?
%a{href: ContentConfig.footer_instagram_url}
%i.ofn-i_043-instagram
- if ContentConfig.footer_linkedin_url.present?
%a{href: ContentConfig.footer_linkedin_url}
%i.ofn-i_042-linkedin
- if ContentConfig.footer_googleplus_url.present?
%a{href: ContentConfig.footer_googleplus_url}
%i.ofn-i_046-g
- if ContentConfig.footer_pinterest_url.present?
%a{href: ContentConfig.footer_pinterest_url}
%i.ofn-i_045-pintrest
- if ContentConfig.footer_email.present?
%p
%a{href: ContentConfig.footer_email.reverse, mailto: true, target: '_blank'}
= t '.footer_contact_email'
= render_markdown(ContentConfig.footer_links_md).html_safe
.small-6.medium-3.columns.text-left
%h4
= t '.footer_nav_headline'
%p
%a{href: ContentConfig.footer_email.reverse, mailto: true, target: '_blank'}
= t '.footer_contact_email'
= render_markdown(ContentConfig.footer_links_md).html_safe
%a{href: "/shops"}
= t :label_shops
%p
%a{href: "/map"}
= t :label_map
%p
%a{href: "/producers"}
= t :label_producers
%p
%a{href: "/groups"}
= t :label_groups
%p
%a{href: ContentConfig.footer_about_url}
= t :label_about
.small-12.medium-2.columns.text-left
%h4
= t '.footer_join_headline'
%p
= t '.footer_join_body'
%a{href: "/sell"}
= t '.footer_join_cta'
.small-6.medium-3.columns.text-left
%h4
= t '.footer_nav_headline'
%p
%a{href: "/shops"}
= t :label_shops
%p
%a{href: "/map"}
= t :label_map
%p
%a{href: "/producers"}
= t :label_producers
%p
%a{href: "/groups"}
= t :label_groups
%p
%a{href: ContentConfig.footer_about_url}
= t :label_about
.medium-2.columns.text-center
/ Placeholder
.small-12.medium-2.columns.text-left
%h4
= t '.footer_join_headline'
%p
= t '.footer_join_body'
%a{href: "/sell"}
= t '.footer_join_cta'
.row
.small-12.medium-8.medium-offset-2.columns.text-center
%hr.hr-light
%br
.medium-2.columns.text-center
/ Placeholder
.row
.small-12.medium-8.medium-offset-2.columns.text-center
%hr.hr-light
%br
.row.legal
.small-12.medium-3.medium-offset-2.columns.text-left
%a{href: main_app.root_path}
%img{src: ContentConfig.url_for(:footer_logo), width: "220"}
.small-12.medium-5.columns.text-left
%p.text-small
= t '.footer_legal_call'
= link_to_platform_terms
&#124;
= t '.footer_legal_visit'
%a{href:"https://github.com/openfoodfoundation/openfoodnetwork", target: "_blank"} GitHub
%p.text-small
= t('.footer_legal_text_html', content_license: link_to('CC BY-SA 3.0', 'https://creativecommons.org/licenses/by-sa/3.0/'), code_license: link_to('AGPL 3', 'https://tldrlegal.com/license/gnu-affero-general-public-license-v3-(agpl-3.0)' ))
%p.text-small
- if Spree::Config.privacy_policy_url.present?
= t('.footer_data_text_with_privacy_policy_html', cookies_policy: cookies_policy_link.html_safe, privacy_policy: privacy_policy_link.html_safe)
- else
= t('.footer_data_text_without_privacy_policy_html', cookies_policy: cookies_policy_link.html_safe)
.medium-2.columns.text-center
/ Placeholder
= cache_with_locale [ContentConfig.cache_key, TermsOfServiceFile.current_url, Spree::Config.privacy_policy_url] do
.row.legal
.small-12.medium-3.medium-offset-2.columns.text-left
%a{href: main_app.root_path}
%img{src: ContentConfig.url_for(:footer_logo), width: "220"}
.small-12.medium-5.columns.text-left
%p.text-small
= t '.footer_legal_call'
= link_to_platform_terms
&#124;
= t '.footer_legal_visit'
%a{href:"https://github.com/openfoodfoundation/openfoodnetwork", target: "_blank"} GitHub
%p.text-small
= t('.footer_legal_text_html', content_license: link_to('CC BY-SA 3.0', 'https://creativecommons.org/licenses/by-sa/3.0/'), code_license: link_to('AGPL 3', 'https://tldrlegal.com/license/gnu-affero-general-public-license-v3-(agpl-3.0)' ))
%p.text-small
- if Spree::Config.privacy_policy_url.present?
= t('.footer_data_text_with_privacy_policy_html', cookies_policy: cookies_policy_link.html_safe, privacy_policy: privacy_policy_link.html_safe)
- else
= t('.footer_data_text_without_privacy_policy_html', cookies_policy: cookies_policy_link.html_safe)
.medium-2.columns.text-center
/ Placeholder

View File

@@ -1,12 +1,13 @@
.alert-cta
%h6
-# Please forgive the hard-coded link:
-# The more elegant 'registration_path' resolves to /signup due to spree_auth_device > config > routes.rb
-# This is one of several possible fixes. Long-term, we'd like to bring the accounts page into OFN.
-# View the discussion here: https://github.com/openfoodfoundation/openfoodnetwork/pull/3174
%a{href: "/register", target: "_blank"}
= t '.selling_on_ofn'
&nbsp;
%strong
= t '.register'
%i.ofn-i_054-point-right
= cache_with_locale do
.alert-cta
%h6
-# Please forgive the hard-coded link:
-# The more elegant 'registration_path' resolves to /signup due to spree_auth_device > config > routes.rb
-# This is one of several possible fixes. Long-term, we'd like to bring the accounts page into OFN.
-# View the discussion here: https://github.com/openfoodfoundation/openfoodnetwork/pull/3174
%a{href: "/register", target: "_blank"}
= t '.selling_on_ofn'
&nbsp;
%strong
= t '.register'
%i.ofn-i_054-point-right

View File

@@ -1,8 +1,9 @@
%span.cart-span{"ng-controller" => "CartCtrl", "ng-class" => "{ dirty: Cart.dirty || Cart.empty(), 'pure-dirty': Cart.dirty }"}
%a#cart.icon{"ng-click" => "toggleCartSidebar()"}
%span
= t '.cart'
%span.count
%img{ src: image_pack_path("menu/icn-cart.svg") }
= cache_with_locale do
%span.cart-span{"ng-controller" => "CartCtrl", "ng-class" => "{ dirty: Cart.dirty || Cart.empty(), 'pure-dirty': Cart.dirty }"}
%a#cart.icon{"ng-click" => "toggleCartSidebar()"}
%span
{{ Cart.total_item_count() }}
= t '.cart'
%span.count
%img{ src: image_pack_path("menu/icn-cart.svg") }
%span
{{ Cart.total_item_count() }}

View File

@@ -1,38 +1,40 @@
.expanding-sidebar.cart-sidebar{ng: {controller: 'CartCtrl', class: "{'shown': showCartSidebar}"}}
.background{ng: {click: 'toggleCartSidebar()'}}
.sidebar
.cart-header
%span.title{"ng-show" => "Cart.line_items.length == 1"}
= t('.items_in_cart_singular', num: "{{ Cart.total_item_count() }}")
%span.title{"ng-show" => "Cart.line_items.length > 1"}
= t('.items_in_cart_plural', num: "{{ Cart.total_item_count() }}")
%a.close{ng: {click: 'toggleCartSidebar()'}}
= t('.close')
%i.ofn-i_009-close
= cache_with_locale "cart-header" do
.cart-header
%span.title{"ng-show" => "Cart.line_items.length == 1"}
= t('.items_in_cart_singular', num: "{{ Cart.total_item_count() }}")
%span.title{"ng-show" => "Cart.line_items.length > 1"}
= t('.items_in_cart_plural', num: "{{ Cart.total_item_count() }}")
%a.close{ng: {click: 'toggleCartSidebar()'}}
= t('.close')
%i.ofn-i_009-close
.cart-content
%table
%tr.product-cart{"ng-repeat" => "line_item in Cart.line_items", "id" => "cart-variant-{{ line_item.variant.id }}"}
%td.image
%img{'ng-src' => '{{ line_item.variant.thumb_url }}'}
%td
%span {{ line_item.variant.extended_name | truncate: max_characters }}
%br
%span.options-text {{ line_item.variant.options_text | truncate: max_characters }}
%td.text-right
%span.quantity {{ line_item.quantity }}
%td
.total-price.text-right {{ line_item.total_price | localizeCurrency }}
.unit-price
%div{:style => "margin-right: 5px"}
%question-mark-with-tooltip{"question-mark-with-tooltip" => "_",
"question-mark-with-tooltip-append-to-body" => "true",
"question-mark-with-tooltip-placement" => "top",
"question-mark-with-tooltip-animation" => true,
key: "'js.shopfront.unit_price_tooltip'",
context: "'cart-sidebar'"}
.options-text
{{ line_item.variant.unit_price_price | localizeCurrency }}&nbsp;/&nbsp;{{ line_item.variant.unit_price_unit }}
= cache_with_locale "cart-table" do
%table
%tr.product-cart{"ng-repeat" => "line_item in Cart.line_items", "id" => "cart-variant-{{ line_item.variant.id }}"}
%td.image
%img{'ng-src' => '{{ line_item.variant.thumb_url }}'}
%td
%span {{ line_item.variant.extended_name | truncate: max_characters }}
%br
%span.options-text {{ line_item.variant.options_text | truncate: max_characters }}
%td.text-right
%span.quantity {{ line_item.quantity }}
%td
.total-price.text-right {{ line_item.total_price | localizeCurrency }}
.unit-price
%div{:style => "margin-right: 5px"}
%question-mark-with-tooltip{"question-mark-with-tooltip" => "_",
"question-mark-with-tooltip-append-to-body" => "true",
"question-mark-with-tooltip-placement" => "top",
"question-mark-with-tooltip-animation" => true,
key: "'js.shopfront.unit_price_tooltip'",
context: "'cart-sidebar'"}
.options-text
{{ line_item.variant.unit_price_price | localizeCurrency }}&nbsp;/&nbsp;{{ line_item.variant.unit_price_unit }}
.cart-empty{"ng-show" => "Cart.line_items.length == 0"}
%p
@@ -42,15 +44,16 @@
= t('.take_me_shopping')
.sidebar-footer{"ng-show" => "Cart.line_items.length > 0"}
%p.cart-total
%strong
= t 'total'
{{ Cart.total() | localizeCurrency }}
= cache_with_locale "cart-footer" do
%p.cart-total
%strong
= t 'total'
{{ Cart.total() | localizeCurrency }}
%div.fullwidth
%a.edit-cart.button.large.dark.left{href: main_app.cart_path, "ng-disabled" => "Cart.dirty || Cart.empty()", "ng-class" => "{ dirty: Cart.dirty }"}
%div{ ng: { if: "Cart.dirty" } }= t(:cart_updating)
%div{ ng: { if: "!Cart.dirty && Cart.empty()" } }= t(:cart_empty)
%div{ ng: { if: "!Cart.dirty && !Cart.empty()" } }= t('.edit_cart')
%a.checkout.button.large.bright.right{href: main_app.checkout_path, "ng-disabled" => "Cart.dirty || Cart.empty()"}
= t '.checkout'
%div.fullwidth
%a.edit-cart.button.large.dark.left{href: main_app.cart_path, "ng-disabled" => "Cart.dirty || Cart.empty()", "ng-class" => "{ dirty: Cart.dirty }"}
%div{ ng: { if: "Cart.dirty" } }= t(:cart_updating)
%div{ ng: { if: "!Cart.dirty && Cart.empty()" } }= t(:cart_empty)
%div{ ng: { if: "!Cart.dirty && !Cart.empty()" } }= t('.edit_cart')
%a.checkout.button.large.bright.right{href: main_app.checkout_path, "ng-disabled" => "Cart.dirty || Cart.empty()"}
= t '.checkout'

View File

@@ -1,8 +1,9 @@
%li.language-switcher.has-dropdown.not-click
%a{href: '#', class: "top-bar--menu-item-with-icon"}
%i.ofn-i_071-globe
%span= t 'language_name'
%ul.dropdown
- OpenFoodNetwork::I18nConfig.locale_options.each do |l|
%li
= link_to t('language_name', locale: l), main_app.locale_path(l.to_s)
= cache_with_locale OpenFoodNetwork::I18nConfig.locale_options do
%li.language-switcher.has-dropdown.not-click
%a{href: '#', class: "top-bar--menu-item-with-icon"}
%i.ofn-i_071-globe
%span= t 'language_name'
%ul.dropdown
- OpenFoodNetwork::I18nConfig.locale_options.each do |l|
%li
= link_to t('language_name', locale: l), main_app.locale_path(l.to_s)

View File

@@ -1,27 +1,30 @@
%nav.top-bar.show-for-large-up
%section.top-bar-section
%ul.nav-logo
%li.ofn-logo
%a{href: main_logo_link(@white_label_distributor)}
- if @white_label_logo&.variable?
= image_tag @white_label_distributor.white_label_logo_url(:default)
- else
%img{src: ContentConfig.url_for(:logo)}
%li.powered-by
%img{src: '/favicon.ico'}
%span
= t 'powered_by'
%a{href: '/'}
= t 'title'
= cache_with_locale [@white_label_distributor, ContentConfig.cache_key] do
%li.ofn-logo
%a{href: main_logo_link(@white_label_distributor)}
- if @white_label_logo&.variable?
= image_tag @white_label_distributor.white_label_logo_url(:default)
- else
%img{src: ContentConfig.url_for(:logo)}
%li.powered-by
%img{src: '/favicon.ico'}
%span
= t 'powered_by'
%a{href: '/'}
= t 'title'
- unless @hide_ofn_navigation
%ul.nav-main-menu
- [*1..7].each do |menu_number|
- menu_name = "menu_#{menu_number}"
- if ContentConfig[menu_name].present?
%li
%a{href: t("#{menu_name}_url") }
%span.nav-primary
= t "#{menu_name}_title"
= cache_with_locale ContentConfig.cache_key do
%ul.nav-main-menu
- [*1..7].each do |menu_number|
- menu_name = "menu_#{menu_number}"
- if ContentConfig[menu_name].present?
%li
%a{href: t("#{menu_name}_url") }
%span.nav-primary
= t "#{menu_name}_title"
%ul.nav-icons-menu
- if OpenFoodNetwork::I18nConfig.selectable_locales.count > 1
= render 'shared/menu/language_selector'
@@ -31,11 +34,12 @@
- else
= render 'shared/menu/signed_in'
%li.current_hub{"ng-controller" => "CurrentHubCtrl", "ng-show" => "CurrentHub.hub.id", "ng-cloak" => true}
%a{href: main_app.shop_path}
%span{ class: "top-bar--current-hub-prefix" }
= t 'label_shopping'
= '@'
%span{ class: "top-bar--current-hub-name" } {{ CurrentHub.hub.name | truncate:25 }}
%li.cart{"ng-cloak" => true}
= render partial: "shared/menu/cart"
= cache_with_locale "cart" do
%li.current_hub{"ng-controller" => "CurrentHubCtrl", "ng-show" => "CurrentHub.hub.id", "ng-cloak" => true}
%a{href: main_app.shop_path}
%span{ class: "top-bar--current-hub-prefix" }
= t 'label_shopping'
= '@'
%span{ class: "top-bar--current-hub-name" } {{ CurrentHub.hub.name | truncate:25 }}
%li.cart{"ng-cloak" => true}
= render partial: "shared/menu/cart"

View File

@@ -1,25 +1,26 @@
%nav.tab-bar.show-for-medium-down
%section.left
%a.left-off-canvas-toggle.menu-icon
= image_pack_tag "menu/btn-menu-mobile.png"
= cache_with_locale [@white_label_distributor, ContentConfig.cache_key] do
%nav.tab-bar.show-for-medium-down
%section.left
%a.left-off-canvas-toggle.menu-icon
= image_pack_tag "menu/btn-menu-mobile.png"
%section.left
.ofn-logo
%a{href: main_app.root_path}
- if @white_label_logo&.variable?
= image_tag @white_label_distributor.white_label_logo_url(:mobile)
- else
%img{src: ContentConfig.url_for(:logo_mobile), srcset: ContentConfig.url_for(:logo_mobile_svg), width: "75", height: "26"}
%section.left
.ofn-logo
%a{href: main_app.root_path}
- if @white_label_logo&.variable?
= image_tag @white_label_distributor.white_label_logo_url(:mobile)
- else
%img{src: ContentConfig.url_for(:logo_mobile), srcset: ContentConfig.url_for(:logo_mobile_svg), width: "75", height: "26"}
%section.right{"ng-cloak" => true}
%span.cart-span{"ng-class" => "{ dirty: Cart.dirty || Cart.empty(), 'pure-dirty': Cart.dirty }"}
%a.icon{ng: {click: 'toggleCartSidebar()'}}
%span
= t '.cart'
%span.count
= image_pack_tag "menu/icn-cart.svg"
%section.right{"ng-cloak" => true}
%span.cart-span{"ng-class" => "{ dirty: Cart.dirty || Cart.empty(), 'pure-dirty': Cart.dirty }"}
%a.icon{ng: {click: 'toggleCartSidebar()'}}
%span
{{ Cart.total_item_count() }}
= t '.cart'
%span.count
= image_pack_tag "menu/icn-cart.svg"
%span
{{ Cart.total_item_count() }}
%a{href: main_app.shop_path}
{{ CurrentHub.hub.name }}
%a{href: main_app.shop_path}
{{ CurrentHub.hub.name }}

View File

@@ -1,16 +1,18 @@
%aside.left-off-canvas-menu.show-for-medium-down{ ng: { controller: "OffcanvasCtrl" } }
%ul.off-canvas-list
%li.ofn-logo
%a{href: main_app.root_path}
%img{src: ContentConfig.url_for(:logo_mobile), srcset: ContentConfig.url_for(:logo_mobile_svg), width: "75", height: "26"}
- [*1..7].each do |menu_number|
- menu_name = "menu_#{menu_number}"
- if ContentConfig[menu_name].present?
%li.li-menu
%a{href: t("#{menu_name}_url") }
%span.nav-primary
%i{class: ContentConfig["#{menu_name}_icon_name"]}
= t "#{menu_name}_title"
= cache_with_locale ContentConfig.cache_key do
%li.ofn-logo
%a{href: main_app.root_path}
%img{src: ContentConfig.url_for(:logo_mobile), srcset: ContentConfig.url_for(:logo_mobile_svg), width: "75", height: "26"}
- [*1..7].each do |menu_number|
- menu_name = "menu_#{menu_number}"
- if ContentConfig[menu_name].present?
%li.li-menu
%a{href: t("#{menu_name}_url") }
%span.nav-primary
%i{class: ContentConfig["#{menu_name}_icon_name"]}
= t "#{menu_name}_title"
- if OpenFoodNetwork::I18nConfig.selectable_locales.count > 1
%li.language-switcher.li-menu
%a

View File

@@ -1,5 +1,6 @@
%li#login-link{ "data-controller": "login-modal" }
%a{"auth": "login", "data-action": "click->login-modal#call" }
%img{ src: image_pack_path("menu/icn-login.svg") }
%span
= t 'label_login'
= cache_with_locale do
%li#login-link{ "data-controller": "login-modal" }
%a{"auth": "login", "data-action": "click->login-modal#call" }
%img{ src: image_pack_path("menu/icn-login.svg") }
%span
= t 'label_login'

View File

@@ -1,9 +1,10 @@
%span{ "ng-show" => "query && ( appliedPropertiesList() || appliedTaxonsList() )" }
= t :products_filters_in
= cache_with_locale do
%span{ "ng-show" => "query && ( appliedPropertiesList() || appliedTaxonsList() )" }
= t :products_filters_in
%span.applied-properties{'ng-bind-html' => 'appliedPropertiesList()'}
%span.applied-properties{'ng-bind-html' => 'appliedPropertiesList()'}
%span{ "ng-show" => "appliedPropertiesList() && appliedTaxonsList()" }
= t :products_and
%span{ "ng-show" => "appliedPropertiesList() && appliedTaxonsList()" }
= t :products_and
%span.applied-taxons{'ng-bind-html' => 'appliedTaxonsList()'}
%span.applied-taxons{'ng-bind-html' => 'appliedTaxonsList()'}

View File

@@ -1,5 +1,6 @@
.filter-shopfront.taxon-selectors{ng: {show: 'supplied_taxons != null'}}
%filter-selector{ 'selector-set' => "taxonSelectors", objects: "supplied_taxons", "active-selectors" => "activeTaxons"}
= cache_with_locale do
.filter-shopfront.taxon-selectors{ng: {show: 'supplied_taxons != null'}}
%filter-selector{ 'selector-set' => "taxonSelectors", objects: "supplied_taxons", "active-selectors" => "activeTaxons"}
.filter-shopfront.property-selectors{ng: {show: 'supplied_properties != null'}}
%filter-selector{ 'selector-set' => "propertySelectors", objects: "supplied_properties", "active-selectors" => "activeProperties"}
.filter-shopfront.property-selectors{ng: {show: 'supplied_properties != null'}}
%filter-selector{ 'selector-set' => "propertySelectors", objects: "supplied_properties", "active-selectors" => "activeProperties"}

View File

@@ -1,51 +1,52 @@
%form{action: main_app.cart_path}
%products{"ng-init" => "refreshStaleData()", "ng-show" => "order_cycle.order_cycle_id != null", "ng-cloak" => true }
= cache_with_locale do
%form{action: main_app.cart_path}
%products{"ng-init" => "refreshStaleData()", "ng-show" => "order_cycle.order_cycle_id != null", "ng-cloak" => true }
= render partial: "shop/products/searchbar"
= render partial: "shop/products/searchbar"
.row
.footer-pad.small-12.columns.product-listing
.row.full
.medium-12.large-9.columns.full
= render partial: "shop/products/search_feedback"
.row
.footer-pad.small-12.columns.product-listing
.row.full
.medium-12.large-9.columns.full
= render partial: "shop/products/search_feedback"
%div.pad-top{ "infinite-scroll" => "loadMore()", "infinite-scroll-distance" => "1", "infinite-scroll-disabled" => 'Products.loading', "infinite-scroll-immediate-check": "false" }
%product.animate-repeat{"ng-controller" => "ProductNodeCtrl", "ng-repeat" => "product in Products.products track by product.id", "id" => "product-{{ product.id }}"}
= render "shop/products/summary"
.shop-variants
.variants.row{"ng-controller": "ShopVariantCtrl", variant: 'variant', "ng-repeat" => "variant in product.variants | orderBy: ['name_to_display','unit_value'] track by variant.id", "id" => "variant-{{ variant.id }}", "ng-class" => "{'out-of-stock': !variant.on_demand && variant.on_hand == 0}"}
= render "shop/products/shop_variant"
%product{"ng-show" => "Products.loading"}
.summary
.small-12.columns.text-center
= t :products_loading
.row.full
.small-12.columns.text-center
= render partial: "components/spinner"
%div.pad-top{ "infinite-scroll" => "loadMore()", "infinite-scroll-distance" => "1", "infinite-scroll-disabled" => 'Products.loading', "infinite-scroll-immediate-check": "false" }
%product.animate-repeat{"ng-controller" => "ProductNodeCtrl", "ng-repeat" => "product in Products.products track by product.id", "id" => "product-{{ product.id }}"}
= render "shop/products/summary"
.shop-variants
.variants.row{"ng-controller": "ShopVariantCtrl", variant: 'variant', "ng-repeat" => "variant in product.variants | orderBy: ['name_to_display','unit_value'] track by variant.id", "id" => "variant-{{ variant.id }}", "ng-class" => "{'out-of-stock': !variant.on_demand && variant.on_hand == 0}"}
= render "shop/products/shop_variant"
%product{"ng-show" => "Products.loading"}
.summary
.small-12.columns.text-center
= t :products_loading
.row.full
.small-12.columns.text-center
= render partial: "components/spinner"
.hide-for-medium-down.large-1.columns
-# Space between products and filters
&nbsp;
.hide-for-medium-down.large-1.columns
-# Space between products and filters
&nbsp;
.sticky-shop-filters-container.thin-scroll-bar.hide-for-medium-down.large-2.columns
%h5.filter-header
= t(:products_filter_by)
%span{ng: {show: 'filtersCount()' }}
= "({{ filtersCount() }} #{t(:products_filter_selected)})"
= render partial: "shop/products/filters"
.expanding-sidebar.shop-filters-sidebar.hide-for-large-up{ng: {show: 'showFilterSidebar', class: "{'shown': showFilterSidebar}"}}
.background{ng: {click: 'toggleFilterSidebar()'}}
.sidebar
%h5
.sticky-shop-filters-container.thin-scroll-bar.hide-for-medium-down.large-2.columns
%h5.filter-header
= t(:products_filter_by)
%span{ng: {show: 'filtersCount()' }}
= "({{ filtersCount() }} #{t(:products_filter_selected)})"
= render partial: "shop/products/filters"
.sidebar-footer
%button.large.dark.left{type: 'button', ng: {click: 'clearFilters()'}}
= t(:products_filter_clear)
%button.large.bright.right{type: 'button', ng: {click: 'toggleFilterSidebar()'}}
= t(:products_filter_done)
.expanding-sidebar.shop-filters-sidebar.hide-for-large-up{ng: {show: 'showFilterSidebar', class: "{'shown': showFilterSidebar}"}}
.background{ng: {click: 'toggleFilterSidebar()'}}
.sidebar
%h5
= t(:products_filter_by)
%span{ng: {show: 'filtersCount()' }}
= "({{ filtersCount() }} #{t(:products_filter_selected)})"
= render partial: "shop/products/filters"
.sidebar-footer
%button.large.dark.left{type: 'button', ng: {click: 'clearFilters()'}}
= t(:products_filter_clear)
%button.large.bright.right{type: 'button', ng: {click: 'toggleFilterSidebar()'}}
= t(:products_filter_done)

View File

@@ -1,24 +1,25 @@
.row.animate-slide{ "ng-show" => "query || appliedPropertiesList() || appliedTaxonsList()" }
.small-12.columns
.alert-box.search-alert.ng-scope
%div{"ng-show" => "Products.products.length > 0"}
= cache_with_locale do
.row.animate-slide{ "ng-show" => "query || appliedPropertiesList() || appliedTaxonsList()" }
.small-12.columns
.alert-box.search-alert.ng-scope
%div{"ng-show" => "Products.products.length > 0"}
%a.clear-all.right{"ng-click" => "clearAll()"}
= t :products_clear
%i.ofn-i_009-close
%a.clear-all.right{"ng-click" => "clearAll()"}
= t :products_clear
%i.ofn-i_009-close
%span.filter-label
= t :products_results_for
%span{ ng: { hide: "!query"} }
%span.applied-search
{{ query }}
= render partial: 'shop/products/applied_filters_feedback'
%span.filter-label
= t :products_results_for
%span{ ng: { hide: "!query"} }
%span.applied-search
{{ query }}
= render partial: 'shop/products/applied_filters_feedback'
%div.no-results-bar{"ng-show" => "Products.products.length == 0 && !Products.loading"}
.row.summary
.small-12.columns
%p.no-results
= t :products_no_results_html, query: "<span class='applied-search'>{{query}}</span>".html_safe
= render partial: 'shop/products/applied_filters_feedback'
%button.clear-search{type: 'button', ng: {click: 'clearAll()'}}
= t :products_clear_search
%div.no-results-bar{"ng-show" => "Products.products.length == 0 && !Products.loading"}
.row.summary
.small-12.columns
%p.no-results
= t :products_no_results_html, query: "<span class='applied-search'>{{query}}</span>".html_safe
= render partial: 'shop/products/applied_filters_feedback'
%button.clear-search{type: 'button', ng: {click: 'clearAll()'}}
= t :products_clear_search

View File

@@ -1,17 +1,18 @@
.shop-searchbar
.row
.small-12.large-5.columns.flex
%div.search-wrap
%input#search.text{"ng-model" => "query",
type: 'search',
placeholder: t(:products_search),
"ng-debounce" => "200",
"disable-enter-with-blur" => true}
%a.clear{type: 'button', ng: {show: 'query', click: 'clearQuery()'}, 'focus-search' => true}
= image_pack_tag "icn-close.png"
= cache_with_locale do
.shop-searchbar
.row
.small-12.large-5.columns.flex
%div.search-wrap
%input#search.text{"ng-model" => "query",
type: 'search',
placeholder: t(:products_search),
"ng-debounce" => "200",
"disable-enter-with-blur" => true}
%a.clear{type: 'button', ng: {show: 'query', click: 'clearQuery()'}, 'focus-search' => true}
= image_pack_tag "icn-close.png"
.hide-for-large-up
%button{type: 'button', ng: {click: 'toggleFilterSidebar()'}}
= t(:products_filter_heading)
%span{ng: {show: 'filtersCount()' }}
({{ filtersCount() }})
.hide-for-large-up
%button{type: 'button', ng: {click: 'toggleFilterSidebar()'}}
= t(:products_filter_heading)
%span{ng: {show: 'filtersCount()' }}
({{ filtersCount() }})

View File

@@ -1,22 +1,23 @@
.small-4.medium-4.large-5.columns.variant-name
.inline{"ng-if" => "::variant.display_name"} {{ ::variant.display_name }}
.variant-unit {{ ::variant.unit_to_display }}
.small-3.medium-3.large-2.columns.variant-price
%price-breakdown{"price-breakdown" => "_", variant: "variant",
"price-breakdown-append-to-body" => "true",
"price-breakdown-placement" => "bottom",
"price-breakdown-animation" => true}
{{ variant.price_with_fees | localizeCurrency }}
.unit-price.variant-unit-price
%question-mark-with-tooltip{"question-mark-with-tooltip" => "_",
"question-mark-with-tooltip-append-to-body" => "true",
"question-mark-with-tooltip-placement" => "top",
"question-mark-with-tooltip-animation" => true,
key: "'js.shopfront.unit_price_tooltip'"}
{{ variant.unit_price_price | localizeCurrency }}&nbsp;/&nbsp;{{ variant.unit_price_unit }}
= cache_with_locale do
.small-4.medium-4.large-5.columns.variant-name
.inline{"ng-if" => "::variant.display_name"} {{ ::variant.display_name }}
.variant-unit {{ ::variant.unit_to_display }}
.small-3.medium-3.large-2.columns.variant-price
%price-breakdown{"price-breakdown" => "_", variant: "variant",
"price-breakdown-append-to-body" => "true",
"price-breakdown-placement" => "bottom",
"price-breakdown-animation" => true}
{{ variant.price_with_fees | localizeCurrency }}
.unit-price.variant-unit-price
%question-mark-with-tooltip{"question-mark-with-tooltip" => "_",
"question-mark-with-tooltip-append-to-body" => "true",
"question-mark-with-tooltip-placement" => "top",
"question-mark-with-tooltip-animation" => true,
key: "'js.shopfront.unit_price_tooltip'"}
{{ variant.unit_price_price | localizeCurrency }}&nbsp;/&nbsp;{{ variant.unit_price_unit }}
.medium-2.large-2.columns.total-price
%span{"ng-class" => "{filled: variant.line_item.total_price}"}
{{ variant.line_item.total_price | localizeCurrency }}
= render partial: "shop/products/shop_variant_no_group_buy"
= render partial: "shop/products/shop_variant_with_group_buy"
.medium-2.large-2.columns.total-price
%span{"ng-class" => "{filled: variant.line_item.total_price}"}
{{ variant.line_item.total_price | localizeCurrency }}
= render partial: "shop/products/shop_variant_no_group_buy"
= render partial: "shop/products/shop_variant_with_group_buy"

View File

@@ -1,22 +1,23 @@
.small-5.medium-3.large-3.columns.variant-quantity-column.text-right{"ng-if" => "::!variant.product.group_buy"}
= cache_with_locale do
.small-5.medium-3.large-3.columns.variant-quantity-column.text-right{"ng-if" => "::!variant.product.group_buy"}
.variant-quantity-inputs{ng: {if: "variant.line_item.quantity == 0"}}
%button.add-variant{type: "button", ng: {click: "add(1)", disabled: "!canAdd(1)"}}
{{ "js.shopfront.variant.add_to_cart" | t }}
.variant-quantity-inputs{ng: {if: "variant.line_item.quantity == 0"}}
%button.add-variant{type: "button", ng: {click: "add(1)", disabled: "!canAdd(1)"}}
{{ "js.shopfront.variant.add_to_cart" | t }}
.variant-quantity-inputs{ng: {if: "variant.line_item.quantity != 0"}}
%button.variant-quantity{type: "button", ng: {click: "add(-1)", disabled: "!canAdd(-1)"}}>
-# U+FF0D Fullwidth Hyphen-Minus
%input.variant-quantity{ type: "number", min: "0", max: "{{ available() }}",
ng: {model: "variant.line_item.quantity", max: "Infinity"}}>
%button.variant-quantity{type: "button", ng: {click: "add(1)", disabled: "!canAdd(1)"}}
-# U+FF0B Fullwidth Plus Sign
.variant-remaining-stock{ng: {if: "displayRemainingInStock()"}}
{{ "js.shopfront.variant.remaining_in_stock" | t:{quantity: available()} }}
.variant-quantity-display{ng: {class: "{visible: variant.line_item.quantity}"}}
{{ "js.shopfront.variant.quantity_in_cart" | t:{quantity: variant.line_item.quantity || 0} }}
%input{type: :hidden,
name: "variants[{{::variant.id}}]",
ng: {model: "variant.line_item.quantity"}}
.variant-quantity-inputs{ng: {if: "variant.line_item.quantity != 0"}}
%button.variant-quantity{type: "button", ng: {click: "add(-1)", disabled: "!canAdd(-1)"}}>
-# U+FF0D Fullwidth Hyphen-Minus
%input.variant-quantity{ type: "number", min: "0", max: "{{ available() }}",
ng: {model: "variant.line_item.quantity", max: "Infinity"}}>
%button.variant-quantity{type: "button", ng: {click: "add(1)", disabled: "!canAdd(1)"}}
-# U+FF0B Fullwidth Plus Sign
.variant-remaining-stock{ng: {if: "displayRemainingInStock()"}}
{{ "js.shopfront.variant.remaining_in_stock" | t:{quantity: available()} }}
.variant-quantity-display{ng: {class: "{visible: variant.line_item.quantity}"}}
{{ "js.shopfront.variant.quantity_in_cart" | t:{quantity: variant.line_item.quantity || 0} }}
%input{type: :hidden,
name: "variants[{{::variant.id}}]",
ng: {model: "variant.line_item.quantity"}}

View File

@@ -1,17 +1,18 @@
.small-5.medium-3.large-3.columns.variant-quantity-column.text-right{"ng-if" => "::variant.product.group_buy"}
= cache_with_locale do
.small-5.medium-3.large-3.columns.variant-quantity-column.text-right{"ng-if" => "::variant.product.group_buy"}
%button.add-variant{type: "button", ng: {if: "!variant.line_item.quantity", click: "addBulk(1)", disabled: "!canAdd(1)"}}
{{ "js.shopfront.variant.add_to_cart" | t }}
%button.bulk-buy.variant-quantity{type: "button", ng: {if: "variant.line_item.quantity", click: "addBulk(0)"}}>
{{ variant.line_item.quantity }}
%button.bulk-buy.variant-quantity{type: "button", ng: {if: "variant.line_item.quantity", click: "addBulk(0)"}}
{{ variant.line_item.max_quantity || "-" }}
%br
.variant-quantity-display{ng: {class: "{visible: variant.line_item.quantity}"}}
{{ "js.shopfront.variant.in_cart" | t }}
%input{type: :hidden,
name: "variants[{{::variant.id}}]",
ng: {model: "variant.line_item.quantity"}}
%input{type: :hidden,
name: "variants[{{::variant.id}}]",
ng: {model: "variant.line_item.max_quantity"}}
%button.add-variant{type: "button", ng: {if: "!variant.line_item.quantity", click: "addBulk(1)", disabled: "!canAdd(1)"}}
{{ "js.shopfront.variant.add_to_cart" | t }}
%button.bulk-buy.variant-quantity{type: "button", ng: {if: "variant.line_item.quantity", click: "addBulk(0)"}}>
{{ variant.line_item.quantity }}
%button.bulk-buy.variant-quantity{type: "button", ng: {if: "variant.line_item.quantity", click: "addBulk(0)"}}
{{ variant.line_item.max_quantity || "-" }}
%br
.variant-quantity-display{ng: {class: "{visible: variant.line_item.quantity}"}}
{{ "js.shopfront.variant.in_cart" | t }}
%input{type: :hidden,
name: "variants[{{::variant.id}}]",
ng: {model: "variant.line_item.quantity"}}
%input{type: :hidden,
name: "variants[{{::variant.id}}]",
ng: {model: "variant.line_item.max_quantity"}}

View File

@@ -1,21 +1,22 @@
.product-thumb
%a{"ng-click" => "triggerProductModal()"}
%span.product-thumb__bulk-label{"ng-if" => "::product.group_buy"}
= t(".bulk")
%img{"ng-src" => "{{::product.primaryImageOrMissing}}"}
= cache_with_locale do
.product-thumb
%a{"ng-click" => "triggerProductModal()"}
%span.product-thumb__bulk-label{"ng-if" => "::product.group_buy"}
= t(".bulk")
%img{"ng-src" => "{{::product.primaryImageOrMissing}}"}
.summary
.summary-header
%h3
%a{"ng-click" => "triggerProductModal()", href: 'javascript:void(0)'}
%span{"ng-bind" => "::product.name"}
.product-description{ng: {"bind-html": "::product.description_html", click: "triggerProductModal()", show: "product.description_html.length"}}
%div{ "ng-switch" => "enterprise.visible" }
.product-producer
= t :products_from
%span{ "ng-switch-when": "hidden", "ng-bind" => "::enterprise.name"}
%span{ "ng-switch-default": true }
%enterprise-modal{"ng-bind" => "::enterprise.name"}
.summary
.summary-header
%h3
%a{"ng-click" => "triggerProductModal()", href: 'javascript:void(0)'}
%span{"ng-bind" => "::product.name"}
.product-description{ng: {"bind-html": "::product.description_html", click: "triggerProductModal()", show: "product.description_html.length"}}
%div{ "ng-switch" => "enterprise.visible" }
.product-producer
= t :products_from
%span{ "ng-switch-when": "hidden", "ng-bind" => "::enterprise.name"}
%span{ "ng-switch-default": true }
%enterprise-modal{"ng-bind" => "::enterprise.name"}
.product-properties.filter-shopfront.property-selectors
%filter-selector{ 'selector-set' => "productPropertySelectors", objects: "[product] | propertiesWithValuesOf" }
.product-properties.filter-shopfront.property-selectors
%filter-selector{ 'selector-set' => "productPropertySelectors", objects: "[product] | propertiesWithValuesOf" }

View File

@@ -1,53 +1,54 @@
.row.active_table_row{"ng-show" => "open()", "ng-click" => "toggle($event)", "ng-class" => "{'open' : open()}"}
.columns.small-12.fat.text-center{"ng-show" => "open() && shopfront_loading"}
%p.fullwidth
= render partial: "components/spinner"
= cache_with_locale do
.row.active_table_row{"ng-show" => "open()", "ng-click" => "toggle($event)", "ng-class" => "{'open' : open()}"}
.columns.small-12.fat.text-center{"ng-show" => "open() && shopfront_loading"}
%p.fullwidth
= render partial: "components/spinner"
.columns.small-12.medium-6.large-5.fat{"ng-show" => "open() && !shopfront_loading"}
%div{"ng-if" => "::hub.taxons"}
%label
= t :hubs_buy
.trans-sentence
%div
%span.fat-taxons{"ng-repeat" => "taxon in hub.taxons"}
%span{"ng-bind" => "::taxon.name"}
%div
%span.fat-properties{"ng-repeat" => "property in hub.distributed_properties"}
%span{"ng-bind" => "property.presentation"}
%div.show-for-medium-up{"ng-if" => "::hub.taxons.length==0"}
&nbsp;
.columns.small-12.medium-3.large-2.fat{"ng-show" => "open() && !shopfront_loading"}
%div{"ng-if" => "::(hub.pickup || hub.delivery)"}
%label
= t :hubs_delivery_options
%ul.small-block-grid-2.medium-block-grid-1.large-block-grid-1
%li.pickup{"ng-if" => "::hub.pickup"}
%i.ofn-i_038-takeaway
= t :hubs_pickup
%li.delivery{"ng-if" => "::hub.delivery"}
%i.ofn-i_039-delivery
= t :hubs_delivery
.columns.small-12.medium-3.large-5.fat{"ng-show" => "open() && !shopfront_loading"}
%div{"ng-if" => "::hub.producers"}
%label
= t :hubs_producers
%ul.small-block-grid-2.medium-block-grid-1.large-block-grid-2{"ng-class" => "{'show-more-producers' : toggleMoreProducers}", "class" => "producers-list"}
%li{"ng-repeat" => "enterprise in hub.producers | limitTo:7"}
%enterprise-modal
%i.ofn-i_036-producers
%span{"ng-bind" => "::enterprise.name"}
%li{"ng-repeat" => "enterprise in hub.producers.slice(7,hub.producers.length)", "class" => "additional-producer"}
%enterprise-modal
%i.ofn-i_036-producers
%span{"ng-bind" => "::enterprise.name"}
%li{"data-is-link" => "true", "class" => "more-producers-link", "ng-show" => "::hub.producers.length>7"}
%a{"ng-click" => "toggleMoreProducers=!toggleMoreProducers; $event.stopPropagation()"}
.more
+
%span{"ng-bind" => "::hub.producers.length-7"}
= t :label_more
.less
= t :label_less
.columns.small-12.medium-6.large-5.fat{"ng-show" => "open() && !shopfront_loading"}
%div{"ng-if" => "::hub.taxons"}
%label
= t :hubs_buy
.trans-sentence
%div
%span.fat-taxons{"ng-repeat" => "taxon in hub.taxons"}
%span{"ng-bind" => "::taxon.name"}
%div
%span.fat-properties{"ng-repeat" => "property in hub.distributed_properties"}
%span{"ng-bind" => "property.presentation"}
%div.show-for-medium-up{"ng-if" => "::hub.taxons.length==0"}
&nbsp;
.columns.small-12.medium-3.large-2.fat{"ng-show" => "open() && !shopfront_loading"}
%div{"ng-if" => "::(hub.pickup || hub.delivery)"}
%label
= t :hubs_delivery_options
%ul.small-block-grid-2.medium-block-grid-1.large-block-grid-1
%li.pickup{"ng-if" => "::hub.pickup"}
%i.ofn-i_038-takeaway
= t :hubs_pickup
%li.delivery{"ng-if" => "::hub.delivery"}
%i.ofn-i_039-delivery
= t :hubs_delivery
.columns.small-12.medium-3.large-5.fat{"ng-show" => "open() && !shopfront_loading"}
%div{"ng-if" => "::hub.producers"}
%label
= t :hubs_producers
%ul.small-block-grid-2.medium-block-grid-1.large-block-grid-2{"ng-class" => "{'show-more-producers' : toggleMoreProducers}", "class" => "producers-list"}
%li{"ng-repeat" => "enterprise in hub.producers | limitTo:7"}
%enterprise-modal
%i.ofn-i_036-producers
%span{"ng-bind" => "::enterprise.name"}
%li{"ng-repeat" => "enterprise in hub.producers.slice(7,hub.producers.length)", "class" => "additional-producer"}
%enterprise-modal
%i.ofn-i_036-producers
%span{"ng-bind" => "::enterprise.name"}
%li{"data-is-link" => "true", "class" => "more-producers-link", "ng-show" => "::hub.producers.length>7"}
%a{"ng-click" => "toggleMoreProducers=!toggleMoreProducers; $event.stopPropagation()"}
.more
+
%span{"ng-bind" => "::hub.producers.length-7"}
= t :label_more
.less
= t :label_less
%div.show-for-medium-up{"ng-if" => "::hub.producers.length==0"}
&nbsp;
%div.show-for-medium-up{"ng-if" => "::hub.producers.length==0"}
&nbsp;

View File

@@ -7,31 +7,32 @@
= render "shared/components/enterprise_search"
= render "filters"
.row
.small-12.columns
.name-matches{"ng-show" => "nameMatchesFiltered.length > 0"}
%h2
= t :hubs_matches
= render "hubs_table", enterprises: "nameMatches"
= cache_with_locale do
.row
.small-12.columns
.name-matches{"ng-show" => "nameMatchesFiltered.length > 0"}
%h2
= t :hubs_matches
= render "hubs_table", enterprises: "nameMatches"
.distance-matches{"ng-if" => "nameMatchesFiltered.length == 0 || distanceMatchesShown"}
%h2{"ng-show" => "nameMatchesFiltered.length > 0 || query.length > 0"}
= t :hubs_matches
%span{"ng-show" => "nameMatchesFiltered.length > 0"} {{ nameMatchesFiltered[0].name }}...
%span{"ng-hide" => "nameMatchesFiltered.length > 0"} {{ query }}...
.distance-matches{"ng-if" => "nameMatchesFiltered.length == 0 || distanceMatchesShown"}
%h2{"ng-show" => "nameMatchesFiltered.length > 0 || query.length > 0"}
= t :hubs_matches
%span{"ng-show" => "nameMatchesFiltered.length > 0"} {{ nameMatchesFiltered[0].name }}...
%span{"ng-hide" => "nameMatchesFiltered.length > 0"} {{ query }}...
= render "hubs_table", enterprises: "distanceMatches"
= render "hubs_table", enterprises: "distanceMatches"
.show-distance-matches{"ng-show" => "nameMatchesFiltered.length > 0 && !distanceMatchesShown"}
%a{href: "", "ng-click" => "showDistanceMatches()"}
= t :hubs_distance_filter, location: "{{ nameMatchesFiltered[0].name }}"
.more-controls
%span{ng: {show: "closed_shops_loading", cloak: true}}
= render partial: "components/spinner"
%span{ng: {if: "!show_closed", cloak: true}}
%a.button{href: "", ng: {click: "showClosedShops()"}}
= t '.show_closed_shops'
%span{ng: {if: "show_closed", cloak: true}}
%a.button{href: "", ng: {click: "hideClosedShops()"}}
= t '.hide_closed_shops'
%a.button{href: main_app.map_path}= t '.show_on_map'
.show-distance-matches{"ng-show" => "nameMatchesFiltered.length > 0 && !distanceMatchesShown"}
%a{href: "", "ng-click" => "showDistanceMatches()"}
= t :hubs_distance_filter, location: "{{ nameMatchesFiltered[0].name }}"
.more-controls
%span{ng: {show: "closed_shops_loading", cloak: true}}
= render partial: "components/spinner"
%span{ng: {if: "!show_closed", cloak: true}}
%a.button{href: "", ng: {click: "showClosedShops()"}}
= t '.show_closed_shops'
%span{ng: {if: "show_closed", cloak: true}}
%a.button{href: "", ng: {click: "hideClosedShops()"}}
= t '.hide_closed_shops'
%a.button{href: main_app.map_path}= t '.show_on_map'

View File

@@ -1,10 +1,11 @@
.active_table
%hub.active_table_node.row{"ng-repeat" => "hub in #{enterprises}Filtered = (#{enterprises} | closedShops:show_closed | taxons:activeTaxons | properties:activeProperties:'distributed_properties' | shipping:shippingTypes | orderBy:['-active', '+distance', '+orders_close_at'])",
"ng-class" => "{'is_profile' : hub.category == 'hub_profile', 'closed' : !open(), 'open' : open(), 'inactive' : !hub.active, 'current' : current()}",
"ng-controller" => "HubNodeCtrl",
id: "{{hub.hash}}"}
.small-12.columns
= render 'skinny'
= render 'fat'
= cache_with_locale enterprises do
.active_table
%hub.active_table_node.row{"ng-repeat" => "hub in #{enterprises}Filtered = (#{enterprises} | closedShops:show_closed | taxons:activeTaxons | properties:activeProperties:'distributed_properties' | shipping:shippingTypes | orderBy:['-active', '+distance', '+orders_close_at'])",
"ng-class" => "{'is_profile' : hub.category == 'hub_profile', 'closed' : !open(), 'open' : open(), 'inactive' : !hub.active, 'current' : current()}",
"ng-controller" => "HubNodeCtrl",
id: "{{hub.hash}}"}
.small-12.columns
= render 'skinny'
= render 'fat'
= render 'shared/components/enterprise_no_results', enterprises: "#{enterprises}Filtered"
= render 'shared/components/enterprise_no_results', enterprises: "#{enterprises}Filtered"

View File

@@ -1,46 +1,47 @@
.row.active_table_row{"ng-if" => "hub.is_distributor", "ng-click" => "toggle($event)", "ng-class" => "{'closed' : !open(), 'is_distributor' : producer.is_distributor}"}
.columns.small-12.medium-5.large-5.skinny-head
%a.hub{"ng-href" => "{{::hub.path}}", "ng-attr-target" => "{{ embedded_layout ? '_blank' : undefined}}", "ng-class" => "{primary: hub.active, secondary: !hub.active}", "ofn-change-hub" => "hub", "data-is-link" => "true"}
%i{ng: {class: "::hub.icon_font"}}
%span.margin-top.hub-name-listing{"ng-bind" => "::hub.name | truncate:40"}
= cache_with_locale do
.row.active_table_row{"ng-if" => "hub.is_distributor", "ng-click" => "toggle($event)", "ng-class" => "{'closed' : !open(), 'is_distributor' : producer.is_distributor}"}
.columns.small-12.medium-5.large-5.skinny-head
%a.hub{"ng-href" => "{{::hub.path}}", "ng-attr-target" => "{{ embedded_layout ? '_blank' : undefined}}", "ng-class" => "{primary: hub.active, secondary: !hub.active}", "ofn-change-hub" => "hub", "data-is-link" => "true"}
%i{ng: {class: "::hub.icon_font"}}
%span.margin-top.hub-name-listing{"ng-bind" => "::hub.name | truncate:40"}
.columns.small-4.medium-2.large-2
%span.margin-top{"ng-bind" => "::hub.address.city"}
.columns.small-2.medium-1.large-1
%span.margin-top{"ng-bind" => "::hub.address.state_name"}
%span.margin-top{"ng-if" => "hub.distance != null && hub.distance > 0"} ({{ hub.distance / 1000 | number:0 }} km)
.columns.small-4.medium-2.large-2
%span.margin-top.ellipsed{"ng-bind" => "::hub.address.city"}
.columns.small-3.medium-2.large-2
%span.margin-top.ellipsed{"ng-bind" => "::hub.address.state_name"}
%span.margin-top{"ng-if" => "hub.distance != null && hub.distance > 0"} ({{ hub.distance / 1000 | number:0 }} km)
.columns.small-5.medium-3.large-3.text-right{"ng-if" => "::hub.active"}
%a.hub.open_closed{"ng-href" => "{{::hub.path}}", "ng-attr-target" => "{{ embedded_layout ? '_blank' : undefined}}", "ng-class" => "{primary: hub.active, secondary: !hub.active}", "ofn-change-hub" => "hub"}
%i.ofn-i_068-shop-reversed.show-for-medium-up
%span.margin-top{ ng: { if: "::current()" } }
%em= t :hubs_shopping_here
%span.margin-top{ ng: { if: "::!current()" } }
%span{"ng-bind" => "::hub.orders_close_at | sensible_timeframe"}
.columns.small-5.medium-3.large-3.text-right.no-wrap.flex.flex-align-center.flex-justify-end{"ng-if" => "::hub.active"}
%a.hub.open_closed.flex.flex-align-center{"ng-href" => "{{::hub.path}}", "ng-attr-target" => "{{ embedded_layout ? '_blank' : undefined}}", "ng-class" => "{primary: hub.active, secondary: !hub.active}", "ofn-change-hub" => "hub"}
%span{ ng: { if: "::current()" } }
%em= t :hubs_shopping_here
%span{ ng: { if: "::!current()" } }
%span{"ng-bind" => "::hub.orders_close_at | sensible_timeframe"}
%i.ofn-i_068-shop-reversed.show-for-medium-up
%span{style: "margin-left: 0.5rem;"}
%i{"ng-class" => "{'ofn-i_005-caret-down' : !open(), 'ofn-i_006-caret-up' : open()}"}
.columns.small-5.medium-3.large-3.text-right{"ng-if" => "::!hub.active"}
%a.hub.open_closed{"ng-href" => "{{::hub.path}}", "ng-attr-target" => "{{ embedded_layout ? '_blank' : undefined}}", "ng-class" => "{primary: hub.active, secondary: !hub.active}", "ofn-change-hub" => "hub"}
%span.margin-top{ ng: { if: "::current()" } }
%em= t :hubs_shopping_here
%span.margin-top{ ng: { if: "::!current()" } }
= t :hubs_orders_closed
%i.ofn-i_068-shop-reversed.show-for-medium-up
.columns.small-5.medium-3.large-3.text-right.no-wrap.flex.flex-align-center.flex-justify-end{"ng-if" => "::!hub.active"}
%a.hub.open_closed.flex{"ng-href" => "{{::hub.path}}", "ng-attr-target" => "{{ embedded_layout ? '_blank' : undefined}}", "ng-class" => "{primary: hub.active, secondary: !hub.active}", "ofn-change-hub" => "hub"}
%span{ ng: { if: "::current()" } }
%em= t :hubs_shopping_here
%span{ ng: { if: "::!current()" } }
= t :hubs_orders_closed
%i.ofn-i_068-shop-reversed.show-for-medium-up
%span{style: "margin-left: 0.5rem;"}
%i{"ng-class" => "{'ofn-i_005-caret-down' : !open(), 'ofn-i_006-caret-up' : open()}"}
.columns.small-1.medium-1.large-1.text-right
%span.margin-top
%i{"ng-class" => "{'ofn-i_005-caret-down' : !open(), 'ofn-i_006-caret-up' : open()}"}
.row.active_table_row{"ng-if" => "!hub.is_distributor", "ng-class" => "closed"}
.columns.small-12.medium-6.large-5.skinny-head
%a.hub{"ng-click" => "openModal(hub)", "ng-class" => "{primary: hub.active, secondary: !hub.active}"}
%i{ng: {class: "hub.icon_font"}}
%span.hub-name-listing{"ng-bind" => "::hub.name | truncate:40"}
.row.active_table_row{"ng-if" => "!hub.is_distributor", "ng-class" => "closed"}
.columns.small-12.medium-6.large-5.skinny-head
%a.hub{"ng-click" => "openModal(hub)", "ng-class" => "{primary: hub.active, secondary: !hub.active}"}
%i{ng: {class: "hub.icon_font"}}
%span.margin-top.hub-name-listing{"ng-bind" => "::hub.name | truncate:40"}
.columns.small-4.medium-2.large-2
%span.ellipsed{"ng-bind" => "::hub.address.city"}
.columns.small-2.medium-1.large-1
%span.ellipsed{"ng-bind" => "::hub.address.state_name"}
.columns.small-4.medium-2.large-2
%span.margin-top{"ng-bind" => "::hub.address.city"}
.columns.small-2.medium-1.large-1
%span.margin-top{"ng-bind" => "::hub.address.state_name"}
.columns.small-6.medium-3.large-4.text-right
%span.margin-top{ ng: { if: "::!current()" } }
%em= t :hubs_profile_only
.columns.small-6.medium-3.large-4.text-right.no-wrap.flex.flex-align-center.flex-justify-end
%span{ ng: { if: "::!current()" } }
%em= t :hubs_profile_only

View File

@@ -1,5 +1,5 @@
%table.index{"data-hook" => "adjustments"}
%thead{"data-hook" => "adjustmment_head"}
%table.index
%thead
%tr
%th= "#{t('spree.date')}/#{t('spree.time')}"
%th= t(:description)
@@ -15,7 +15,7 @@
- taxable = adjustment.adjustable_type == "Spree::Shipment" ? adjustment.adjustable : adjustment
- tr_class = cycle('odd', 'even')
- tr_id = spree_dom_id(adjustment)
%tr{:class => tr_class, "data-hook" => "adjustment_row", :id => tr_id}
%tr{:class => tr_class, :id => tr_id}
%td.align-center.created_at
= pretty_time(adjustment.created_at)
%td.align-center.label

View File

@@ -1,4 +1,4 @@
.row{"data-hook" => "admin_adjustment_form_fields"}
.row
- if @adjustment.new_record?
= render 'new_form', f: f
- else

View File

@@ -14,6 +14,6 @@
= form_for @adjustment, :url => admin_order_adjustment_path(@order, @adjustment), :method => :put do |f|
%fieldset.no-border-top
= render :partial => 'form', :locals => { :f => f }
.filter-actions.actions{"data-hook" => "buttons"}
.filter-actions.actions
= button Spree.t(:continue), 'icon-arrow-right'
= link_to_with_icon 'icon-remove', Spree.t('actions.cancel'), admin_order_adjustments_url(@order), :class => 'button'

View File

@@ -13,6 +13,6 @@
= form_for @adjustment, :url => admin_order_adjustments_path do |f|
%fieldset.no-border-top
= render :partial => 'form', :locals => { :f => f }
.filter-actions.actions{"data-hook" => "buttons"}
.filter-actions.actions
= button Spree.t(:continue), 'icon-arrow-right'
= button_link_to Spree.t('actions.cancel'), admin_order_adjustments_url(@order), :icon => 'icon-remove'

View File

@@ -5,7 +5,7 @@
= Spree.t(:general_settings)
= form_tag admin_general_settings_path, :method => :put do
#preferences{"data-hook" => ""}
#preferences
%fieldset.general.no-border-top
- @preferences_general.each do |key|
@@ -85,6 +85,6 @@
= preference_field_tag("available_units[#{unit}]", selected, { type: :boolean, selected: selected })
= label_tag(unit, unit.downcase) + tag(:br)
.form-buttons.filter-actions.actions{"data-hook" => "buttons"}
.form-buttons.filter-actions.actions
= button Spree.t('actions.update'), 'icon-refresh'
= link_to_with_icon 'icon-remove', Spree.t('actions.cancel'), edit_admin_general_settings_url, :class => 'button'

View File

@@ -18,10 +18,3 @@
%br/
%span.info
= t("spree.smtp_send_copy_to_this_addresses")
.field
= label_tag :intercept_email, t("spree.intercept_email_address")
%br/
= text_field_tag :intercept_email, Spree::Config[:intercept_email], disabled: true, class: 'fullwidth'
%br/
%span.info
= t("spree.intercept_email_instructions")

View File

@@ -1,13 +1,13 @@
= render :partial => "spree/admin/variants/autocomplete", :formats => :js
#add-line-item{"data-hook" => ""}
#add-line-item
%fieldset.no-border-bottom
%legend{:align => "center"}= Spree.t(:add_product)
- if @order.canceled?
= t(".cannot_add_item_to_canceled_order")
- else
.field.nine.columns.alpha{"data-hook" => "add_product_name"}
.field.nine.columns.alpha
= label_tag :add_variant_id, Spree.t(:name_or_sku)
= hidden_field_tag :add_variant_id, "", :class => "variant_autocomplete fullwidth"
.five.columns.omega

View File

@@ -1,4 +1,4 @@
%div{"data-hook" => "admin_orders_index_search"}
%div.admin-orders-index-search
= form_tag spree.admin_orders_url, {name: "orders_form", "ng-submit" => "fetchResults()"} do
.field-block.alpha.four.columns
.date-range-filter.field

View File

@@ -1,4 +1,4 @@
%div{"data-hook" => "admin_order_form_fields"}
%div.admin-order-form-fields
- if @line_item.try(:errors).present?
= render :partial => 'spree/shared/error_messages', :locals => { :target => @line_item }
@@ -13,7 +13,7 @@
= render :partial => "spree/admin/orders/_form/adjustments", :locals => { :adjustments => order_adjustments_for_display(@order), :title => t(".order_adjustments")}
- if order.line_items.exists?
%fieldset#order-total.no-border-bottom{"data-hook" => "order_details_total"}
%fieldset#order-total.no-border-bottom.order-details-total
%legend{ align: 'center' }= t(".order_total")
%span.order-total= order.display_total

View File

@@ -1,6 +1,6 @@
%div{ :id => "shipment_#{shipment.id}" }
%fieldset.no-border-bottom
%legend.stock-location{ :align => "center", "data-hook" => "stock-location" }
%legend.stock-location{ :align => "center" }
%span.shipment-number
= shipment.number
= "-"
@@ -10,7 +10,7 @@
= "-"
= link_to t(:ship), '#', :class => 'ship button icon-arrow-right', :data => { 'shipment-number' => shipment.number }
%table.stock-contents.index{ "data-hook" => "stock-contents" }
%table.stock-contents.index
%colgroup
%col{ :style => "width: 10%;" }
%col{ :style => "width: 30%;" }
@@ -28,7 +28,7 @@
= Spree.t(:quantity)
%th.force-rounded-right
= Spree.t(:total)
%th.orders-actions.actions{ "data-hook" => "admin_order_form_line_items_header_actions" }
%th.orders-actions.actions
%tbody{ "data-shipment-number" => "#{shipment.number}", "data-order-number" => "#{order.number}" }
= render 'spree/admin/orders/shipment_manifest', order: order, shipment: shipment

View File

@@ -17,7 +17,7 @@
%td.item-total.align-center
= line_item_shipment_price(line_item, item.quantity)
%td.cart-item-delete.actions{ "data-hook" => "cart_item_delete" }
%td.cart-item-delete.actions
- if shipment.can_modify? && can?(:update, shipment)
.flex
= link_to '', '#', :class => 'save-item icon_link icon-ok no-text with-tip', :data => {'shipment-number' => shipment.number, 'variant-id' => item.variant.id, :action => 'save'}, :title => t('actions.save'), :style => 'display: none'

View File

@@ -1,19 +1,19 @@
%fieldset.no-border-top{"data-hook" => "admin_customer_detail_form_fields"}
%fieldset.index.no-border-bottom{"data-hook" => "customer_guest"}
%fieldset.no-border-top
%fieldset.index.no-border-bottom
%legend{:align => "center"}= Spree.t(:account)
.row{"data-hook" => "customer_fields"}
.row
.alpha.eight.columns.fullwidth
.field
= f.label :email, Spree.t(:email) + ':'
= f.email_field :email, :class => 'fullwidth'
.alpha.eight.columns{"data-hook" => "bill_address_wrapper"}
.alpha.eight.columns
%fieldset.no-border-bottom
%legend{:align => "center"}= Spree.t(:billing_address)
= f.fields_for :bill_address do |ba_form|
= render :partial => 'address_form', :locals => { :f => ba_form, :name => Spree.t(:billing_address), :use_billing => false }
.omega.eight.columns{"data-hook" => "ship_address_wrapper"}
.omega.eight.columns
%fieldset.no-border-bottom
%legend{:align => "center"}= Spree.t(:shipping_address)
= f.fields_for :ship_address do |sa_form|
@@ -21,7 +21,7 @@
.clear
.form-buttons.filter-actions.actions{"data-hook" => "buttons"}
.form-buttons.filter-actions.actions
= button Spree.t('actions.update'), 'icon-refresh'
- content_for :head do

View File

@@ -12,7 +12,7 @@
%li= button_link_to Spree.t(:back_to_orders_list), admin_orders_path, :icon => 'icon-arrow-left'
- if @order.cart? || @order.address?
#select-customer{"data-hook" => ""}
#select-customer
%fieldset.no-border-bottom
%legend{:align => "center"}= Spree.t(:customer_search)
- content_for :main_ng_app_name do
@@ -24,3 +24,4 @@
= form_for @order, :url => admin_order_customer_url(@order) do |f|
= render 'form', :f => f
= f.hidden_field :customer_id, value: @order.customer_id, id: "customer_id"

View File

@@ -15,7 +15,7 @@
= render partial: "spree/admin/shared/order_page_title"
= render partial: "spree/admin/shared/order_tabs", locals: { current: 'Order Details' }
%div{"data-hook" => "admin_order_edit_header"}
%div
-# Suppress errors when manually creating a new order - needs to proceed to edit page
-# without having line items (which otherwise gives a validation error)
- unless params["suppress_error_msg"]
@@ -31,5 +31,5 @@
.no-objects-found
= Spree.t(:your_order_is_empty_add_product)
%div{"data-hook" => "admin_order_edit_form"}
%div.admin-order-edit-form
= render :partial => 'form', :locals => { :order => @order }

View File

@@ -3,6 +3,6 @@
.alpha.four.columns
= label :payment_method, :type, t('.provider')
.omega.twelve.columns
= collection_select(:payment_method, :type, @providers, :to_s, :clean_name, (!@object.persisted? ? { :selected => "Spree::PaymentMethod::Check"} : {}), { class: 'select2 fullwidth', 'provider-prefs-for' => "#{@object.id}"})
= collection_select(:payment_method, :type, @providers, :to_s, :clean_name, {}, { class: 'select2 fullwidth', 'provider-prefs-for' => "#{@object.id}"})
%div{"ng-include" => "include_html" }

View File

@@ -1,4 +1,4 @@
%tr.product_property.fields{"data-hook" => "product_property", id: "spree_#{dom_id(f.object)}"}
%tr.product_property.fields{id: "spree_#{dom_id(f.object)}"}
%td.no-border
%span.handle
= f.hidden_field :id

View File

@@ -1,4 +1,4 @@
%div{"data-hook" => "admin_product_form_fields"}
%div.admin-product-form-fields
.left.twelve.columns.alpha
= f.field_container :name do
= f.label :name, raw(t(:name) + content_tag(:span, ' *', :class => 'required'))

View File

@@ -1,4 +1,4 @@
.row{"data-hook" => "admin_product_meta_form"}
.row
.alpha.eleven.columns
= f.field_container :meta_keywords do
= f.label :meta_keywords, t('admin.products.seo.product_search_keywords')

View File

@@ -2,7 +2,7 @@
= t('.title')
- content_for :page_actions do
%div{ :class => "toolbar", 'data-hook' => "toolbar" }
%div{ :class => "toolbar" }
%ul{ :class => "actions header-action-links inline-menu" }
%li#new_product_link
= button_link_to t(:new_product), new_object_url, { :icon => 'icon-plus', :id => 'admin_new_product' }

View File

@@ -1,9 +1,9 @@
%div{"data-hook" => "admin_shipping_category_form_fields"}
.field.align-center{"data-hook" => "name"}
%div
.field.align-center
= label_tag Spree.t(:name)
%br/
= f.text_field :name
.field.align-center{"data-hook" => "name"}
.field.align-center
= f.label :temperature_controlled, t(:temperature_controlled)
= f.check_box :temperature_controlled

View File

@@ -12,14 +12,14 @@
%col{:style => "width: 85%"}/
%col{:style => "width: 15%"}/
%thead
%tr{"data-hook" => "categories_header"}
%tr
%th= Spree.t(:name)
%th
= t(:temperature_controlled)
%th.actions
%tbody
- @shipping_categories.each do |shipping_category|
%tr{:class => "#{cycle('odd', 'even')}", "data-hook" => "category_row", :id => "#{spree_dom_id shipping_category}"}
%tr{:class => "#{cycle('odd', 'even')}", :id => "#{spree_dom_id shipping_category}"}
%td{:style => "width:350px;"}= shipping_category.name
%td.align-center
= shipping_category.temperature_controlled ? t(:yes) : t(:no)

View File

@@ -15,7 +15,7 @@
%col{style: "width: 15%"}/
%col{style: "width: 15%"}/
%thead
%tr{"data-hook" => "tax_header"}
%tr
%th= t("spree.name")
%th= t("spree.description")
%th= t("spree.default")

View File

@@ -5,10 +5,10 @@
= form_tag admin_tax_settings_path, :method => :put do
.field.align-center{ "data-hook" => "products_require_tax_category" }
.field.align-center
= hidden_field_tag 'preferences[products_require_tax_category]', '0'
= check_box_tag 'preferences[products_require_tax_category]', '1', Spree::Config[:products_require_tax_category]
= label_tag nil, t(:products_require_tax_category)
.form-buttons{"data-hook" => "buttons"}
.form-buttons
= button t(:update), 'icon-refresh'

View File

@@ -3,15 +3,15 @@
- content_for :page_actions do
%li
= button_link_to t(".back_to_users_list"), spree.admin_users_path, icon: "icon-arrow-left"
%fieldset.alpha.ten.columns{"data-hook" => "admin_user_edit_general_settings"}
%fieldset.alpha.ten.columns
%legend= t(".general_settings")
%div{"data-hook" => "admin_user_edit_form_header"}
%div
= render partial: "spree/shared/error_messages", locals: { target: @user }
%div{"data-hook" => "admin_user_edit_form"}
%div
= form_for [:admin, @user] do |f|
= render "email_confirmation" unless @user.confirmed?
= render partial: "form", locals: { f: f }
%div{"data-hook" => "admin_user_edit_form_button"}
%div
= render partial: "spree/admin/shared/edit_resource_links"
= render partial: 'spree/admin/users/api_fields'

View File

@@ -29,7 +29,7 @@
<script type='text/template' id='variant_autocomplete_stock_template'>
<fieldset>
<legend align="center"><%= Spree.t(:select_stock) %></legend>
<table class="stock-levels" data-hook="stock-levels">
<table class="stock-levels">
<colgroup>
<col style="width: 60%;" />
<col style="width: 30%;" />

View File

@@ -3,7 +3,7 @@
= admin_inject_available_units
= form_for [:admin, @product, @variant], :url => admin_product_variants_path(@product, @url_filters) do |f|
%fieldset{'data-hook' => "admin_variant_new_form"}
%fieldset
%legend{align: "center"}= t('.new_variant')
= render partial: 'form', locals: { f: f }

View File

@@ -2,7 +2,7 @@
= render "layouts/i18n_script"
= yield :stripe_js
#wrapper{ data: { hook: '' } }
#wrapper
.flash-container
- if flash[:error]
.flash.error= flash[:error]
@@ -15,27 +15,27 @@
= render partial: "spree/layouts/admin/progress_spinner"
%header#header{"data-hook" => ""}
%header#header
.container
%figure.columns.five{"data-hook" => "logo-wrapper"}
%figure.columns.five
= link_to image_tag(Spree::Config[:admin_interface_logo], :id => 'logo'), spree.admin_dashboard_path
%nav.columns.eleven{"data-hook" => "admin_login_navigation_bar"}
%nav.columns.eleven.admin-login-navigation-bar
= render :partial => 'spree/layouts/admin/login_nav'
%nav#admin-menu{ data: { hook: '' }}
%nav#admin-menu
.container.no-gutter
.sixteen.columns.main-menu-wrapper
%ul.inline-menu{"data-hook" => "admin_tabs"}
%ul.inline-menu
= render :partial => 'spree/admin/shared/tabs'
- if content_for?(:sub_menu)
%nav#sub-menu{ data: { hook: ''} }
%nav#sub-menu
.container
.sixteen.columns
= yield :sub_menu
- if content_for?(:page_title) || content_for?(:page_actions)
.js-admin-section-header.admin__section-header{ data: { hook: '' } }
.js-admin-section-header.admin__section-header
.container
.sixteen.columns
.admin__section-header__content
@@ -44,16 +44,16 @@
%h1.js-admin-page-title= yield :page_title
- if content_for?(:page_actions)
%ul.admin__section-header__actions{ data: { hook: 'toolbar' } }
%ul.admin__section-header__actions
= yield :page_actions
.container
.row
- content_class = content_for?(:sidebar) ? "with-sidebar" : ""
#content{:class => content_class, "data-hook" => ""}
#content{:class => content_class}
- if content_for?(:table_filter)
- table_filter_class = content_for?(:sidebar) ? 'twelve columns' : 'sixteen columns'
#table-filter{:class => table_filter_class, "data-hook" => ""}
#table-filter{:class => table_filter_class}
%fieldset
%legend{:align => "center"}= yield :table_filter_title
= yield :table_filter
@@ -61,14 +61,12 @@
%div{:class => div_class}
= yield
- if content_for?(:sidebar)
%aside#sidebar.four.columns{"data-hook" => ""}
%aside#sidebar.four.columns
- if content_for?(:sidebar_title)
%h5.sidebar-title
%span= yield :sidebar_title
= yield :sidebar
%div{"data-hook" => "admin_footer_scripts"}
%script
= raw "Spree.api_key = \"#{spree_current_user.try(:spree_api_key).to_s}\";"

View File

@@ -1,6 +1,6 @@
!!!
%html{:lang => "en", "ng-csp": "no-unsafe-eval" }
%head{"data-hook" => "admin_inside_head"}
%head
= render :partial => 'spree/admin/shared/head'
%body.admin{ "class": ("admin-v2" if feature?(:admin_style_v2, spree_current_user)) }

View File

@@ -1,14 +1,14 @@
- if spree_current_user
%ul#login-nav.inline-menu
%li{"data-hook" => "user-logged-in-as"}
%li.user-logged-in-as
= t(:logged_in_as)
\: #{spree_current_user.email}
%li{"data-hook" => "user-account-link"}
%li
%i.icon-user
= link_to t(:account), account_path
%li{"data-hook" => "user-logout-link"}
%li
%i.icon-signout
= link_to t(:logout), logout_path
%li{"data-hook" => "store-frontend-link"}
%li
%i.icon-external-link
= link_to t(".header.store"), main_app.root_path, target: "_blank"

View File

@@ -1,7 +1,7 @@
%html{ lang: "en", "ng-csp": "no-unsafe-eval" }
%head{"data-hook" => "admin_inside_head"}= render :partial => 'spree/admin/shared/head'
%head= render :partial => 'spree/admin/shared/head'
%body.admin{"data-ajax-root-path" => main_app.root_path}
#wrapper{"data-hook" => ""}
#wrapper
- if flash[:error]
.flash.error= flash[:error]
- if notice
@@ -10,16 +10,16 @@
.flash.success= flash[:success]
= render partial: "spree/layouts/admin/progress_spinner"
%header#header{"data-hook" => ""}
%header#header
.container
%figure.columns.five{"data-hook" => "logo-wrapper"}
%figure.columns.five
= link_to image_tag(Spree::Config[:admin_interface_logo], id: 'logo'), spree.admin_dashboard_path
%nav.columns.eleven{"data-hook" => "admin_login_navigation_bar"}
%nav.columns.eleven.admin-login-navigation-bar
= render partial: "spree/layouts/admin/login_nav"
.container
.row
#content{"data-hook" => ""}
#content
%div{:class => "sixteen columns"}
= yield
%div{"data-hook" => "admin_footer_scripts"}
%div

View File

@@ -2,21 +2,21 @@
.row
.columns.large-12
%table#cart-detail{"data-hook" => ""}
%table#cart-detail
%col{halign: "left", valign: "middle", width: "60%"}/
%col{halign: "left", valign: "middle", width: "15%"}/
%col{halign: "center", valign: "middle", width: "10%"}/
%col{halign: "center", valign: "middle", width: "10%"}/
%col{halign: "center", valign: "middle", width: "5%"}/
%thead
%tr{"data-hook" => "cart_items_headers"}
%tr
%th.cart-item-description-header= t(:item)
%th.cart-item-price-header.text-right= t(:price)
%th.text-center.cart-item-quantity-header= t(:qty)
%th.cart-item-total-header.text-right= t(:total)
%th.cart-item-delete-header
%tbody#line_items{"data-hook" => ""}
%tbody#line_items
= render partial: 'line_item', collection: order_form.object.line_items, locals: {order_form: order_form}
= render 'bought' if show_bought_items? && !@order.complete?

View File

@@ -1,9 +1,9 @@
- variant = line_item.variant
= order_form.fields_for :line_items, line_item do |item_form|
%tr.line-item{class: "variant-#{variant.id}"}
%td.cart-item-description{'data-hook' => "cart_item_description"}
%td.cart-item-description
%div.item-thumb-image{"data-hook" => "cart_item_image"}
%div.item-thumb-image
= render 'spree/shared/variant_thumbnail', variant: variant
= render 'spree/shared/line_item_name', line_item: line_item
@@ -18,21 +18,21 @@
= t(".unavailable_item")
%br/
%td.text-right.cart-item-price{"data-hook" => "cart_item_price"}
%td.text-right.cart-item-price
= line_item.single_display_amount_with_adjustments.to_html
%br
%span.unit-price
= line_item.unit_price_price_and_unit
%td.text-center.cart-item-quantity{"data-hook" => "cart_item_quantity"}
%td.text-center.cart-item-quantity
- finalized_quantity = @order.completed? ? line_item.quantity : 0
= item_form.number_field :quantity,
:min => 0, "ofn-on-hand" => "#{variant.on_demand && 9999 || variant.on_hand}",
"finalizedquantity" => finalized_quantity, :class => "line_item_quantity", :size => 5,
"ng-model" => "line_item_#{line_item.id}",
"validate-stock-quantity" => true
%td.cart-item-total.text-right{"data-hook" => "cart_item_total"}
%td.cart-item-total.text-right
= line_item.display_amount_with_adjustments.to_html unless line_item.quantity.nil?
%td.cart-item-delete.text-center{"data-hook" => "cart_item_delete"}
%td.cart-item-delete.text-center
%a.delete{href: "#", id: "delete_#{dom_id(line_item)}"}
%i.delete.ofn-i_026-trash

View File

@@ -1,31 +1,30 @@
- display_footer = true if display_footer.nil?
%table#line-items{"data-hook" => "order_details"}
%table#line-items
%col{valign: "middle"}/
%col{halign: "center", valign: "middle", width: "5%"}/
%col{halign: "center", valign: "middle", width: "5%"}/
%col{halign: "center", valign: "middle", width: "5%"}/
%thead{"data-hook" => ""}
%tr{"data-hook" => "order_details_line_items_headers"}
%thead
%tr
%th= t(:item)
%th.price= t(:price)
%th.text-center.qty= t(:qty)
%th.text-right.total
%span= t(:total)
%tbody{"data-hook" => ""}
%tbody
- order.line_items.sorted_by_name_and_unit_value.each do |item|
%tr.line_item{"data-hook" => "order_details_line_item_row", class: "variant-#{item.variant.id}" }
%td(data-hook = "order_item_description")
%div.item-thumb-image{"data-hook" => "order_item_image"}
%tr.line_item{ class: "variant-#{item.variant.id}" }
%td
%div.item-thumb-image
= render 'spree/shared/variant_thumbnail', variant: item.variant
= render 'spree/shared/line_item_name', line_item: item
%td.text-right.price{"data-hook" => "order_item_price"}
%td.text-right.price
%span= item.single_display_amount_with_adjustments.to_html
%td.text-center{"data-hook" => "order_item_qty"}= item.quantity
%td.text-right.total{"data-hook" => "order_item_total"}
%td.text-center= item.quantity
%td.text-right.total
%span= item.display_amount_with_adjustments.to_html
= render partial: "spree/orders/totals_footer", locals: { order: order } if display_footer

View File

@@ -1,5 +1,5 @@
%tfoot
#subtotal{"data-hook" => "order_details_subtotal"}
#subtotal
%tr#subtotal-row.total
%td.text-right{colspan: "3"}
%strong
@@ -7,7 +7,7 @@
%td.text-right.total
%span= display_checkout_subtotal(order)
#order-charges{"data-hook" => "order_details_adjustments"}
#order-charges
- checkout_adjustments_for(order, exclude: [:line_item]).reverse_each do |adjustment|
%tr.total
%td.text-right{:colspan => "3"}
@@ -16,7 +16,7 @@
%td.text-right.total
%span= adjustment.display_amount.to_html
#order-total{"data-hook" => "order_details_total"}
#order-total.order-details-total
%tr.total
%td.text-right{colspan: "3"}
%h5
@@ -25,7 +25,7 @@
%h5#order_total= order.display_total.to_html
- if order.total_tax > 0
#tax{"data-hook" => "order_details_tax"}
#tax
%tr#tax-row.total
%td.text-right{colspan: "3"}
= t :order_includes_tax

View File

@@ -27,16 +27,16 @@
#cart-container
- if @order.line_items.empty?
%div.row{"data-hook" => "empty_cart"}
%div.row
%p= t(:your_cart_is_empty)
%p= link_to t(:continue_shopping), current_shop_products_path, :class => 'button continue'
- else
%div{"data-hook" => "outside_cart_form"}
%div
= form_for @order, :url => main_app.update_cart_path,
:html => {id: 'update-cart', name: "form", "ng-controller"=> 'CartFormCtrl'} do |order_form|
%div{"data-hook" => "inside_cart_form"}
%div{"data-hook" => "cart_items"}
%div
%div
.row
= render :partial => 'form', :locals => { :order_form => order_form }

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