From e31b2782e6521b70201081800413a4d90e4f210f Mon Sep 17 00:00:00 2001 From: ZippyDev Date: Sat, 25 Apr 2020 19:41:40 -0600 Subject: [PATCH] update views, mailers, styles, etc. --- Gemfile | 3 +- Gemfile.lock | 4 + Procfile | 4 + README.md | 1 + app/assets/stylesheets/application.scss | 19 ++ app/assets/stylesheets/devise.scss | 15 ++ app/assets/stylesheets/mailer.scss | 18 ++ app/controllers/application_controller.rb | 2 +- app/helpers/application_helper.rb | 23 +++ app/javascript/controllers/application.js | 0 app/javascript/controllers/home.js | 0 app/javascript/packs/application.js | 4 +- app/javascript/packs/bulma/base.js | 1 + app/javascript/packs/bulma/notification.js | 16 ++ app/javascript/packs/devise.js | 11 ++ app/mailers/bulma_devise_mailer.rb | 6 + app/models/user.rb | 13 ++ app/views/devise/confirmations/new.html.erb | 46 +++++ .../mailer/confirmation_instructions.html.erb | 25 +++ .../devise/mailer/email_changed.html.erb | 28 +++ .../devise/mailer/password_change.html.erb | 26 +++ .../reset_password_instructions.html.erb | 26 +++ .../mailer/unlock_instructions.html.erb | 25 +++ app/views/devise/passwords/edit.html.erb | 66 +++++++ app/views/devise/passwords/new.html.erb | 45 +++++ app/views/devise/registrations/edit.html.erb | 124 ++++++++++++ app/views/devise/registrations/new.html.erb | 71 +++++++ app/views/devise/sessions/new.html.erb | 58 ++++++ .../devise/shared/_error_messages.html.erb | 12 ++ app/views/devise/shared/_links.html.erb | 39 ++++ app/views/devise/unlocks/new.html.erb | 45 +++++ app/views/layouts/application.html.erb | 6 +- app/views/layouts/mailer.html.erb | 19 +- app/views/shared/_developer_view.html.erb | 25 +++ app/views/shared/_notifications.html.erb | 13 ++ config/initializers/assets.rb | 1 + config/initializers/devise.rb | 4 +- config/initializers/premailer_rails.rb | 3 + config/initializers/simple_form.rb | 177 ++++++++++++++++++ config/locales/simple_form.en.yml | 31 +++ config/webpack/environment.js | 8 + config/webpacker.yml | 4 +- docker-compose.yml | 15 +- lib/templates/erb/scaffold/_form.html.erb | 15 ++ package.json | 1 + public/404.html | 89 +++------ public/422.html | 87 +++------ public/500.html | 86 +++------ yarn.lock | 5 + 49 files changed, 1162 insertions(+), 203 deletions(-) create mode 100644 Procfile create mode 100644 app/assets/stylesheets/devise.scss create mode 100644 app/assets/stylesheets/mailer.scss delete mode 100644 app/javascript/controllers/application.js delete mode 100644 app/javascript/controllers/home.js create mode 100644 app/javascript/packs/bulma/base.js create mode 100644 app/javascript/packs/bulma/notification.js create mode 100644 app/javascript/packs/devise.js create mode 100644 app/mailers/bulma_devise_mailer.rb create mode 100644 app/views/devise/confirmations/new.html.erb create mode 100644 app/views/devise/mailer/confirmation_instructions.html.erb create mode 100644 app/views/devise/mailer/email_changed.html.erb create mode 100644 app/views/devise/mailer/password_change.html.erb create mode 100644 app/views/devise/mailer/reset_password_instructions.html.erb create mode 100644 app/views/devise/mailer/unlock_instructions.html.erb create mode 100644 app/views/devise/passwords/edit.html.erb create mode 100644 app/views/devise/passwords/new.html.erb create mode 100644 app/views/devise/registrations/edit.html.erb create mode 100644 app/views/devise/registrations/new.html.erb create mode 100644 app/views/devise/sessions/new.html.erb create mode 100644 app/views/devise/shared/_error_messages.html.erb create mode 100644 app/views/devise/shared/_links.html.erb create mode 100644 app/views/devise/unlocks/new.html.erb create mode 100644 app/views/shared/_developer_view.html.erb create mode 100644 app/views/shared/_notifications.html.erb create mode 100644 config/initializers/premailer_rails.rb create mode 100644 config/initializers/simple_form.rb create mode 100644 config/locales/simple_form.en.yml create mode 100644 lib/templates/erb/scaffold/_form.html.erb diff --git a/Gemfile b/Gemfile index 4ccba12..b4a6805 100644 --- a/Gemfile +++ b/Gemfile @@ -15,6 +15,7 @@ gem 'rails', '~> 6.0' gem 'redis-rails', '~> 5.0' gem 'responders', '~> 3.0' gem 'sidekiq', '~> 6.0' +gem 'simple_form', '~> 5.0' gem 'validates_email_format_of', '~> 1.6' gem 'webpacker', '~> 4.2' @@ -25,7 +26,7 @@ gem 'devise', '~> 4.7' # styles gem 'bulma-rails', '~> 0.8.0' -gem 'foundation_emails', '~> 2.2' +gem 'premailer-rails', '~> 1.11' group :development, :test do gem 'factory_bot_rails', '~> 5.1' diff --git a/Gemfile.lock b/Gemfile.lock index fbe0002..5026ec4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -303,6 +303,9 @@ GEM rack (~> 2.0) rack-protection (>= 2.0.0) redis (>= 4.1.0) + simple_form (5.0.2) + actionpack (>= 5.0) + activemodel (>= 5.0) simplecov (0.18.5) docile (~> 1.1) simplecov-html (~> 0.11) @@ -370,6 +373,7 @@ DEPENDENCIES shoulda-callback-matchers (~> 1.1) shoulda-matchers (~> 3.1) sidekiq (~> 6.0) + simple_form (~> 5.0) simplecov (~> 0.16) spring spring-watcher-listen (~> 2.0) diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..037059d --- /dev/null +++ b/Procfile @@ -0,0 +1,4 @@ +web: bundle exec puma -C config/puma.rb +webpack: bin/webpack +worker: bundle exec sidekiq -C config/sidekiq.yml +release: bin/rake db:migrate diff --git a/README.md b/README.md index 044348d..eae4d0e 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ This repo is a designed to be a Dockerized Rails 6 template: - `bundle` - `yarn install --check-files` - `Find/replace all TODO` + - `docker-compose up --build` ### Dependencies diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 99e194d..661bf1d 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -13,3 +13,22 @@ */ @import "bulma"; // https://bulma.io/documentation/ +@import "./devise"; + +html { + background-image: radial-gradient(circle at 13% 47%, rgba(140, 140, 140,0.03) 0%, rgba(140, 140, 140,0.03) 25%,transparent 25%, transparent 100%),radial-gradient(circle at 28% 63%, rgba(143, 143, 143,0.03) 0%, rgba(143, 143, 143,0.03) 16%,transparent 16%, transparent 100%),radial-gradient(circle at 81% 56%, rgba(65, 65, 65,0.03) 0%, rgba(65, 65, 65,0.03) 12%,transparent 12%, transparent 100%),radial-gradient(circle at 26% 48%, rgba(60, 60, 60,0.03) 0%, rgba(60, 60, 60,0.03) 6%,transparent 6%, transparent 100%),radial-gradient(circle at 97% 17%, rgba(150, 150, 150,0.03) 0%, rgba(150, 150, 150,0.03) 56%,transparent 56%, transparent 100%),radial-gradient(circle at 50% 100%, rgba(25, 25, 25,0.03) 0%, rgba(25, 25, 25,0.03) 36%,transparent 36%, transparent 100%),radial-gradient(circle at 55% 52%, rgba(69, 69, 69,0.03) 0%, rgba(69, 69, 69,0.03) 6%,transparent 6%, transparent 100%),linear-gradient(90deg, rgb(255,255,255),rgb(255,255,255)); + background-repeat: no-repeat; + background-size: cover; +} + +.toggleable { + display: none; + + &.is-active { + display: inherit; + } +} + +.notifications-container { + padding: $size-7; +} diff --git a/app/assets/stylesheets/devise.scss b/app/assets/stylesheets/devise.scss new file mode 100644 index 0000000..81eaaa9 --- /dev/null +++ b/app/assets/stylesheets/devise.scss @@ -0,0 +1,15 @@ +#registrations, #passwords { + padding-top: $size-1; +} + +#registrations-column { + background-color: $white; + padding: $size-6; +} + +#registrations-column-form, #registrations-column-form-submit-button, +#registration-edit-account-deletion-container, #registrations-edit-passwords, +#registrations-edit-update-password, #passwords-column-form, #unlocks-column-form, +#confirmations-column-form { + padding: $size-3; +} diff --git a/app/assets/stylesheets/mailer.scss b/app/assets/stylesheets/mailer.scss new file mode 100644 index 0000000..384554f --- /dev/null +++ b/app/assets/stylesheets/mailer.scss @@ -0,0 +1,18 @@ +@import "bulma"; + +body { + background-color: $grey-light; +} + +.email-main-container { + padding: $size-3; + background-color: $white; +} + +.email-details { + padding: $size-1 $size-5 ; +} + +.email-action-button-container { + padding: $size-1; +} diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 93e99b4..2eb6f8e 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -8,7 +8,7 @@ class ApplicationController < ActionController::Base authenticate_user! return if current_user.admin? - redirect_to root_path, flash: { alert: 'You are not allowed to do that.' } + redirect_to root_path, flash: { alert: "Whoops! We don't know where that path goes ¯\\_(ツ)_/¯" } end protected diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 15b06f0..e416307 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,4 +1,27 @@ # frozen_string_literal: true module ApplicationHelper + # Javascript Pack helper for controller-based JS + def javascript_controller_pack_tag_helper + javascript_pack_tag params[:controller] + rescue Webpacker::Manifest::MissingEntryError + begin + # Fallback retry for nested controllers + namespace = params[:controller].split('/').first + javascript_pack_tag namespace + rescue StandardError + nil + end + end + + def notification_type(name) + case name.to_sym + when :notice + 'info' + when :alert + 'danger' + else + name + end + end end diff --git a/app/javascript/controllers/application.js b/app/javascript/controllers/application.js deleted file mode 100644 index e69de29..0000000 diff --git a/app/javascript/controllers/home.js b/app/javascript/controllers/home.js deleted file mode 100644 index e69de29..0000000 diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js index c7264c9..75fb5c6 100644 --- a/app/javascript/packs/application.js +++ b/app/javascript/packs/application.js @@ -4,8 +4,10 @@ // that code so it'll be compiled. require("@rails/ujs").start() -require("turbolinks").start() +// require("turbolinks").start() require("channels") +require("./bulma/base") +require("jquery") // Uncomment to copy all static images under ../images to the output folder and reference // them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>) diff --git a/app/javascript/packs/bulma/base.js b/app/javascript/packs/bulma/base.js new file mode 100644 index 0000000..b03acca --- /dev/null +++ b/app/javascript/packs/bulma/base.js @@ -0,0 +1 @@ +require("./notification") diff --git a/app/javascript/packs/bulma/notification.js b/app/javascript/packs/bulma/notification.js new file mode 100644 index 0000000..9804c1e --- /dev/null +++ b/app/javascript/packs/bulma/notification.js @@ -0,0 +1,16 @@ +// https://bulma.io/documentation/elements/notification/#javascript-example +// document.addEventListener('DOMContentLoaded', () => { +// (document.querySelectorAll('.notification .delete') || []).forEach(($delete) => { +// $notification = $delete.parentNode; +// +// $delete.addEventListener('click', () => { +// $notification.parentNode.removeChild($notification); +// }); +// }); +// }); + +$(function(){ + $('.notification .delete').on('click', function(){ + $(this).parent().hide(); + }); +}); diff --git a/app/javascript/packs/devise.js b/app/javascript/packs/devise.js new file mode 100644 index 0000000..34f91a2 --- /dev/null +++ b/app/javascript/packs/devise.js @@ -0,0 +1,11 @@ +$(function() { + $('#registration-edit-password-button').on('click', function(){ + $('#registrations-edit-update-password').toggleClass('is-active'); + return false; + }); + + $('#registration-edit-account-delete-button').on('click', function(){ + $('#registration-edit-account-delete').toggleClass('is-active'); + return false; + }); +}); diff --git a/app/mailers/bulma_devise_mailer.rb b/app/mailers/bulma_devise_mailer.rb new file mode 100644 index 0000000..3d72fe6 --- /dev/null +++ b/app/mailers/bulma_devise_mailer.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +class BulmaDeviseMailer < Devise::Mailer + default from: App::Config::DEFAULT_EMAIL + layout 'mailer' +end diff --git a/app/models/user.rb b/app/models/user.rb index b5048f2..fde03d8 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -3,10 +3,23 @@ class User < ApplicationRecord acts_as_paranoid + before + # Include default devise modules. Others available are: # :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable, :confirmable, :lockable, :timeoutable, :trackable + validates :username, uniqueness: true validates :email, presence: true, email_format: { message: 'format is not valid' } + + before_validation :set_username, on: :create + + private + + def set_username + return if username.present? + + self.username = Digest::MD5.hexdigest(Time.now.to_f.to_s + email) + end end diff --git a/app/views/devise/confirmations/new.html.erb b/app/views/devise/confirmations/new.html.erb new file mode 100644 index 0000000..6990656 --- /dev/null +++ b/app/views/devise/confirmations/new.html.erb @@ -0,0 +1,46 @@ +
+
+
+
+
+
+

