diff --git a/.babelrc b/.babelrc
index 0b10d107b..746d17f73 100644
--- a/.babelrc
+++ b/.babelrc
@@ -3,14 +3,32 @@
[
"@babel/preset-env",
{
- "useBuiltIns": "entry"
+ "useBuiltIns": "usage",
+ "corejs": 3,
+ "modules": false
}
]
],
-
"plugins": [
+ "babel-plugin-macros",
"@babel/plugin-syntax-dynamic-import",
- "@babel/plugin-syntax-object-rest-spread",
- "@babel/plugin-proposal-class-properties"
- ]
-}
+ "@babel/plugin-proposal-class-properties",
+ "@babel/plugin-transform-runtime"
+ ],
+ "env": {
+ "test": {
+ "presets": [
+ [
+ "@babel/preset-env",
+ {
+ "targets": { "node": "current" },
+ "modules": "commonjs"
+ }
+ ]
+ ],
+ "plugins": [
+ "babel-plugin-dynamic-import-node"
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/.browserslistrc b/.browserslistrc
index e94f8140c..24a8d0f62 100644
--- a/.browserslistrc
+++ b/.browserslistrc
@@ -1 +1,3 @@
-defaults
+> 0.2%
+not dead
+not op_mini all
diff --git a/.eslintrc.json b/.eslintrc.json
deleted file mode 100644
index 1565e4d2c..000000000
--- a/.eslintrc.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "env": {
- "browser": true,
- "es6": true
- },
- "extends": [
- "plugin:vue/essential",
- "eslint:recommended"
- ],
- "parserOptions": {
- "sourceType": "module"
- },
- "rules": {
- "indent": [
- "error",
- 2
- ],
- "linebreak-style": [
- "error",
- "unix"
- ],
- "quotes": [
- "error",
- "single"
- ],
- "semi": [
- "error",
- "always"
- ]
- }
-}
diff --git a/.gitignore b/.gitignore
index f88fa113e..f84aa0b91 100644
--- a/.gitignore
+++ b/.gitignore
@@ -37,19 +37,14 @@ yarn-error\.log
/node_modules
yarn-debug.log*
.yarn-integrity
+/app/assets/builds/*
+!/app/assets/builds/.keep
# Ignore master key for decrypting credentials and more.
/config/master.key
-/public/packs
-/public/packs-test
-/node_modules
-/yarn-error.log
-yarn-debug.log*
-.yarn-integrity
-
# Ignore Jetbrains IDE files
/.idea
# Ignore gemini-Cli files
-gemini.md
\ No newline at end of file
+gemini.md
diff --git a/.postcssrc.yml b/.postcssrc.yml
deleted file mode 100644
index 150dac3c6..000000000
--- a/.postcssrc.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-plugins:
- postcss-import: {}
- postcss-cssnext: {}
diff --git a/.sass-lint.yml b/.sass-lint.yml
deleted file mode 100644
index e0890ee51..000000000
--- a/.sass-lint.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-files:
- include: 'app/**/*.s+(a|c)ss'
-
-rules:
- indentation:
- - 2
- -
- size: 2
-
- property-sort-order:
- - 2
- -
- # http://rhodesmill.org/brandon/2011/concentric-css/
- order: 'concentric'
-
- force-element-nesting:
- - 2
-
- force-pseudo-nesting:
- - 2
-
- single-line-per-selector:
- - 2
-
- no-qualifying-elements:
- - 2
-
- leading-zero:
- - 2
diff --git a/.slim-lint.yml b/.slim-lint.yml
deleted file mode 100644
index 9f7eafc3d..000000000
--- a/.slim-lint.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-linters:
-
- LineLength:
- max: 120
diff --git a/.stylelintrc.json b/.stylelintrc.json
new file mode 100644
index 000000000..b5b3e9010
--- /dev/null
+++ b/.stylelintrc.json
@@ -0,0 +1,17 @@
+{
+ "extends": [
+ "stylelint-config-standard-scss",
+ "stylelint-config-recess-order"
+ ],
+ "rules": {
+ "selector-no-qualifying-type": [true, {
+ "ignore" : ["attribute", "class", "id"]
+ }]
+ },
+ "overrides": [
+ {
+ "files": ["**/*.vue"],
+ "customSyntax": "postcss-html"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index f5cb658fa..8bc2117bf 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -19,7 +19,7 @@ RUN apt-get update -qq && \
libyaml-dev
# Add Node, required for asset pipeline.
-RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - && \
+RUN curl -sL https://deb.nodesource.com/setup_18.x | bash - && \
apt-get install -y nodejs && \
npm install -q -g yarn
diff --git a/Gemfile b/Gemfile
index 45b02644b..05104b136 100644
--- a/Gemfile
+++ b/Gemfile
@@ -3,14 +3,16 @@ source 'https://rubygems.org'
gem 'bcrypt', '~> 3.1.20'
gem 'bootsnap', '~> 1.18.6'
gem 'browser', '~> 6.2.0'
+gem 'cssbundling-rails', '~> 1.4'
+gem 'dartsass-rails', '~> 0.5.1'
gem 'devise', '~>4.9.4'
gem 'devise-i18n', '~>1.15.0'
gem 'factory_bot_rails', '~> 6.5.1'
gem 'faker', '~> 3.5.2'
-gem 'font-awesome-rails', '~> 4.7.0.9'
gem 'http', '~> 5.3.1'
gem 'jbuilder', '~> 2.14.1'
gem 'jquery-rails', '~> 4.6.1'
+gem 'jsbundling-rails', '~> 1.3'
gem 'kaminari', '~> 1.2.2'
gem 'mollie-api-ruby', '~> 4.18.0'
gem 'net-imap', '~> 0.5.12'
@@ -29,17 +31,16 @@ gem 'rails', '~> 7.2.2', '>= 7.2.2.2'
gem 'rails-i18n', '~> 7.0.10'
gem 'redis-rails', '~> 5.0.2'
gem 'rest-client', '~> 2.1.0'
-gem 'sassc-rails', '~> 2.1.2'
gem 'sentry-rails', '~> 5.28', '>= 5.28.1'
gem 'sentry-ruby', '~> 5.28', '>= 5.28.1'
gem 'sentry-sidekiq', '~> 5.28', '>= 5.28.1'
gem 'sidekiq', '~> 8.0.8'
gem 'sidekiq-scheduler', '~> 6.0.1'
gem 'simple_form', '~> 5.4.0'
-gem 'turbolinks', '~> 5.2.1'
+gem 'sprockets-rails', '~> 3.5'
+gem 'turbo-rails', '~> 2.0'
gem 'uglifier', '~> 4.2.1'
gem 'validates_timeliness', '~> 7.1.0'
-gem 'webpacker', '~> 5.4.4'
gem 'wicked_pdf', '~> 2.8.2'
gem 'wkhtmltopdf-binary', '~> 0.12.6.10'
diff --git a/Gemfile.lock b/Gemfile.lock
index 1bf4502e4..12e45aa9e 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -113,6 +113,11 @@ GEM
concurrent-ruby (1.3.5)
connection_pool (2.5.4)
crass (1.0.6)
+ cssbundling-rails (1.4.3)
+ railties (>= 6.0.0)
+ dartsass-rails (0.5.1)
+ railties (>= 6.0.0)
+ sass-embedded (~> 1.63)
database_consistency (2.0.6)
activerecord (>= 3.2)
date (3.4.1)
@@ -155,13 +160,10 @@ GEM
logger
faraday-net_http (3.4.1)
net-http (>= 0.5.0)
- ffi (1.17.2)
ffi (1.17.2-x86_64-linux-gnu)
ffi-compiler (1.3.2)
ffi (>= 1.15.5)
rake
- font-awesome-rails (4.7.0.9)
- railties (>= 3.2, < 9.0)
foreman (0.90.0)
thor (~> 1.4)
formatador (1.2.1)
@@ -171,6 +173,9 @@ GEM
raabro (~> 1.4)
globalid (1.3.0)
activesupport (>= 6.1)
+ google-protobuf (4.33.0-x86_64-linux-gnu)
+ bigdecimal
+ rake (>= 13)
guard (2.19.1)
formatador (>= 0.2.4)
listen (>= 2.7, < 4.0)
@@ -217,6 +222,8 @@ GEM
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
+ jsbundling-rails (1.3.1)
+ railties (>= 6.0.0)
json (2.15.2)
jwt (3.1.2)
base64
@@ -352,8 +359,6 @@ GEM
base64 (>= 0.1.0)
logger (>= 1.6.0)
rack (>= 3.0.0, < 4)
- rack-proxy (0.7.7)
- rack
rack-session (2.1.1)
base64 (>= 0.1.0)
rack (>= 3.0.0)
@@ -499,16 +504,9 @@ GEM
ruby-progressbar (1.13.0)
rufus-scheduler (3.9.2)
fugit (~> 1.1, >= 1.11.1)
- sassc (2.4.0)
- ffi (~> 1.9)
- sassc-rails (2.1.2)
- railties (>= 4.0.0)
- sassc (>= 2.0)
- sprockets (> 3.0)
- sprockets-rails
- tilt
+ sass-embedded (1.93.2-x86_64-linux-gnu)
+ google-protobuf (~> 4.31)
securerandom (0.4.1)
- semantic_range (3.1.0)
sentry-rails (5.28.1)
railties (>= 5.0)
sentry-ruby (~> 5.28.1)
@@ -565,14 +563,13 @@ GEM
stringio (3.1.7)
terminal-notifier-guard (1.7.0)
thor (1.4.0)
- tilt (2.6.1)
timecop (0.9.10)
timeliness (0.5.3)
timeout (0.4.3)
tsort (0.2.0)
- turbolinks (5.2.1)
- turbolinks-source (~> 5.2)
- turbolinks-source (5.2.0)
+ turbo-rails (2.0.17)
+ actionpack (>= 7.1.0)
+ railties (>= 7.1.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
uglifier (4.2.1)
@@ -594,11 +591,6 @@ GEM
activemodel (>= 6.0.0)
bindex (>= 0.4.0)
railties (>= 6.0.0)
- webpacker (5.4.4)
- activesupport (>= 5.2)
- rack-proxy (>= 0.6.1)
- railties (>= 5.2)
- semantic_range (>= 2.3.0)
websocket-driver (0.8.0)
base64
websocket-extensions (>= 0.1.0)
@@ -622,19 +614,21 @@ DEPENDENCIES
bullet (~> 8.1)
capistrano-sidekiq (~> 3.2.0)
colorize (~> 1.1.0)
+ cssbundling-rails (~> 1.4)
+ dartsass-rails (~> 0.5.1)
database_consistency (~> 2.0.6)
devise (~> 4.9.4)
devise-i18n (~> 1.15.0)
dotenv-rails (~> 3.1.8)
factory_bot_rails (~> 6.5.1)
faker (~> 3.5.2)
- font-awesome-rails (~> 4.7.0.9)
foreman (~> 0.90.0)
guard-livereload (~> 2.5.2)
guard-rspec (~> 4.7.3)
http (~> 5.3.1)
jbuilder (~> 2.14.1)
jquery-rails (~> 4.6.1)
+ jsbundling-rails (~> 1.3)
kaminari (~> 1.2.2)
listen (~> 3.9.0)
mina (~> 1.2.5)
@@ -666,7 +660,6 @@ DEPENDENCIES
rubocop-rails (~> 2.33, >= 2.33.4)
rubocop-rspec (~> 3.7)
rubocop-rspec_rails (~> 2.31)
- sassc-rails (~> 2.1.2)
sentry-rails (~> 5.28, >= 5.28.1)
sentry-ruby (~> 5.28, >= 5.28.1)
sentry-sidekiq (~> 5.28, >= 5.28.1)
@@ -678,14 +671,14 @@ DEPENDENCIES
spring (~> 4.4.0)
spring-commands-rspec (~> 1.0.4)
spring-watcher-listen (~> 2.1.0)
+ sprockets-rails (~> 3.5)
terminal-notifier-guard (~> 1.7.0)
timecop (~> 0.9.10)
- turbolinks (~> 5.2.1)
+ turbo-rails (~> 2.0)
tzinfo-data
uglifier (~> 4.2.1)
validates_timeliness (~> 7.1.0)
web-console (~> 4.2.1)
- webpacker (~> 5.4.4)
wicked_pdf (~> 2.8.2)
wkhtmltopdf-binary (~> 0.12.6.10)
diff --git a/Procfile.dev b/Procfile.dev
new file mode 100644
index 000000000..43717fdeb
--- /dev/null
+++ b/Procfile.dev
@@ -0,0 +1,3 @@
+web: env RUBY_DEBUG_OPEN=true bin/rails server -b 0.0.0.0
+js: NODE_ENV=development yarn watch
+css: yarn build:css --watch
diff --git a/README.md b/README.md
index 02fea7872..e259e4ea2 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@ Alpha SOFIA
[](https://github.com/csvalpha/sofia/actions/workflows/continuous-delivery.yml)
[](https://codecov.io/github/csvalpha/sofia)
-The source code belonging to Alpha SOFIA. It is a system built with Ruby on Rails with Turbolinks and a little VueJS, used to manage orders in our own bar "Flux". Users authenticate via OAuth API (currently "Alpha AMBER") or through the builtin login portal to see how much credit they got left, or to be able to register new orders and/or payments.
+The source code belonging to Alpha SOFIA. It is a system built with Ruby on Rails with Turbo and a little VueJS, used to manage orders in our own bar "Flux". Users authenticate via OAuth API (currently "Alpha AMBER") or through the built-in login portal to see how much credit they have left, or to register new orders and/or payments.
Use this repository to build upon, use as-is, learn from it, prove a point or whatever 😏
diff --git a/app/.gitattributes b/app/.gitattributes
new file mode 100644
index 000000000..a9fc77db5
--- /dev/null
+++ b/app/.gitattributes
@@ -0,0 +1,2 @@
+# Default to LF for most text files
+* text=auto eol=lf
diff --git a/app/assets/builds/.keep b/app/assets/builds/.keep
new file mode 100644
index 000000000..e69de29bb
diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js
index b16e53d6d..9a99757a4 100644
--- a/app/assets/config/manifest.js
+++ b/app/assets/config/manifest.js
@@ -1,3 +1,2 @@
//= link_tree ../images
-//= link_directory ../javascripts .js
-//= link_directory ../stylesheets .css
+//= link_tree ../builds
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
deleted file mode 100644
index bdd70a3e5..000000000
--- a/app/assets/javascripts/application.js
+++ /dev/null
@@ -1,36 +0,0 @@
-// This is a manifest file that'll be compiled into application.js, which will include all the files
-// listed below.
-//
-// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, or any plugin's
-// vendor/assets/javascripts directory can be referenced here using a relative path.
-//
-// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
-// compiled file. JavaScript code in this file should be added after the last require_* statement.
-//
-// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
-// about supported directives.
-//
-//= require rails-ujs
-//= require turbolinks
-//= require jquery3
-//= require bootstrap.bundle.min.js
-//= require webfontloader.js
-//= require turbolinks-animate/src/index.js
-//= require_tree .
-
-/* eslint-disable no-undef */
-WebFont.load({
- google: {
- families: ['Roboto:300,400,500']
- }
-});
-
-document.addEventListener( 'turbolinks:load', function() {
- TurbolinksAnimate.init({
- element: document.querySelector('main'),
- animation: 'fadein',
- duration: '0.15s',
- });
-});
-
-/* eslint-enable no-undef */
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index 1bf012c17..085224c7b 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -1,7 +1,5 @@
+@import 'bootstrap/scss/bootstrap';
@import 'theme_sofia';
-@import 'bootstrap';
-@import 'font-awesome';
-
@import 'order_screen';
@import 'price_lists';
@@ -29,16 +27,16 @@ a {
.slide-fade-enter,
.slide-fade-leave-to {
- transform: translateX(10px);
opacity: 0;
+ transform: translateX(10px);
}
// Source: jsfiddle.net/mwj2tagh
.fa-plus18 {
- text-align: center;
- font-family: 'helvetica neue', Helvetica, Arial, Sans-Serif;
+ font-family: 'helvetica neue', Helvetica, Arial, sans-serif;
font-size: 80%;
font-weight: bold;
+ text-align: center;
&::before {
content: '18+';
@@ -80,10 +78,10 @@ a {
.footer {
position: absolute;
bottom: 0;
- background-color: $gray-400;
width: 100%;
height: 48px;
line-height: 48px;
+ background-color: $gray-400;
}
.footer-padding {
diff --git a/app/assets/stylesheets/order_screen.scss b/app/assets/stylesheets/order_screen.scss
index 27af62c2d..0735535ba 100644
--- a/app/assets/stylesheets/order_screen.scss
+++ b/app/assets/stylesheets/order_screen.scss
@@ -1,76 +1,23 @@
+@import 'bootstrap/scss/bootstrap';
@import 'theme_sofia';
-@import 'bootstrap';
+
.order-screen {
display: grid;
-
+ grid-template-rows: [header-start] 80px [header-end user-details-start product-grid-start orders-start order-grid-start] 1fr [user-details-end orders-end product-grid-end order-grid-end];
+ grid-template-columns: [header-start orders-start user-details-start] minmax(35%, 340px) [user-details-end orders-end product-grid-start order-grid-start] 1fr [header-end product-grid-end order-grid-end];
width: 100vw;
height: 100vh;
- grid-template-columns: [header-start orders-start user-details-start] minmax(35%, 340px) [user-details-end orders-end product-grid-start order-grid-start] 1fr [header-end product-grid-end order-grid-end];
- grid-template-rows: [header-start] 80px [header-end user-details-start product-grid-start orders-start order-grid-start] 1fr [user-details-end orders-end product-grid-end order-grid-end];
-
- .header {
- display: flex;
-
- flex-flow: row nowrap;
- justify-content: space-between;
- z-index: 10;
-
- box-shadow: 0 1px 4px $transparent-200;
- background-color: $gray-100;
-
- color: $font-color-dark;
-
- grid-area: header;
- }
-
- .header-nav {
- display: flex;
- flex: 1;
-
- flex-flow: row nowrap;
- align-items: center;
- align-self: flex-start;
- justify-content: start;
-
- margin: 0;
- padding: 0;
-
- height: 100%;
-
- list-style: none;
-
- line-height: 20pt;
- font-size: $font-size-xl;
- }
-
- .header-nav-item {
- padding: 0 1rem;
- }
-
- .header-nav-home {
- a {
- i {
- padding: 0;
- padding-left: 1rem;
- color: $gray-600;
- }
- }
- }
-
.flash {
display: flex;
align-self: flex-end;
-
- background-color: $gray-800;
height: 100%;
-
+ font-size: $font-size-lg;
vertical-align: middle;
- text-align: center;
-
color: $font-color-light;
- font-size: $font-size-lg;
+ text-align: center;
+ background-color: $gray-800;
}
.flash-text {
@@ -114,28 +61,75 @@
color: inherit;
}
+ .orders-rows-row-count {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-between;
+
+ i {
+ color: $font-color-medium;
+ }
+ }
+
+ .header {
+ z-index: 10;
+ display: flex;
+ flex-flow: row nowrap;
+ grid-area: header;
+ justify-content: space-between;
+ color: $font-color-dark;
+ background-color: $gray-100;
+ box-shadow: 0 1px 4px $transparent-200;
+ }
+
+ .header-nav {
+ display: flex;
+ flex: 1;
+ flex-flow: row nowrap;
+ align-items: center;
+ align-self: flex-start;
+ justify-content: start;
+ height: 100%;
+ padding: 0;
+ margin: 0;
+ font-size: $font-size-xl;
+ line-height: 20pt;
+ list-style: none;
+ }
+
+ .header-nav-item {
+ padding: 0 1rem;
+ }
+
+ .header-nav-home {
+ a {
+ i {
+ padding: 0;
+ padding-left: 1rem;
+ color: $gray-600;
+ }
+ }
+ }
+
.side-panel {
+ z-index: 4;
display: flex;
flex-flow: column nowrap;
+ grid-area: user-details;
align-items: stretch;
justify-content: flex-start;
-
- z-index: 4;
-
+ overflow-y: auto;
+ color: $font-color-dark;
+ background-color: $gray-200;
border-right: 2px solid $gray-400;
box-shadow: 2px 0 4px -2px $transparent-200;
- background-color: $gray-200;
- color: $font-color-dark;
- overflow-y: auto;
-
- grid-area: user-details;
}
.user-details {
+ z-index: 5;
display: flex;
flex-flow: column nowrap;
-
- z-index: 5;
overflow-y: auto;
.highlight {
@@ -144,19 +138,16 @@
}
.user-details-search {
- flex-shrink: 0;
-
z-index: 6;
-
- border-bottom: 1px solid $gray-400;
+ flex-shrink: 0;
padding: 1.5rem;
+ border-bottom: 1px solid $gray-400;
}
.user-details-seperator {
- text-align: center;
-
- color: $font-color-medium;
font-size: $font-size-lg;
+ color: $font-color-medium;
+ text-align: center;
}
.user-details-cash-button {
@@ -176,22 +167,19 @@
}
.user-details-suggestions {
+ z-index: 6;
display: flex;
flex-flow: column nowrap;
-
- z-index: 6;
overflow-y: auto;
}
.user-details-user {
z-index: 6;
-
border-bottom: 1px solid $gray-400;
}
.user-details-suggestions-user {
flex-shrink: 0;
-
border-bottom: 1px solid $gray-400;
&.highlight,
@@ -201,11 +189,10 @@
}
.orders {
+ z-index: 5;
display: flex;
- flex-flow: column nowrap;
flex-grow: 1;
-
- z-index: 5;
+ flex-flow: column nowrap;
& > * {
flex: 0 1 auto;
@@ -223,27 +210,14 @@
.orders-rows-row {
align-items: center;
-
- border-top: 1px solid $gray-400;
-
font-size: $font-size-lg;
+ border-top: 1px solid $gray-400;
&:last-child {
border-bottom: 1px solid $gray-400;
}
}
- .orders-rows-row-count {
- display: flex;
- flex-direction: row;
- align-items: center;
- justify-content: space-between;
-
- i {
- color: $font-color-medium;
- }
- }
-
.orders-rows-total {
font-size: $font-size-lg;
}
@@ -253,23 +227,20 @@
}
.orders-confirmation {
- padding: 1rem;
width: 100%;
-
- color: $font-color-light;
+ padding: 1rem;
font-size: $font-size-lg;
+ color: $font-color-light;
}
.product-grid {
display: grid;
+ grid-area: product-grid;
+ grid-template-rows: auto;
+ grid-template-columns: repeat(4, 1fr);
+ gap: 2px;
justify-content: flex-start;
-
background-color: $gray-400;
-
- grid-template-columns: repeat(4, 1fr);
- grid-template-rows: auto;
- grid-gap: 2px;
- grid-area: product-grid;
}
.product-grid-product {
@@ -277,7 +248,6 @@
flex-flow: column nowrap;
align-items: center;
justify-content: center;
-
background-color: $gray-100;
&:hover {
@@ -294,9 +264,9 @@
}
.product-grid-product-name {
- text-align: center;
- color: $font-color-dark;
font-size: $font-size-lg;
+ color: $font-color-dark;
+ text-align: center;
}
.fa-circle-lighter {
@@ -308,4 +278,4 @@
grid-area: order-grid;
overflow-y: auto;
}
-}
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/theme_sofia.scss b/app/assets/stylesheets/theme_sofia.scss
index 3b985bfda..b2e69ba7e 100644
--- a/app/assets/stylesheets/theme_sofia.scss
+++ b/app/assets/stylesheets/theme_sofia.scss
@@ -1,8 +1,7 @@
// Basic colors
-$brand-primary: #e8df0c;
+$brand-primary: #e8df0c;
$brand-secondary: #00a5b5;
-
$gray-100: #f8f9fa;
$gray-200: #e9ecef;
$gray-300: #dee2e6;
@@ -14,24 +13,21 @@ $gray-800: #343a40;
$gray-900: #212529;
// Transparent blacks
-$transparent-200: rgba(0, 0, 0, .2);
-$transparent-800: rgba(0, 0, 0, .8);
+$transparent-200: rgb(0 0 0 / 20%);
+$transparent-800: rgb(0 0 0 / 80%);
// Typography
-$font-family-sans-serif: Roboto, 'Helvetica Neue', Arial, sans-serif;
-
-$font-size-base: .93rem;
-$font-size-xl: ($font-size-base * 2);
-
-$font-color-light: $gray-100;
-$font-color-medium: $gray-600;
-$font-color-dark: $gray-800;
-
+$font-family-sans-serif: roboto, 'Helvetica Neue', arial, sans-serif;
+$font-size-base: .93rem;
+$font-size-xl: ($font-size-base * 2);
+$font-color-light: $gray-100;
+$font-color-medium: $gray-600;
+$font-color-dark: $gray-800;
$alpha-primary: #ff0;
// Basic layout
-$body-bg: $gray-100;
-$body-color: $font-color-dark;
+$body-bg: $gray-100;
+$body-color: $font-color-dark;
// Custom stuff
.table-header-rotated {
@@ -40,8 +36,8 @@ $body-color: $font-color-dark;
white-space: nowrap;
> div {
- transform: translate(-9px, 0) rotate(-45deg);
width: 30px;
+ transform: translate(-9px, 0) rotate(-45deg);
}
> div > a {
@@ -51,10 +47,10 @@ $body-color: $font-color-dark;
.sofia-header {
margin-bottom: .5rem;
- line-height: 1.2;
- color: inherit;
font-family: inherit;
font-size: 2.5rem;
font-weight: 500;
+ line-height: 1.2;
+ color: inherit;
}
}
diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb
index e79828b8a..b9f77f45d 100644
--- a/app/controllers/orders_controller.rb
+++ b/app/controllers/orders_controller.rb
@@ -39,7 +39,7 @@ def create # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
end
def update
- @order = Order.find(permitted_attributes_on_update[:id])
+ @order = Order.find(params[:id])
authorize @order
@@ -89,7 +89,7 @@ def permitted_attributes
end
def permitted_attributes_on_update
- params.permit(:id, order_rows_attributes: %i[id product_count])
+ params.require(:order).permit(order_rows_attributes: %i[id product_count])
end
def proper_json
diff --git a/app/javascript/packs/activities.js b/app/javascript/activities.js
similarity index 57%
rename from app/javascript/packs/activities.js
rename to app/javascript/activities.js
index 7754e20fb..57816e4e5 100644
--- a/app/javascript/packs/activities.js
+++ b/app/javascript/activities.js
@@ -1,16 +1,10 @@
import Vue from 'vue/dist/vue.esm';
-import TurbolinksAdapter from 'vue-turbolinks';
-import VueResource from 'vue-resource';
-Vue.use(TurbolinksAdapter);
-Vue.use(VueResource);
+document.addEventListener('turbo:load', () => {
+ const element = document.getElementById('new_activity_modal');
+ if (element) {
+ const priceLists = JSON.parse(element.dataset.priceLists);
-document.addEventListener('turbolinks:load', () => {
- Vue.http.headers.common['X-CSRF-TOKEN'] = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
-
- var element = document.getElementById('new_activity_modal');
- if (element !== null) {
- var price_lists = JSON.parse(element.dataset.priceLists);
new Vue({
el: element,
data: {
@@ -19,7 +13,7 @@ document.addEventListener('turbolinks:load', () => {
id: 0,
},
open: false,
- allSuggestions: price_lists
+ allSuggestions: priceLists
},
computed: {
dropdownOpened () {
@@ -27,7 +21,7 @@ document.addEventListener('turbolinks:load', () => {
},
suggestions () {
return this.allSuggestions.filter(value => {
- return value.name.indexOf(this.query) >= 0;
+ return value.name.toLowerCase().indexOf(this.query.toLowerCase()) >= 0;
});
}
},
@@ -45,4 +39,4 @@ document.addEventListener('turbolinks:load', () => {
}
});
}
-});
+});
\ No newline at end of file
diff --git a/app/javascript/activity.js b/app/javascript/activity.js
new file mode 100644
index 000000000..450d5d82f
--- /dev/null
+++ b/app/javascript/activity.js
@@ -0,0 +1,24 @@
+import Vue from 'vue/dist/vue.esm';
+
+import ProductTotals from './components/activity/ProductTotals.vue';
+
+let vueInstance = null;
+
+document.addEventListener('turbo:before-cache', () => {
+ if (vueInstance) {
+ vueInstance.$destroy();
+ vueInstance = null;
+ }
+});
+
+document.addEventListener('turbo:load', () => {
+ const element = document.getElementById('activity');
+ if (element) {
+ vueInstance = new Vue({
+ el: element,
+ components: {
+ ProductTotals
+ }
+ });
+ }
+});
diff --git a/app/javascript/application.js b/app/javascript/application.js
new file mode 100644
index 000000000..fd15ec766
--- /dev/null
+++ b/app/javascript/application.js
@@ -0,0 +1,31 @@
+import { Turbo } from '@hotwired/turbo-rails';
+Turbo.start();
+
+import axios from 'axios';
+
+import 'jquery';
+import 'bootstrap';
+
+import WebFont from 'webfontloader';
+import '@fortawesome/fontawesome-free/css/all.css';
+
+WebFont.load({
+ google: {
+ families: ['Roboto:300,400,500']
+ }
+});
+
+axios.interceptors.request.use((config) => {
+ const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
+ if (csrfToken) {
+ config.headers['X-CSRF-Token'] = csrfToken;
+ }
+ return config;
+}, (error) => {
+ return Promise.reject(error);
+});
+
+
+document.addEventListener('turbo:load', () => {
+
+});
\ No newline at end of file
diff --git a/app/javascript/components/ProductTable.vue b/app/javascript/components/ProductTable.vue
index d9652403a..ff7b81ac3 100644
--- a/app/javascript/components/ProductTable.vue
+++ b/app/javascript/components/ProductTable.vue
@@ -18,10 +18,10 @@
+ class="far fa-square-plus order-history-item-count">
{{orderRow.product_count}}
+ class="far fa-square-minus order-history-item-count">
{{orderRow.product_count}}
@@ -33,8 +33,8 @@
{{doubleToCurrency(orderRow.product_count * orderRow.price_per_product)}}
-
-
+
+
@@ -73,21 +73,24 @@ export default {
},
saveOrderRow(orderRow) {
- const newOrder = {
+ const orderData = {
order_rows_attributes: [ {
id: orderRow.id,
product_count: orderRow.product_count,
} ]
};
- if (this.activity.id) newOrder.activity_id = this.activity.id;
+ const payload = {
+ order: orderData
+ };
- axios.patch(`/orders/${this.order.id}`, newOrder).then((response) => {
+ axios.patch(`/orders/${this.order.id}`, payload).then((response) => {
const updatedOrder = response.data;
this.$emit('updateordertotal', this.order, updatedOrder.order_total);
orderRow.editing = false;
+ this.$set(this.orderRowErrors, orderRow.id, null);
}, (error) => {
let errorMessage = 'Er is iets misgegaan bij het opslaan van deze rij';
if (error.response && error.response.data['order_rows.product_count']) {
diff --git a/app/javascript/components/UserInput.vue b/app/javascript/components/UserInput.vue
index 4e07be4f0..0994b93c1 100644
--- a/app/javascript/components/UserInput.vue
+++ b/app/javascript/components/UserInput.vue
@@ -19,6 +19,8 @@
<% end %>
-
-
- <%= csrf_meta_tags %>
-
<%= yield(:modal) %>
diff --git a/app/views/layouts/errors.html.erb b/app/views/layouts/errors.html.erb
index f3459a9ea..a44767d54 100644
--- a/app/views/layouts/errors.html.erb
+++ b/app/views/layouts/errors.html.erb
@@ -3,8 +3,8 @@
<%= "#{Rails.application.config.x.site_name} – Streepsysteem der #{Rails.application.config.x.site_association}" %>
- <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
- <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
+ <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
+ <%= javascript_include_tag "application", "data-turbo-track": "reload", defer: true %>
diff --git a/app/views/partials/_login_prompt.html.erb b/app/views/partials/_login_prompt.html.erb
index 0ba91def2..e9baa0ba8 100644
--- a/app/views/partials/_login_prompt.html.erb
+++ b/app/views/partials/_login_prompt.html.erb
@@ -10,7 +10,7 @@
Log in with a <%= Rails.application.config.x.site_association %> account.
- <%= link_to("Sign in with #{Rails.application.config.x.site_association}", user_amber_oauth2_omniauth_authorize_path, class: 'btn btn-primary', method: :post) %>
+ <%= link_to "Sign in with #{Rails.application.config.x.site_association}", user_amber_oauth2_omniauth_authorize_path, class: 'btn btn-primary', data: { turbo_method: :post } %>
diff --git a/app/views/partials/_navigation_bar.html.erb b/app/views/partials/_navigation_bar.html.erb
index e4ebdf08f..b9c3d5608 100644
--- a/app/views/partials/_navigation_bar.html.erb
+++ b/app/views/partials/_navigation_bar.html.erb
@@ -10,60 +10,60 @@
-
<%= nav_link root_path, class: 'nav-link' do %>
- <%= fa_icon 'home', class: 'me-2', text: 'Home' %>
+ Home
<% end %>
<% if policy(Activity).index? %>
-
<%= nav_link activities_path, class: 'nav-link' do %>
- <%= fa_icon 'calendar', class: 'me-2', text: 'Activiteiten' %>
+ Activiteiten
<% end %>
<% end %>
<% if current_user&.treasurer? || current_user&.renting_manager? %>
-
<%= nav_link users_path, class: 'nav-link' do %>
- <%= fa_icon 'users', class: 'me-2', text: 'Gebruikers' %>
+ Gebruikers
<% end %>
-
<%= nav_link price_lists_path, class: 'nav-link' do %>
- <%= fa_icon 'beer', class: 'me-2', text: 'Prijslijsten' %>
+ Prijslijsten
<% end %>
<% end %>
<% if current_user&.treasurer? %>
-
<%= nav_link credit_mutations_path, class: 'nav-link' do %>
- <%= fa_icon 'money', class: 'me-2', text: 'Inleg en saldocorrecties' %>
+ Inleg en saldocorrecties
<% end %>
<% end %>
<% if policy(:zatladder).index? %>
-
<%= nav_link zatladder_index_path, class: 'nav-link' do %>
- <%= fa_icon 'list', class: 'me-2', text: 'Zatladder' %>
+ Zatladder
<% end %>
<% end %>
<% if policy(Invoice).index? %>
-
<%= nav_link invoices_path, class: 'nav-link' do %>
- <%= fa_icon 'shopping-cart', class: 'me-2', text: 'Facturen' %>
+ Facturen
<% end %>
<% end %>
<% if policy(Payment).index? %>
-
<%= nav_link payments_path, class: 'nav-link' do %>
- <%= fa_icon 'credit-card', class: 'me-2', text: 'Betalingen' %>
+ Betalingen
<% end %>
<% end %>
<% if policy(:finance_overview).index? %>
-
<%= nav_link finance_overview_index_path, class: 'nav-link' do %>
- <%= fa_icon 'money', class: 'me-2', text: 'Financien' %>
+ Financien
<% end %>
<% end %>
@@ -72,14 +72,14 @@
<%= nav_link current_user, class: 'nav-item' do %>
- <%= fa_icon 'user-circle-o', class: 'me-2', text: current_user.name %>
+ <%= current_user.name %>
<% end %>
- <%= link_to '(uitloggen)', destroy_user_session_path, class: 'ms-1', method: :delete %>
+ <%= link_to '(uitloggen)', destroy_user_session_path, class: 'ms-1', data: { turbo_method: :delete }%>
<% end %>
-
+
\ No newline at end of file
diff --git a/app/views/payments/add.html.erb b/app/views/payments/add.html.erb
index 904e26e49..c1074cea0 100644
--- a/app/views/payments/add.html.erb
+++ b/app/views/payments/add.html.erb
@@ -1,5 +1,7 @@
<% content_for :title, "Saldo opwaarderen voor #{@user.name} - #{Rails.application.config.x.site_name}" %>
-
+<% content_for :head do %>
+ <%= javascript_include_tag "payment_add", "data-turbo-track": "reload", defer: true %>
+<% end %>
<%= content_tag :div, id: 'payment-add', class: 'container footer-padding', data: {user_credit: @user.credit, payment_amount: @payment.amount} do %>
-<% end %>
+<% end %>
\ No newline at end of file
diff --git a/app/views/users/index.html.erb b/app/views/users/index.html.erb
index 9617f796c..80ff06102 100644
--- a/app/views/users/index.html.erb
+++ b/app/views/users/index.html.erb
@@ -1,4 +1,7 @@
<% content_for :title, "Gebruikers - #{Rails.application.config.x.site_name}" %>
+<% content_for :head do %>
+ <%= javascript_include_tag "users", "data-turbo-track": "reload", defer: true %>
+<% end %>
<% content_for :modal do %>
<%= render 'modal' %>
<% end %>
@@ -11,7 +14,7 @@
Handmatig aangemaakte gebruikers
<% if policy(User).create? %>