bullet_train 1.0.2 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/account/invitations_controller.rb +1 -144
- data/app/controllers/account/memberships_controller.rb +1 -130
- data/app/controllers/account/onboarding/user_details_controller.rb +1 -61
- data/app/controllers/account/onboarding/user_email_controller.rb +1 -63
- data/app/controllers/account/teams_controller.rb +1 -120
- data/app/controllers/account/users_controller.rb +1 -57
- data/app/controllers/concerns/account/invitations/controller_base.rb +150 -0
- data/app/controllers/concerns/account/memberships/controller_base.rb +136 -0
- data/app/controllers/concerns/account/onboarding/user_details/controller_base.rb +67 -0
- data/app/controllers/concerns/account/onboarding/user_email/controller_base.rb +69 -0
- data/app/controllers/concerns/account/teams/controller_base.rb +126 -0
- data/app/controllers/concerns/account/users/controller_base.rb +63 -0
- data/app/controllers/concerns/registrations/controller_base.rb +39 -0
- data/app/controllers/concerns/sessions/controller_base.rb +15 -0
- data/app/controllers/registrations_controller.rb +9 -0
- data/app/controllers/sessions_controller.rb +3 -0
- data/app/helpers/account/buttons_helper.rb +12 -0
- data/app/helpers/account/dates_helper.rb +38 -0
- data/app/helpers/account/forms_helper.rb +67 -0
- data/app/helpers/account/locale_helper.rb +51 -0
- data/app/helpers/account/markdown_helper.rb +5 -0
- data/app/helpers/account/role_helper.rb +5 -0
- data/app/helpers/attributes_helper.rb +32 -0
- data/app/helpers/email_helper.rb +7 -0
- data/app/helpers/images_helper.rb +7 -0
- data/app/mailers/concerns/mailers/base.rb +16 -0
- data/app/mailers/devise_mailer.rb +10 -0
- data/app/mailers/user_mailer.rb +24 -0
- data/app/models/concerns/{invitation.rb → invitations/base.rb} +2 -2
- data/app/models/concerns/{membership.rb → memberships/base.rb} +2 -2
- data/app/models/concerns/{team.rb → teams/base.rb} +2 -2
- data/app/models/concerns/{user.rb → users/base.rb} +2 -2
- data/app/models/invitations.rb +5 -0
- data/app/models/memberships.rb +5 -0
- data/app/models/teams.rb +5 -0
- data/app/models/users.rb +5 -0
- data/app/views/devise/confirmations/new.html.erb +16 -0
- data/app/views/devise/mailer/confirmation_instructions.html.erb +5 -0
- data/app/views/devise/mailer/password_change.html.erb +3 -0
- data/app/views/devise/mailer/reset_password_instructions.html.erb +30 -0
- data/app/views/devise/mailer/unlock_instructions.html.erb +7 -0
- data/app/views/devise/passwords/edit.html.erb +17 -0
- data/app/views/devise/passwords/new.html.erb +20 -0
- data/app/views/devise/registrations/_two_factor.html.erb +42 -0
- data/app/views/devise/registrations/edit.html.erb +43 -0
- data/app/views/devise/registrations/new.html.erb +30 -0
- data/app/views/devise/sessions/new.html.erb +59 -0
- data/app/views/devise/sessions/pre_otp.js.erb +11 -0
- data/app/views/devise/shared/_links.html.erb +21 -0
- data/app/views/devise/shared/_oauth.html.erb +9 -0
- data/app/views/devise/unlocks/new.html.erb +16 -0
- data/config/locales/en/devise.en.yml +110 -0
- data/config/routes.rb +40 -0
- data/lib/bullet_train/version.rb +1 -1
- metadata +48 -6
@@ -0,0 +1,38 @@
|
|
1
|
+
module Account::DatesHelper
|
2
|
+
# e.g. October 11, 2018
|
3
|
+
def display_date(timestamp)
|
4
|
+
return nil unless timestamp
|
5
|
+
if local_time(timestamp).year == local_time(Time.now).year
|
6
|
+
local_time(timestamp).strftime("%B %-d")
|
7
|
+
else
|
8
|
+
local_time(timestamp).strftime("%B %-d, %Y")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# e.g. October 11, 2018 at 4:22 PM
|
13
|
+
# e.g. Yesterday at 2:12 PM
|
14
|
+
# e.g. April 24 at 7:39 AM
|
15
|
+
def display_date_and_time(timestamp)
|
16
|
+
return nil unless timestamp
|
17
|
+
|
18
|
+
# today?
|
19
|
+
if local_time(timestamp).to_date == local_time(Time.now).to_date
|
20
|
+
"Today at #{display_time(timestamp)}"
|
21
|
+
# yesterday?
|
22
|
+
elsif (local_time(timestamp).to_date) == (local_time(Time.now).to_date - 1.day)
|
23
|
+
"Yesterday at #{display_time(timestamp)}"
|
24
|
+
else
|
25
|
+
"#{display_date(timestamp)} at #{display_time(timestamp)}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# e.g. 4:22 PM
|
30
|
+
def display_time(timestamp)
|
31
|
+
local_time(timestamp).strftime("%l:%M %p")
|
32
|
+
end
|
33
|
+
|
34
|
+
def local_time(time)
|
35
|
+
return time if current_user.time_zone.nil?
|
36
|
+
time.in_time_zone(current_user.time_zone)
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Account::FormsHelper
|
2
|
+
PRESENCE_VALIDATORS = [ActiveRecord::Validations::PresenceValidator, ActiveModel::Validations::PresenceValidator]
|
3
|
+
|
4
|
+
def presence_validated?(object, attribute)
|
5
|
+
validators = object.class.validators
|
6
|
+
validators.select! do |validator|
|
7
|
+
PRESENCE_VALIDATORS.include?(validator.class) && validator.attributes.include?(attribute)
|
8
|
+
end
|
9
|
+
validators.any?
|
10
|
+
end
|
11
|
+
|
12
|
+
def flush_content_for(name)
|
13
|
+
content_for name, flush: true do
|
14
|
+
""
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def options_with_labels(options, namespace)
|
19
|
+
hash = {}
|
20
|
+
options.each do |option|
|
21
|
+
hash[option] = t([namespace, option].join("."))
|
22
|
+
end
|
23
|
+
hash
|
24
|
+
end
|
25
|
+
|
26
|
+
def if_present(string)
|
27
|
+
string.present? ? string : nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def id_for(form, method)
|
31
|
+
[form.object.class.name, form.index, method].compact.join("_").underscore
|
32
|
+
end
|
33
|
+
|
34
|
+
def model_key(form)
|
35
|
+
form.object.class.name.pluralize.underscore
|
36
|
+
end
|
37
|
+
|
38
|
+
def labels_for(form, method)
|
39
|
+
keys = [:placeholder, :label, :help, :options_help]
|
40
|
+
path = [model_key(form), (current_fields_namespace || :fields), method].compact
|
41
|
+
Struct.new(*keys).new(*keys.map { |key| t((path + [key]).join("."), default: "").presence })
|
42
|
+
end
|
43
|
+
|
44
|
+
def options_for(form, method)
|
45
|
+
# e.g. "scaffolding/completely_concrete/tangible_things.fields.text_area_value.options"
|
46
|
+
path = [model_key(form), (current_fields_namespace || :fields), method, :options]
|
47
|
+
t(path.compact.join("."))
|
48
|
+
end
|
49
|
+
|
50
|
+
def legacy_label_for(form, method)
|
51
|
+
# e.g. 'scaffolding/things.labels.name'
|
52
|
+
key = "#{model_key(form)}.labels.#{method}"
|
53
|
+
# e.g. 'scaffolding/things.labels.name' or 'scaffolding.things.labels.name' or nil
|
54
|
+
t(key, default: "").presence || t(key.tr("/", "."), default: "").presence
|
55
|
+
end
|
56
|
+
|
57
|
+
def within_fields_namespace(namespace)
|
58
|
+
@fields_namespaces ||= []
|
59
|
+
@fields_namespaces << namespace
|
60
|
+
yield
|
61
|
+
@fields_namespaces.pop
|
62
|
+
end
|
63
|
+
|
64
|
+
def current_fields_namespace
|
65
|
+
@fields_namespaces&.last
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Account::LocaleHelper
|
2
|
+
def current_locale
|
3
|
+
current_user.locale || current_team.locale || "en"
|
4
|
+
end
|
5
|
+
|
6
|
+
# as of now, we only calculate a possessive version of nouns in english.
|
7
|
+
# if you're aware of another language where we can do this, please don't hesitate to reach out!
|
8
|
+
def possessive_string(string)
|
9
|
+
[:en].include?(I18n.locale) ? string.possessive : string
|
10
|
+
end
|
11
|
+
|
12
|
+
def model_locales(model)
|
13
|
+
name = model.label_string.presence
|
14
|
+
return {} unless name
|
15
|
+
|
16
|
+
hash = {}
|
17
|
+
prefix = model.class.name.split("::").last.underscore
|
18
|
+
hash[:"#{prefix}_name"] = name
|
19
|
+
hash[:"#{prefix.pluralize}_possessive"] = possessive_string(name)
|
20
|
+
|
21
|
+
hash
|
22
|
+
end
|
23
|
+
|
24
|
+
def models_locales(*models)
|
25
|
+
hash = {}
|
26
|
+
models.compact.each do |model|
|
27
|
+
hash.merge! model_locales(model)
|
28
|
+
end
|
29
|
+
hash
|
30
|
+
end
|
31
|
+
|
32
|
+
# this is a bit scary, no?
|
33
|
+
def account_controller?
|
34
|
+
controller.class.name.match(/^Account::/)
|
35
|
+
end
|
36
|
+
|
37
|
+
def t(key, options = {})
|
38
|
+
if account_controller?
|
39
|
+
# give preference to the options they've passed in.
|
40
|
+
options = models_locales(@child_object, @parent_object).merge(options)
|
41
|
+
end
|
42
|
+
super(key, options)
|
43
|
+
end
|
44
|
+
|
45
|
+
# like 't', but if the key isn't found, it returns nil.
|
46
|
+
def ot(key, options = {})
|
47
|
+
t(key, options)
|
48
|
+
rescue I18n::MissingTranslationData => _
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module AttributesHelper
|
2
|
+
def current_attributes_object
|
3
|
+
@_attributes_helper_objects ? @_attributes_helper_objects.last : nil
|
4
|
+
end
|
5
|
+
|
6
|
+
def current_attributes_strategy
|
7
|
+
@_attributes_helper_strategies ? @_attributes_helper_strategies.last : nil
|
8
|
+
end
|
9
|
+
|
10
|
+
def with_attribute_settings(options)
|
11
|
+
@_attributes_helper_objects ||= []
|
12
|
+
@_attributes_helper_strategies ||= []
|
13
|
+
|
14
|
+
if options[:object]
|
15
|
+
@_attributes_helper_objects << options[:object]
|
16
|
+
end
|
17
|
+
|
18
|
+
if options[:strategy]
|
19
|
+
@_attributes_helper_strategies << options[:strategy]
|
20
|
+
end
|
21
|
+
|
22
|
+
yield
|
23
|
+
|
24
|
+
if options[:strategy]
|
25
|
+
@_attributes_helper_strategies.pop
|
26
|
+
end
|
27
|
+
|
28
|
+
if options[:object]
|
29
|
+
@_attributes_helper_objects.pop
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
module EmailHelper
|
2
|
+
def email_image_tag(image, **options)
|
3
|
+
image_underscore = image.tr("-", "_")
|
4
|
+
attachments.inline[image_underscore] = File.read(Rails.root.join("app/javascript/images/#{image}"))
|
5
|
+
image_tag attachments.inline[image_underscore].url, **options
|
6
|
+
end
|
7
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Mailers::Base
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
default from: "#{I18n.t("application.name")} <#{I18n.t("application.support_email")}>"
|
6
|
+
layout "mailer"
|
7
|
+
|
8
|
+
helper :email
|
9
|
+
helper :application
|
10
|
+
helper :images
|
11
|
+
helper "account/teams"
|
12
|
+
helper "account/users"
|
13
|
+
helper "account/locale"
|
14
|
+
helper "fields/trix_editor"
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class UserMailer < ApplicationMailer
|
2
|
+
def welcome(user)
|
3
|
+
@user = user
|
4
|
+
@cta_url = account_dashboard_url
|
5
|
+
@values = {
|
6
|
+
# are there any substitution values you want to include?
|
7
|
+
}
|
8
|
+
mail(to: @user.email, subject: I18n.t("user_mailer.welcome.subject", **@values))
|
9
|
+
end
|
10
|
+
|
11
|
+
# technically not a 'user' email, but they'll be a user soon.
|
12
|
+
# didn't seem worth creating an entirely new mailer for.
|
13
|
+
def invited(uuid)
|
14
|
+
@invitation = Invitation.find_by_uuid uuid
|
15
|
+
return if @invitation.nil?
|
16
|
+
@cta_url = accept_account_invitation_url(@invitation.uuid)
|
17
|
+
@values = {
|
18
|
+
# Just in case the inviting user has been removed from the team...
|
19
|
+
inviter_name: @invitation.from_membership&.user&.full_name || @invitation.from_membership.name,
|
20
|
+
team_name: @invitation.team.name,
|
21
|
+
}
|
22
|
+
mail(to: @invitation.email, subject: I18n.t("user_mailer.invited.subject", **@values))
|
23
|
+
end
|
24
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
|
-
module Teams::
|
1
|
+
module Teams::Base
|
2
2
|
extend ActiveSupport::Concern
|
3
3
|
|
4
|
-
|
4
|
+
included do
|
5
5
|
# super scaffolding
|
6
6
|
unless scaffolding_things_disabled?
|
7
7
|
has_many :scaffolding_absolutely_abstract_creative_concepts, class_name: "Scaffolding::AbsolutelyAbstract::CreativeConcept", dependent: :destroy, enable_updates: true
|
@@ -1,7 +1,7 @@
|
|
1
|
-
module Users::
|
1
|
+
module Users::Base
|
2
2
|
extend ActiveSupport::Concern
|
3
3
|
|
4
|
-
|
4
|
+
included do
|
5
5
|
if two_factor_authentication_enabled?
|
6
6
|
devise :two_factor_authenticatable, :two_factor_backupable, :omniauthable,
|
7
7
|
:registerable, :recoverable, :rememberable, :trackable, :validatable,
|
data/app/models/teams.rb
ADDED
data/app/models/users.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
<h2><%= t('device.headers.resend_confirm') %></h2>
|
2
|
+
|
3
|
+
<%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %>
|
4
|
+
<%= devise_error_messages! %>
|
5
|
+
|
6
|
+
<div class="field">
|
7
|
+
<%= f.label :email %><br />
|
8
|
+
<%= f.email_field :email, autofocus: true, value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email) %>
|
9
|
+
</div>
|
10
|
+
|
11
|
+
<div class="actions">
|
12
|
+
<%= f.submit t('devise.buttons.resend_confirm') %>
|
13
|
+
</div>
|
14
|
+
<% end %>
|
15
|
+
|
16
|
+
<%= render "devise/shared/links" %>
|
@@ -0,0 +1,30 @@
|
|
1
|
+
<p><%= t('.hello', email: @resource.first_name || @resource.email) %></p>
|
2
|
+
|
3
|
+
<p><%= t('.requested_change') %></p>
|
4
|
+
|
5
|
+
<!-- Action -->
|
6
|
+
<table class="body-action" align="center" width="100%" cellpadding="0" cellspacing="0">
|
7
|
+
<tr>
|
8
|
+
<td align="center">
|
9
|
+
<!-- Border based button https://litmus.com/blog/a-guide-to-bulletproof-buttons-in-email-design -->
|
10
|
+
<table width="100%" border="0" cellspacing="0" cellpadding="0">
|
11
|
+
<tr>
|
12
|
+
<td align="center">
|
13
|
+
<table border="0" cellspacing="0" cellpadding="0">
|
14
|
+
<tr>
|
15
|
+
<td>
|
16
|
+
<%= link_to t('.change_password'), edit_password_url(@resource, reset_password_token: @token), class: 'button button--', target: '_blank' %>
|
17
|
+
</td>
|
18
|
+
</tr>
|
19
|
+
</table>
|
20
|
+
</td>
|
21
|
+
</tr>
|
22
|
+
</table>
|
23
|
+
</td>
|
24
|
+
</tr>
|
25
|
+
</table>
|
26
|
+
|
27
|
+
<p><%= t('.ignore') %></p>
|
28
|
+
<p><%= t('.access_change') %></p>
|
29
|
+
|
30
|
+
<%= t('user_mailer.signature.html', support_email: t('application.support_email')) %>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<% @title = t('devise.headers.change_password') %>
|
2
|
+
<%= render 'account/shared/workflow/box' do |p| %>
|
3
|
+
<% p.content_for :title, @title %>
|
4
|
+
<% p.content_for :body do %>
|
5
|
+
<% within_fields_namespace(:update_self) do %>
|
6
|
+
<%= form_for(resource, as: resource_name, url: password_path(resource_name), class: 'form', html: { method: :put }) do |f| %>
|
7
|
+
<%= f.hidden_field :reset_password_token %>
|
8
|
+
<%= render 'account/shared/forms/errors', form: f, attributes: [:reset_password_token] %>
|
9
|
+
<%= render 'shared/fields/password_field', form: f, method: :password, options: {autofocus: true, autocomplete: "off"} %>
|
10
|
+
<%= render 'shared/fields/password_field', form: f, method: :password_confirmation, options: {autocomplete: "off"} %>
|
11
|
+
<div class="buttons">
|
12
|
+
<%= f.submit t('devise.buttons.change_password'), class: "button" %>
|
13
|
+
</div>
|
14
|
+
<% end %>
|
15
|
+
<% end %>
|
16
|
+
<% end %>
|
17
|
+
<% end %>
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<%= render 'account/shared/workflow/box' do |p| %>
|
2
|
+
<% p.content_for :title, t('devise.titles.reset_password') %>
|
3
|
+
<% p.content_for :body do %>
|
4
|
+
<% within_fields_namespace(:sign_up) do %>
|
5
|
+
<%= form_for resource, as: resource_name, url: password_path(resource_name), html: {method: :post, class: 'form'} do |f| %>
|
6
|
+
<%= render 'account/shared/forms/errors', form: f %>
|
7
|
+
|
8
|
+
<%= render 'shared/fields/email_field', form: f, method: :email, options: {autofocus: true} do %>
|
9
|
+
<% if show_sign_up_options? %>
|
10
|
+
<% content_for :help do %>
|
11
|
+
<%= link_to t('devise.links.account'), new_user_registration_path %>
|
12
|
+
<% end %>
|
13
|
+
<% end %>
|
14
|
+
<% end %>
|
15
|
+
|
16
|
+
<%= f.submit t('devise.buttons.reset_password'), class: 'button full' %>
|
17
|
+
<% end %>
|
18
|
+
<% end %>
|
19
|
+
<% end %>
|
20
|
+
<% end %>
|
@@ -0,0 +1,42 @@
|
|
1
|
+
<%= render 'account/shared/box', divider: @backup_codes do |p| %>
|
2
|
+
<% p.content_for :title, t("users.edit.two_factor.header") %>
|
3
|
+
<% p.content_for :description, t("users.edit.two_factor.description_#{@user.otp_required_for_login? ? 'enabled' : 'disabled'}") %>
|
4
|
+
<% p.content_for :body do %>
|
5
|
+
<% if current_user.otp_required_for_login? %>
|
6
|
+
<% if @backup_codes %>
|
7
|
+
|
8
|
+
<%= render 'account/shared/alert' do %>
|
9
|
+
<%= t('users.edit.two_factor.warning').html_safe %>
|
10
|
+
<% end %>
|
11
|
+
|
12
|
+
<p><%= t('users.edit.two_factor.instructions').html_safe %></p>
|
13
|
+
|
14
|
+
<center class="py-4">
|
15
|
+
<%= current_user.otp_qr_code.as_svg(
|
16
|
+
offset: 0,
|
17
|
+
color: '000',
|
18
|
+
shape_rendering: 'crispEdges',
|
19
|
+
module_size: 4,
|
20
|
+
standalone: true
|
21
|
+
).html_safe %>
|
22
|
+
</center>
|
23
|
+
|
24
|
+
<p><%= t('users.edit.two_factor.recovery_codes').html_safe %></p>
|
25
|
+
|
26
|
+
<center>
|
27
|
+
<% @backup_codes.each do |code| %>
|
28
|
+
<p><code><%= code %></code></p>
|
29
|
+
<% end %>
|
30
|
+
</center>
|
31
|
+
|
32
|
+
<% end %>
|
33
|
+
<% end %>
|
34
|
+
<% end %>
|
35
|
+
<% p.content_for :actions do %>
|
36
|
+
<% if current_user.otp_required_for_login? %>
|
37
|
+
<%= link_to t('users.edit.two_factor.buttons.disable'), account_two_factor_path, method: :delete, remote: true, class: "button" %>
|
38
|
+
<% else %>
|
39
|
+
<%= link_to t('users.edit.two_factor.buttons.enable'), account_two_factor_path, method: :post, remote: true, class: "button" %>
|
40
|
+
<% end %>
|
41
|
+
<% end %>
|
42
|
+
<% end %>
|
@@ -0,0 +1,43 @@
|
|
1
|
+
<h2><%= t('devise.headers.edit_registration', resource_name: resource_name.to_s.humanize) %></h2>
|
2
|
+
|
3
|
+
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
|
4
|
+
<%= devise_error_messages! %>
|
5
|
+
|
6
|
+
<div class="field">
|
7
|
+
<%= f.label :email %><br />
|
8
|
+
<%= f.email_field :email, autofocus: true %>
|
9
|
+
</div>
|
10
|
+
|
11
|
+
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
|
12
|
+
<div><%= t('devise.labels.wait_confirm', unconfirmed_email: resource.unconfirmed_email) %></div>
|
13
|
+
<% end %>
|
14
|
+
|
15
|
+
<div class="field">
|
16
|
+
<%= f.label :password %> <i><%= t('devise.hints.leave_blank') %></i><br />
|
17
|
+
<%= f.password_field :password, autocomplete: "off" %>
|
18
|
+
<% if @minimum_password_length %>
|
19
|
+
<br />
|
20
|
+
<em><%= t('devise.hints.password_length', length: @minimum_password_length) %></em>
|
21
|
+
<% end %>
|
22
|
+
</div>
|
23
|
+
|
24
|
+
<div class="field">
|
25
|
+
<%= f.label :password_confirmation %><br />
|
26
|
+
<%= f.password_field :password_confirmation, autocomplete: "off" %>
|
27
|
+
</div>
|
28
|
+
|
29
|
+
<div class="field">
|
30
|
+
<%= f.label :current_password %> <i><%= t('devise.hints.need_password') %></i><br />
|
31
|
+
<%= f.password_field :current_password, autocomplete: "off" %>
|
32
|
+
</div>
|
33
|
+
|
34
|
+
<div class="actions">
|
35
|
+
<%= f.submit t('global.buttons.update') %>
|
36
|
+
</div>
|
37
|
+
<% end %>
|
38
|
+
|
39
|
+
<h3><%= t('devise.headers.cancel_account') %></h3>
|
40
|
+
|
41
|
+
<p>Unhappy? <%= button_to t('devise.buttons.cancel_account'), registration_path(resource_name), data: { confirm: t('global.confirm_message') }, method: :delete %></p>
|
42
|
+
|
43
|
+
<%= link_to t('global.buttons.back'), :back %>
|
@@ -0,0 +1,30 @@
|
|
1
|
+
<%= render 'account/shared/workflow/box' do |p| %>
|
2
|
+
<% p.content_for :title, t('devise.headers.create_account') %>
|
3
|
+
<% p.content_for :body do %>
|
4
|
+
<% within_fields_namespace(:sign_up) do %>
|
5
|
+
<%= form_for resource, as: resource_name, url: registration_path(resource_name), html: {class: 'form'} do |f| %>
|
6
|
+
<%= render 'account/shared/notices' %>
|
7
|
+
<%= render 'account/shared/forms/errors', form: f %>
|
8
|
+
|
9
|
+
<%= render 'shared/fields/email_field', form: f, method: :email, options: {autofocus: true} do %>
|
10
|
+
<% content_for :help do %>
|
11
|
+
<%= link_to t('devise.links.have_account'), new_user_session_path %>
|
12
|
+
<% end %>
|
13
|
+
<% end %>
|
14
|
+
|
15
|
+
<div class="grid grid-cols-2 gap-5">
|
16
|
+
<div>
|
17
|
+
<%= render 'shared/fields/password_field', form: f, method: :password %>
|
18
|
+
</div>
|
19
|
+
<div>
|
20
|
+
<%= render 'shared/fields/password_field', form: f, method: :password_confirmation, other_options: {error: f.object.errors.full_messages_for(:password).first, hide_custom_error: true} %>
|
21
|
+
</div>
|
22
|
+
</div>
|
23
|
+
|
24
|
+
<%= f.submit t('global.buttons.sign_up'), class: 'button full' %>
|
25
|
+
|
26
|
+
<%= render 'devise/shared/oauth', verb: 'Sign Up' %>
|
27
|
+
<% end %>
|
28
|
+
<% end %>
|
29
|
+
<% end %>
|
30
|
+
<% end %>
|
@@ -0,0 +1,59 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
<%= render 'account/shared/workflow/box' do |p| %>
|
4
|
+
<% p.content_for :title, t('devise.headers.sign_in') %>
|
5
|
+
<% p.content_for :body do %>
|
6
|
+
<% within_fields_namespace(:self) do %>
|
7
|
+
<%= form_for resource, as: resource_name, url: two_factor_authentication_enabled? ? users_pre_otp_path : session_path(resource_name), remote: two_factor_authentication_enabled?, html: {class: 'form'}, authenticity_token: true do |form| %>
|
8
|
+
<% with_field_settings form: form do %>
|
9
|
+
<%= render 'account/shared/notices', form: form %>
|
10
|
+
<%= render 'account/shared/forms/errors', form: form %>
|
11
|
+
|
12
|
+
<% email_field = capture do %>
|
13
|
+
<%= render 'shared/fields/email_field', method: :email, options: {autofocus: true} do %>
|
14
|
+
<% if show_sign_up_options? %>
|
15
|
+
<% content_for :help do %>
|
16
|
+
<%= link_to t('devise.links.account'), new_user_registration_path %>
|
17
|
+
<% end %>
|
18
|
+
<% end %>
|
19
|
+
<% end %>
|
20
|
+
<% end %>
|
21
|
+
|
22
|
+
<% if two_factor_authentication_enabled? %>
|
23
|
+
<div id="step-1" class="space-y">
|
24
|
+
<%= email_field %>
|
25
|
+
<%= form.submit t('global.buttons.next'), class: 'button full' %>
|
26
|
+
</div>
|
27
|
+
<% else %>
|
28
|
+
<%= email_field %>
|
29
|
+
<% end %>
|
30
|
+
|
31
|
+
<div id="step-2" class="<%= 'hidden' if two_factor_authentication_enabled? %> space-y">
|
32
|
+
<%= render 'shared/fields/password_field', method: :password do %>
|
33
|
+
<% content_for :help do %>
|
34
|
+
<%= link_to t('devise.links.forgot_password'), new_user_password_path %>
|
35
|
+
<% end %>
|
36
|
+
<% end %>
|
37
|
+
|
38
|
+
<% if two_factor_authentication_enabled? %>
|
39
|
+
<div id="step-2-otp" class="hidden">
|
40
|
+
<%= render 'shared/fields/text_field', method: :otp_attempt %>
|
41
|
+
</div>
|
42
|
+
<% end %>
|
43
|
+
|
44
|
+
<%= form.submit t('global.buttons.sign_in'), class: 'button full' %>
|
45
|
+
</div>
|
46
|
+
|
47
|
+
<div class="flex items-center">
|
48
|
+
<input id="remember_me" name="remember_me" type="checkbox" class="h-4 w-4 text-blue focus:ring-blue-dark border-gray-300 rounded">
|
49
|
+
<label for="remember_me" class="ml-2 block">
|
50
|
+
Remember me
|
51
|
+
</label>
|
52
|
+
</div>
|
53
|
+
<% end %>
|
54
|
+
<% end %>
|
55
|
+
<% end %>
|
56
|
+
|
57
|
+
<%= render 'devise/shared/oauth' %>
|
58
|
+
<% end %>
|
59
|
+
<% end %>
|