+ Resend Confirmation Email +

+
+
+
+ +
+ <%= simple_form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %> +
+ <%= f.label :email, class: "label" %> + +

+ <%= f.input_field :email, + required: true, + autofocus: true, + autocomplete: "email", + value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email), + class: "input" %> + + + + +

+ + <%= f.full_error :email, class: "help is-danger" %> +
+ +
+

+ <%= f.button :submit, "Resend confirmation", class: "button is-primary is-fullwidth is-rounded" %> +

+
+ <% end %> + + <%= render "devise/shared/links" %> +
+
+
+
diff --git a/app/views/devise/mailer/confirmation_instructions.html.erb b/app/views/devise/mailer/confirmation_instructions.html.erb new file mode 100644 index 0000000..431eaa7 --- /dev/null +++ b/app/views/devise/mailer/confirmation_instructions.html.erb @@ -0,0 +1,25 @@ +
+
+
+

+ Account Confirmation +

+
+
+
+ +
+
+
+ +
+
+
diff --git a/app/views/devise/mailer/email_changed.html.erb b/app/views/devise/mailer/email_changed.html.erb new file mode 100644 index 0000000..0a25f0c --- /dev/null +++ b/app/views/devise/mailer/email_changed.html.erb @@ -0,0 +1,28 @@ +
+
+
+

+ Account Email Updated +

+
+
+
+ +
+
+
+ +
+
+
diff --git a/app/views/devise/mailer/password_change.html.erb b/app/views/devise/mailer/password_change.html.erb new file mode 100644 index 0000000..c3f78e3 --- /dev/null +++ b/app/views/devise/mailer/password_change.html.erb @@ -0,0 +1,26 @@ +
+
+
+

+ Account Password Updated +

+
+
+
+ +
+
+
+ +
+
+
diff --git a/app/views/devise/mailer/reset_password_instructions.html.erb b/app/views/devise/mailer/reset_password_instructions.html.erb new file mode 100644 index 0000000..9b06926 --- /dev/null +++ b/app/views/devise/mailer/reset_password_instructions.html.erb @@ -0,0 +1,26 @@ +
+
+
+

+ Reset Password +

+
+
+
+ +
+
+
+ +
+
+
diff --git a/app/views/devise/mailer/unlock_instructions.html.erb b/app/views/devise/mailer/unlock_instructions.html.erb new file mode 100644 index 0000000..a27cda6 --- /dev/null +++ b/app/views/devise/mailer/unlock_instructions.html.erb @@ -0,0 +1,25 @@ +
+
+
+

+ Account Unlock +

+
+
+
+ +
+
+
+ +
+
+
diff --git a/app/views/devise/passwords/edit.html.erb b/app/views/devise/passwords/edit.html.erb new file mode 100644 index 0000000..b8346ca --- /dev/null +++ b/app/views/devise/passwords/edit.html.erb @@ -0,0 +1,66 @@ +
+
+
+
+
+
+

+ Update Password +

+
+
+
+ +
+ <%= simple_form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| %> + <%= f.input :reset_password_token, as: :hidden %> + <%= f.full_error :reset_password_token %> + +
+ <%= f.label :password, class: "label" %> + +

+ <%= f.input_field :password, + required: true, + autofocus: true, + autocomplete: "new-password", + hint: ("#{@minimum_password_length} characters minimum"), + class: "input" %> + + + + +

+ + <%= f.full_error :password, class: "help is-danger" %> +
+ +
+ <%= f.label :password_confirmation, class: "label" %> + +

+ <%= f.input_field :password_confirmation, + required: true, + autocomplete: "new-password", + class: "input" %> + + + + +

+ + <%= f.full_error :password_confirmation, class: "help is-danger" %> +
+ +
+

+ <%= f.button :submit, "Update password", class: "button is-primary is-fullwidth is-rounded" %> +

+
+ <% end %> + + <%= render "devise/shared/links" %> +
+
+
+
diff --git a/app/views/devise/passwords/new.html.erb b/app/views/devise/passwords/new.html.erb new file mode 100644 index 0000000..c91fbc2 --- /dev/null +++ b/app/views/devise/passwords/new.html.erb @@ -0,0 +1,45 @@ +
+
+
+
+
+
+

+ Reset My Password +

+
+
+
+ +
+ <%= simple_form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %> +
+ <%= f.label :email, class: "label" %> + +

+ <%= f.input_field :email, + required: true, + autofocus: true, + autocomplete: "email", + class: "input" %> + + + + +

+ + <%= f.full_error :email, class: "help is-danger" %> +
+ +
+

+ <%= f.button :submit, "Reset password", class: "button is-primary is-fullwidth is-rounded" %> +

+
+ <% end %> + + <%= render "devise/shared/links" %> +
+
+
+
diff --git a/app/views/devise/registrations/edit.html.erb b/app/views/devise/registrations/edit.html.erb new file mode 100644 index 0000000..c953711 --- /dev/null +++ b/app/views/devise/registrations/edit.html.erb @@ -0,0 +1,124 @@ +
+
+
+
+
+
+

+ Edit Account +

+
+
+
+ +
+ <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %> +
+ + + Account confirmation pending for <%= resource.unconfirmed_email %> +
+ <% end %> + + <%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %> +
+ <%= f.label :email, class: "label" %> + +

+ <%= f.input_field :email, required: true, autofocus: true, autocomplete: "email", class: "input" %> + + + + +

+ + <%= f.full_error :email, class: "help is-danger" %> +
+ +
+ <%= link_to "Change password", "#", id: "registration-edit-password-button", class: "button is-fullwidth is-rounded" %> + +
+
+
+ <%= f.label :password, class: "label" %> + +

+ <%= f.input_field :password, required: false, autocomplete: "new-password", class: "input" %> + + + + +

+ + <%= f.hint "Leave blank to not change password", class: "help" %> + <%= f.full_error :password, class: "help is-danger" %> +
+ +
+ <%= f.label :password_confirmation, class: "label" %> + +

+ <%= f.input_field :password_confirmation, required: false, autocomplete: "new-password", class: "input" %> + + + + +

+ + <%= f.full_error :password_confirmation, class: "help is-danger" %> +
+
+
+
+ +
+ <%= f.label :current_password, class: "label" %> + +

+ <%= f.input_field :current_password, required: true, autocomplete: "current-password", class: "input" %> + + + + +

+ + <%= f.hint "Password confirmation needed for changes", class: "help" %> + <%= f.full_error :current_password, class: "help is-danger" %> +
+ +
+

+ <%= f.button :submit, "Update Account", class: "button is-primary is-fullwidth is-rounded" %> +

+
+ <% end %> +
+ + +
+
+ <%= link_to "Back", :back, class: "button is-primary is-fullwidth is-rounded is-light" %> +
+ +
+ <%= link_to "Close my account", "#registration-edit-account-delete", id: "registration-edit-account-delete-button", class: "button is-danger is-fullwidth is-rounded is-light" %> +
+
+ +
+
+
+ Warning! Account deletion is permanant and can not be recovered. + +
+ <%= link_to "Delete My Account", registration_path(resource_name), + data: { confirm: "Are you sure?" }, method: :delete, + class: "button is-danger is-two-thirds is-rounded" %> +
+
+
+
+
+
+
diff --git a/app/views/devise/registrations/new.html.erb b/app/views/devise/registrations/new.html.erb new file mode 100644 index 0000000..5a35240 --- /dev/null +++ b/app/views/devise/registrations/new.html.erb @@ -0,0 +1,71 @@ +
+
+
+
+
+
+

+ Sign up +

+
+
+
+ +
+ <%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> +
+ <%= f.label :email, class: "label" %> + +

+ <%= f.input_field :email, required: true, autofocus: true, autocomplete: "email", class: "input" %> + + + + +

+ + <%= f.full_error :email, class: "help is-danger" %> +
+ +
+ <%= f.label :password, class: "label" %> + +

+ <%= f.input_field :password, required: true, + hint: ("#{@minimum_password_length} characters minimum" if @minimum_password_length), + autocomplete: "new-password", class: "input" %> + + + + +

+ + <%= f.full_error :password, class: "help is-danger" %> +
+ +
+ <%= f.label :password_confirmation, class: "label" %> + +

+ <%= f.input_field :password_confirmation, required: true, autocomplete: "new-password", class: "input" %> + + + + +

+ + <%= f.full_error :password_confirmation, class: "help is-danger" %> +
+ +
+

+ <%= f.button :submit, "Sign up", class: "button is-primary is-fullwidth is-rounded" %> +

+
+ <% end %> + + <%= render "devise/shared/links" %> +
+
+
+
diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb new file mode 100644 index 0000000..bede0bb --- /dev/null +++ b/app/views/devise/sessions/new.html.erb @@ -0,0 +1,58 @@ +
+
+
+
+
+
+

+ Log in <%= resource_name %> +

+
+
+
+ +
+ <%= simple_form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %> +
+ <%= f.label :email, class: "label" %> + +

+ <%= f.input_field :email, required: true, autofocus: true, autocomplete: "email", class: "input" %> + + + + +

+ + <%= f.full_error :email, class: "help is-danger" %> +
+ +
+ <%= f.label :password, class: "label" %> + +

+ <%= f.input_field :password, required: true, autocomplete: "current-password", class: "input" %> + + + + +

+ + <%= f.full_error :password, class: "help is-danger" %> +
+ + <%= f.check_box :remember_me, as: :boolean, class: "checkbox" %> + <%= f.label :remember_me, class: "checkbox" %> + +
+

+ <%= f.button :submit, "Sign in", class: "button is-primary is-fullwidth is-rounded" %> +

+
+ <% end %> + + <%= render "devise/shared/links" %> +
+
+
+
diff --git a/app/views/devise/shared/_error_messages.html.erb b/app/views/devise/shared/_error_messages.html.erb new file mode 100644 index 0000000..4df4080 --- /dev/null +++ b/app/views/devise/shared/_error_messages.html.erb @@ -0,0 +1,12 @@ +<% if resource.errors.any? %> +
+

+ <%= I18n.t("errors.messages.not_saved", count: resource.errors.count, resource: resource.class.model_name.human.downcase) %> +

+ +
+<% end %> diff --git a/app/views/devise/shared/_links.html.erb b/app/views/devise/shared/_links.html.erb new file mode 100644 index 0000000..51ee7c4 --- /dev/null +++ b/app/views/devise/shared/_links.html.erb @@ -0,0 +1,39 @@ +
+ <% if controller_name != 'sessions' %> +
+ <%= link_to "Log in", new_session_path(resource_name) %> +
+ <% end %> + + <% if devise_mapping.registerable? && controller_name != 'registrations' %> +
+ <%= link_to "Sign up", new_registration_path(resource_name) %> +
+ <% end %> + + <% if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %> +
+ <%= link_to "Password Recovery", new_password_path(resource_name) %> +
+ <% end %> + + <% if devise_mapping.confirmable? && controller_name != 'confirmations' %> +
+ <%= link_to "Confirm Account", new_confirmation_path(resource_name) %> +
+ <% end %> + + <% if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %> +
+ <%= link_to "Unlock Account", new_unlock_path(resource_name) %> +
+ <% end %> + + <% if devise_mapping.omniauthable? %> + <% resource_class.omniauth_providers.each do |provider| %> +
+ <%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider) %> +
+ <% end %> + <% end %> +
diff --git a/app/views/devise/unlocks/new.html.erb b/app/views/devise/unlocks/new.html.erb new file mode 100644 index 0000000..d1dcb9e --- /dev/null +++ b/app/views/devise/unlocks/new.html.erb @@ -0,0 +1,45 @@ +
+
+
+
+
+
+

+ Account Unlock +

+
+
+
+ +
+ <%= simple_form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| %> +
+ <%= f.label :email, class: "label" %> + +

+ <%= f.input_field :email, + required: true, + autofocus: true, + autocomplete: "email", + class: "input" %> + + + + +

+ + <%= f.full_error :email, class: "help is-danger" %> +
+ +
+

+ <%= f.button :submit, "Send unlock instructions", class: "button is-primary is-fullwidth is-rounded" %> +

+
+ <% end %> + + <%= render "devise/shared/links" %> +
+
+
+
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 9786a7c..4539283 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -12,12 +12,14 @@ -

<%= notice %>

-

<%= alert %>

+ <%= render "shared/notifications" %> <%= yield %> + + <%= render "shared/developer_view" %> <%= javascript_pack_tag 'application' %> + <%= javascript_controller_pack_tag_helper %> diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb index cbd34d2..423f274 100644 --- a/app/views/layouts/mailer.html.erb +++ b/app/views/layouts/mailer.html.erb @@ -1,13 +1,22 @@ - - + + + + + <%= stylesheet_link_tag :mailer, media: "all" %> - <%= yield %> +
+
+
+
+ <%= yield %> +
+
+
+
diff --git a/app/views/shared/_developer_view.html.erb b/app/views/shared/_developer_view.html.erb new file mode 100644 index 0000000..859807d --- /dev/null +++ b/app/views/shared/_developer_view.html.erb @@ -0,0 +1,25 @@ +<% if Rails.env.development? %> +
+
+
+
+
+

Developer Pane

+
+
+ <% params.each do |key, value| %> +
+
+ <%= key %> +
+
+ <%= value %> +
+
+ <% end %> +
+
+
+
+
+<% end %> diff --git a/app/views/shared/_notifications.html.erb b/app/views/shared/_notifications.html.erb new file mode 100644 index 0000000..c81ead1 --- /dev/null +++ b/app/views/shared/_notifications.html.erb @@ -0,0 +1,13 @@ +
+
+
+ <% flash.each do |name, msg| %> + <%= content_tag :div, msg, class: "notification app-notifications is-#{notification_type(name)}" do %> + + + <%= msg %> + <% end %> + <% end %> +
+
+
diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb index a9b0d0f..8792f03 100644 --- a/config/initializers/assets.rb +++ b/config/initializers/assets.rb @@ -14,3 +14,4 @@ Rails.application.config.assets.paths << Rails.root.join('node_modules') # application.js, application.css, and all non-JS/CSS in the app/assets # folder are already added. # Rails.application.config.assets.precompile += %w( admin.js admin.css ) +Rails.application.config.assets.precompile += %w[mailer.css] diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 17ef9eb..999f510 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -18,10 +18,10 @@ Devise.setup do |config| # Configure the e-mail address which will be shown in Devise::Mailer, # note that it will be overwritten if you use your own mailer class # with default "from" parameter. - config.mailer_sender = 'please-change-me-at-config-initializers-devise@example.com' + # config.mailer_sender = 'please-change-me-at-config-initializers-devise@example.com' # Configure the class responsible to send e-mails. - # config.mailer = 'Devise::Mailer' + config.mailer = 'BulmaDeviseMailer' # Configure the parent class responsible to send e-mails. # config.parent_mailer = 'ActionMailer::Base' diff --git a/config/initializers/premailer_rails.rb b/config/initializers/premailer_rails.rb new file mode 100644 index 0000000..a37f6da --- /dev/null +++ b/config/initializers/premailer_rails.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +Premailer::Rails.config.merge!(preserve_styles: true, remove_ids: true) diff --git a/config/initializers/simple_form.rb b/config/initializers/simple_form.rb new file mode 100644 index 0000000..4c11d27 --- /dev/null +++ b/config/initializers/simple_form.rb @@ -0,0 +1,177 @@ +# frozen_string_literal: true + +# +# Uncomment this and change the path if necessary to include your own +# components. +# See https://github.com/heartcombo/simple_form#custom-components to know +# more about custom components. +# Dir[Rails.root.join('lib/components/**/*.rb')].each { |f| require f } +# +# Use this setup block to configure all options available in SimpleForm. +SimpleForm.setup do |config| + # Wrappers are used by the form builder to generate a + # complete input. You can remove any component from the + # wrapper, change the order or even add your own to the + # stack. The options given below are used to wrap the + # whole input. + config.wrappers :default, class: :input, + hint_class: :field_with_hint, error_class: :field_with_errors, valid_class: :field_without_errors do |b| + ## Extensions enabled by default + # Any of these extensions can be disabled for a + # given input by passing: `f.input EXTENSION_NAME => false`. + # You can make any of these extensions optional by + # renaming `b.use` to `b.optional`. + + # Determines whether to use HTML5 (:email, :url, ...) + # and required attributes + b.use :html5 + + # Calculates placeholders automatically from I18n + # You can also pass a string as f.input placeholder: "Placeholder" + b.use :placeholder + + ## Optional extensions + # They are disabled unless you pass `f.input EXTENSION_NAME => true` + # to the input. If so, they will retrieve the values from the model + # if any exists. If you want to enable any of those + # extensions by default, you can change `b.optional` to `b.use`. + + # Calculates maxlength from length validations for string inputs + # and/or database column lengths + b.optional :maxlength + + # Calculate minlength from length validations for string inputs + b.optional :minlength + + # Calculates pattern from format validations for string inputs + b.optional :pattern + + # Calculates min and max from length validations for numeric inputs + b.optional :min_max + + # Calculates readonly automatically from readonly attributes + b.optional :readonly + + ## Inputs + # b.use :input, class: 'input', error_class: 'is-invalid', valid_class: 'is-valid' + b.use :label_input + b.use :hint, wrap_with: { tag: :span, class: :hint } + b.use :error, wrap_with: { tag: :span, class: :error } + + ## full_messages_for + # If you want to display the full error message for the attribute, you can + # use the component :full_error, like: + # + # b.use :full_error, wrap_with: { tag: :span, class: :error } + end + + # The default wrapper to be used by the FormBuilder. + config.default_wrapper = :default + + # Define the way to render check boxes / radio buttons with labels. + # Defaults to :nested for bootstrap config. + # inline: input + label + # nested: label > input + config.boolean_style = :nested + + # Default class for buttons + config.button_class = 'button' + + # Method used to tidy up errors. Specify any Rails Array method. + # :first lists the first message for each field. + # Use :to_sentence to list all errors for each field. + # config.error_method = :first + + # Default tag used for error notification helper. + config.error_notification_tag = :div + + # CSS class to add for error notification helper. + config.error_notification_class = 'error_notification' + + # Series of attempts to detect a default label method for collection. + # config.collection_label_methods = [ :to_label, :name, :title, :to_s ] + + # Series of attempts to detect a default value method for collection. + # config.collection_value_methods = [ :id, :to_s ] + + # You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none. + # config.collection_wrapper_tag = nil + + # You can define the class to use on all collection wrappers. Defaulting to none. + # config.collection_wrapper_class = nil + + # You can wrap each item in a collection of radio/check boxes with a tag, + # defaulting to :span. + # config.item_wrapper_tag = :span + + # You can define a class to use in all item wrappers. Defaulting to none. + # config.item_wrapper_class = nil + + # How the label text should be generated altogether with the required text. + # config.label_text = lambda { |label, required, explicit_label| "#{required} #{label}" } + + # You can define the class to use on all labels. Default is nil. + # config.label_class = nil + + # You can define the default class to be used on forms. Can be overriden + # with `html: { :class }`. Defaulting to none. + # config.default_form_class = nil + + # You can define which elements should obtain additional classes + # config.generate_additional_classes_for = [:wrapper, :label, :input] + + # Whether attributes are required by default (or not). Default is true. + # config.required_by_default = true + + # Tell browsers whether to use the native HTML5 validations (novalidate form option). + # These validations are enabled in SimpleForm's internal config but disabled by default + # in this configuration, which is recommended due to some quirks from different browsers. + # To stop SimpleForm from generating the novalidate option, enabling the HTML5 validations, + # change this configuration to true. + config.browser_validations = false + + # Custom mappings for input types. This should be a hash containing a regexp + # to match as key, and the input type that will be used when the field name + # matches the regexp as value. + # config.input_mappings = { /count/ => :integer } + + # Custom wrappers for input types. This should be a hash containing an input + # type as key and the wrapper that will be used for all inputs with specified type. + # config.wrapper_mappings = { string: :prepend } + + # Namespaces where SimpleForm should look for custom input classes that + # override default inputs. + # config.custom_inputs_namespaces << "CustomInputs" + + # Default priority for time_zone inputs. + # config.time_zone_priority = nil + + # Default priority for country inputs. + # config.country_priority = nil + + # When false, do not use translations for labels. + # config.translate_labels = true + + # Automatically discover new inputs in Rails' autoload path. + # config.inputs_discovery = true + + # Cache SimpleForm inputs discovery + # config.cache_discovery = !Rails.env.development? + + # Default class for inputs + # config.input_class = nil + + # Define the default class of the input wrapper of the boolean input. + config.boolean_label_class = 'checkbox' + + # Defines if the default input wrapper class should be included in radio + # collection wrappers. + # config.include_default_input_wrapper_class = true + + # Defines which i18n scope will be used in Simple Form. + # config.i18n_scope = 'simple_form' + + # Defines validation classes to the input_field. By default it's nil. + config.input_field_valid_class = 'is-success' + config.input_field_error_class = 'is-danger' +end diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml new file mode 100644 index 0000000..2374383 --- /dev/null +++ b/config/locales/simple_form.en.yml @@ -0,0 +1,31 @@ +en: + simple_form: + "yes": 'Yes' + "no": 'No' + required: + text: 'required' + mark: '*' + # You can uncomment the line below if you need to overwrite the whole required html. + # When using html, text and mark won't be used. + # html: '*' + error_notification: + default_message: "Please review the problems below:" + # Examples + # labels: + # defaults: + # password: 'Password' + # user: + # new: + # email: 'E-mail to sign in.' + # edit: + # email: 'E-mail.' + # hints: + # defaults: + # username: 'User name to sign in.' + # password: 'No special characters, please.' + # include_blanks: + # defaults: + # age: 'Rather not say' + # prompts: + # defaults: + # age: 'Select your age' diff --git a/config/webpack/environment.js b/config/webpack/environment.js index d16d9af..4acbfff 100644 --- a/config/webpack/environment.js +++ b/config/webpack/environment.js @@ -1,3 +1,11 @@ const { environment } = require('@rails/webpacker') +const webpack = require('webpack') + +environment.plugins.prepend('Provide', + new webpack.ProvidePlugin({ + $: 'jquery/src/jquery', + jQuery: 'jquery/src/jquery' + }) +) module.exports = environment diff --git a/config/webpacker.yml b/config/webpacker.yml index e3b0205..ee58518 100644 --- a/config/webpacker.yml +++ b/config/webpacker.yml @@ -50,7 +50,7 @@ default: &default development: <<: *default - compile: true + compile: false # Verifies that correct packages and versions are installed by inspecting package.json, yarn.lock, and node_modules # check_yarn_integrity: true @@ -65,6 +65,7 @@ development: # Non-docker: localhost:3035 public: webpacker:3035 hmr: false + # hmr: true # Inline should be set to true if using HMR inline: true overlay: true @@ -76,6 +77,7 @@ development: headers: 'Access-Control-Allow-Origin': '*' watch_options: + poll: true ignored: '**/node_modules/**' diff --git a/docker-compose.yml b/docker-compose.yml index 0b3a415..515e0e3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,16 +13,16 @@ services: POSTGRES_PASSWORD: "password" ports: - "5432:5432" - # volumes: - # - "postgres:/var/lib/postgresql/data" + volumes: + - /usr/local/var/postgres/data:/var/lib/postgresql/data redis: image: redis:5.0-alpine command: redis-server expose: - "6379" - # volumes: - # - "redis:/var/lib/redis/data" + volumes: + - /usr/local/var/redis/data:/var/lib/redis/data healthcheck: test: "redis-cli ping" interval: 5s @@ -42,6 +42,8 @@ services: webpacker: build: . + environment: + - WEBPACKER_DEV_SERVER_HOST=0.0.0.0 env_file: - '.env.docker' command: ./bin/webpack-dev-server @@ -67,8 +69,3 @@ services: tty: true env_file: - '.env.docker' - - -# volumes: - # redis: - # postgres: diff --git a/lib/templates/erb/scaffold/_form.html.erb b/lib/templates/erb/scaffold/_form.html.erb new file mode 100644 index 0000000..106b71e --- /dev/null +++ b/lib/templates/erb/scaffold/_form.html.erb @@ -0,0 +1,15 @@ +<%# frozen_string_literal: true %> +<%%= simple_form_for(@<%= singular_table_name %>) do |f| %> + <%%= f.error_notification %> + <%%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %> + +
+ <%- attributes.each do |attribute| -%> + <%%= f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %> %> + <%- end -%> +
+ +
+ <%%= f.button :submit %> +
+<%% end %> diff --git a/package.json b/package.json index ba14e3a..763f547 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "@rails/actioncable": "^6.0.0", "@rails/ujs": "^6.0.0", "@rails/webpacker": "4.2.2", + "jquery": "^3.4.1", "stimulus": "^1.1.1", "turbolinks": "^5.2.0" }, diff --git a/public/404.html b/public/404.html index 2be3af2..87a899e 100644 --- a/public/404.html +++ b/public/404.html @@ -1,67 +1,36 @@ - - The page you were looking for doesn't exist (404) - - - - - - -
-
-

The page you were looking for doesn't exist.

-

You may have mistyped the address or the page may have moved.

+

+ Please contact support if the problem persists. +

+
+
-

If you are the application owner check the logs for more information.

- - + + + diff --git a/public/422.html b/public/422.html index c08eac0..9b63dcd 100644 --- a/public/422.html +++ b/public/422.html @@ -1,67 +1,32 @@ - - The change you wanted was rejected (422) - - - - - - -
-
-

The change you wanted was rejected.

-

Maybe you tried to change something you didn't have access to.

+

+ Whoops. That didn't work. Please contact support if problem continues. +

+
+
+ + + -

If you are the application owner check the logs for more information.

- - + + + diff --git a/public/500.html b/public/500.html index 78a030a..11605f4 100644 --- a/public/500.html +++ b/public/500.html @@ -1,66 +1,32 @@ - - We're sorry, but something went wrong (500) - - - - - - -
-
-

We're sorry, but something went wrong.

+

+ A system error occurred. Please contact support if problem continues. +

+
+
+ + + -

If you are the application owner check the logs for more information.

- - + + + diff --git a/yarn.lock b/yarn.lock index 2ebde2e..59fe2c4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3842,6 +3842,11 @@ jest-worker@^25.1.0: merge-stream "^2.0.0" supports-color "^7.0.0" +jquery@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.4.1.tgz#714f1f8d9dde4bdfa55764ba37ef214630d80ef2" + integrity sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw== + js-base64@^2.1.8: version "2.5.2" resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.2.tgz#313b6274dda718f714d00b3330bbae6e38e90209"