Compare commits
102 Commits
abandoneda
...
attempt2
Author | SHA1 | Date |
---|---|---|
|
f0d741cae3 | |
|
2103713552 | |
|
1460df687f | |
|
6d03d80a31 | |
|
bb9c354146 | |
|
b4cd83c2e7 | |
|
e7abc0fa50 | |
|
350ee25d7d | |
|
bdc5c406c7 | |
|
26a7821e11 | |
|
cbbe45c791 | |
|
867deebf20 | |
|
1d5646e61c | |
|
8343c3ae8a | |
|
65df59d3e6 | |
|
a2a9e1312b | |
|
0c7d31bac0 | |
|
cf759a4cc7 | |
|
84c0092701 | |
|
d0149a50e2 | |
|
e52a9da39c | |
|
12a9641ca7 | |
|
5d024f430a | |
|
c5e83e96b0 | |
|
1474feef98 | |
|
47c981cd57 | |
|
54ac6a05a3 | |
|
2360c8fa91 | |
|
67d435d12b | |
|
f154d713b2 | |
|
84136d6d3d | |
|
cf10a66220 | |
|
c1deea8463 | |
|
35d144327b | |
|
b375d289fe | |
|
d0081c9d11 | |
|
ea9d032ad4 | |
|
58f1d921c1 | |
|
6933ca7635 | |
|
944824f443 | |
|
de03804a8f | |
|
3f9358997b | |
|
85dd95b5e1 | |
|
1405b938cd | |
|
b598b345d5 | |
|
fedc2e67b7 | |
|
205fb7fbd6 | |
|
611dee5eb8 | |
|
1265d885ec | |
|
9066a968eb | |
|
dbc900a7f3 | |
|
405125df6c | |
|
778afeec08 | |
|
a5a732b9cd | |
|
12352ef69d | |
|
daa563f31a | |
|
ef63a37371 | |
|
bdfdf6942a | |
|
d8fe866b68 | |
|
66aaeb4ed6 | |
|
d5e19f561e | |
|
1656508ccd | |
|
97bde74af0 | |
|
aefe442be6 | |
|
e952763c3a | |
|
847921ba25 | |
|
8d59f7b788 | |
|
f474c91b8c | |
|
95dd6dca7e | |
|
38e4553e33 | |
|
b742c3bf78 | |
|
d817ae6992 | |
|
9c6f980ccb | |
|
97b4e89e7a | |
|
2c7c20ef33 | |
|
2830ace0d9 | |
|
52e0fbb211 | |
|
edb56c84ef | |
|
f0cf2b0c24 | |
|
335b37f4e2 | |
|
4e02d7259f | |
|
14902e00f0 | |
|
dad8abad3e | |
|
02d8612409 | |
|
2de94bd706 | |
|
9662776c73 | |
|
1fabc351cb | |
|
894aee9279 | |
|
e251dcd304 | |
|
4b31f8e6c9 | |
|
d5e588a0fe | |
|
796bb09b38 | |
|
9569ae50c6 | |
|
d4f7e64906 | |
|
d9873c0672 | |
|
294758c7b2 | |
|
3232d2fb94 | |
|
dd36c3eec1 | |
|
e68a9fc372 | |
|
ba8b547ab0 | |
|
39cad257c9 | |
|
5f26e94d1d |
|
@ -0,0 +1 @@
|
|||
defaults
|
|
@ -33,3 +33,10 @@
|
|||
|
||||
# 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
|
||||
|
|
10
Gemfile
10
Gemfile
|
@ -26,6 +26,16 @@ gem "stimulus-rails"
|
|||
# Build JSON APIs with ease [https://github.com/rails/jbuilder]
|
||||
gem "jbuilder"
|
||||
|
||||
gem 'devise'
|
||||
|
||||
gem 'rolify'
|
||||
|
||||
gem 'cancancan'
|
||||
|
||||
gem 'webpacker'
|
||||
|
||||
gem 'kaminari'
|
||||
|
||||
# Use Redis adapter to run Action Cable in production
|
||||
# gem "redis", ">= 4.0.1"
|
||||
|
||||
|
|
40
Gemfile.lock
40
Gemfile.lock
|
@ -78,11 +78,13 @@ GEM
|
|||
addressable (2.8.6)
|
||||
public_suffix (>= 2.0.2, < 6.0)
|
||||
base64 (0.2.0)
|
||||
bcrypt (3.1.20)
|
||||
bigdecimal (3.1.5)
|
||||
bindex (0.8.1)
|
||||
bootsnap (1.17.0)
|
||||
msgpack (~> 1.2)
|
||||
builder (3.2.4)
|
||||
cancancan (3.5.0)
|
||||
capybara (3.39.2)
|
||||
addressable
|
||||
matrix
|
||||
|
@ -99,6 +101,12 @@ GEM
|
|||
debug (1.9.1)
|
||||
irb (~> 1.10)
|
||||
reline (>= 0.3.8)
|
||||
devise (4.9.3)
|
||||
bcrypt (~> 3.0)
|
||||
orm_adapter (~> 0.1)
|
||||
railties (>= 4.1.0)
|
||||
responders
|
||||
warden (~> 1.2.3)
|
||||
drb (2.2.0)
|
||||
ruby2_keywords
|
||||
erubi (1.12.0)
|
||||
|
@ -117,6 +125,18 @@ GEM
|
|||
jbuilder (2.11.5)
|
||||
actionview (>= 5.0.0)
|
||||
activesupport (>= 5.0.0)
|
||||
kaminari (1.2.2)
|
||||
activesupport (>= 4.1.0)
|
||||
kaminari-actionview (= 1.2.2)
|
||||
kaminari-activerecord (= 1.2.2)
|
||||
kaminari-core (= 1.2.2)
|
||||
kaminari-actionview (1.2.2)
|
||||
actionview
|
||||
kaminari-core (= 1.2.2)
|
||||
kaminari-activerecord (1.2.2)
|
||||
activerecord
|
||||
kaminari-core (= 1.2.2)
|
||||
kaminari-core (1.2.2)
|
||||
loofah (2.22.0)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.12.0)
|
||||
|
@ -153,6 +173,7 @@ GEM
|
|||
racc (~> 1.4)
|
||||
nokogiri (1.16.0-x86_64-linux)
|
||||
racc (~> 1.4)
|
||||
orm_adapter (0.5.0)
|
||||
psych (5.1.2)
|
||||
stringio
|
||||
public_suffix (5.0.4)
|
||||
|
@ -160,6 +181,8 @@ GEM
|
|||
nio4r (~> 2.0)
|
||||
racc (1.7.3)
|
||||
rack (3.0.8)
|
||||
rack-proxy (0.7.7)
|
||||
rack
|
||||
rack-session (2.0.0)
|
||||
rack (>= 3.0.0)
|
||||
rack-test (2.1.0)
|
||||
|
@ -202,13 +225,18 @@ GEM
|
|||
regexp_parser (2.9.0)
|
||||
reline (0.4.2)
|
||||
io-console (~> 0.5)
|
||||
responders (3.1.1)
|
||||
actionpack (>= 5.2)
|
||||
railties (>= 5.2)
|
||||
rexml (3.2.6)
|
||||
rolify (6.0.1)
|
||||
ruby2_keywords (0.0.5)
|
||||
rubyzip (2.3.2)
|
||||
selenium-webdriver (4.16.0)
|
||||
rexml (~> 3.2, >= 3.2.5)
|
||||
rubyzip (>= 1.2.2, < 3.0)
|
||||
websocket (~> 1.0)
|
||||
semantic_range (3.0.0)
|
||||
sprockets (4.2.1)
|
||||
concurrent-ruby (~> 1.0)
|
||||
rack (>= 2.2.4, < 4)
|
||||
|
@ -233,11 +261,18 @@ GEM
|
|||
railties (>= 6.0.0)
|
||||
tzinfo (2.0.6)
|
||||
concurrent-ruby (~> 1.0)
|
||||
warden (1.2.9)
|
||||
rack (>= 2.0.9)
|
||||
web-console (4.2.1)
|
||||
actionview (>= 6.0.0)
|
||||
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)
|
||||
webrick (1.8.1)
|
||||
websocket (1.2.10)
|
||||
websocket-driver (0.7.6)
|
||||
|
@ -257,12 +292,16 @@ PLATFORMS
|
|||
|
||||
DEPENDENCIES
|
||||
bootsnap
|
||||
cancancan
|
||||
capybara
|
||||
debug
|
||||
devise
|
||||
importmap-rails
|
||||
jbuilder
|
||||
kaminari
|
||||
puma (>= 5.0)
|
||||
rails (~> 7.1.2)
|
||||
rolify
|
||||
selenium-webdriver
|
||||
sprockets-rails
|
||||
sqlite3 (~> 1.4)
|
||||
|
@ -270,6 +309,7 @@ DEPENDENCIES
|
|||
turbo-rails
|
||||
tzinfo-data
|
||||
web-console
|
||||
webpacker
|
||||
|
||||
RUBY VERSION
|
||||
ruby 3.2.2p53
|
||||
|
|
61
Makefile
61
Makefile
|
@ -6,3 +6,64 @@ push:
|
|||
pull:
|
||||
git pull
|
||||
|
||||
version:
|
||||
-@rails --version
|
||||
-@whereis rails
|
||||
-@echo "npm" `npm --version`
|
||||
-@whereis npm
|
||||
-@echo "yarn" `yarn -version`
|
||||
-@whereis yarn
|
||||
-@ruby --version
|
||||
-@whereis ruby
|
||||
|
||||
reset:
|
||||
git reset --hard
|
||||
|
||||
#This opens a secure shell on test.obdev.io (ssh jcarr@test.obdev.io)
|
||||
#This opens screen (screen -d) disconnect (screen -a -r) connect
|
||||
#To copy the database info (scp "filename") found in storage
|
||||
|
||||
# gem 'devise'
|
||||
# bundle install
|
||||
# rails generate devise:install
|
||||
# rails generate devise User
|
||||
# rails db:migrate
|
||||
# rails generate devise:views
|
||||
|
||||
# gem 'webpacker'
|
||||
# bundle install
|
||||
# rails webpacker:install
|
||||
|
||||
# gem 'kaminari'
|
||||
# bundle install
|
||||
# rails g kaminari:views default
|
||||
|
||||
# gem 'rolify'
|
||||
# bundle install
|
||||
# rails g rolify Role User
|
||||
# rails db:migrate
|
||||
|
||||
# mariams box:
|
||||
# mariam@flippy:~/obdev$ make version
|
||||
# Rails 7.1.2
|
||||
# rails: /usr/bin/rails /home/mariam/.rbenv/shims/rails
|
||||
# npm 9.2.0
|
||||
# npm: /usr/bin/npm /usr/share/npm /usr/share/man/man1/npm.1.gz
|
||||
# yarn 1.22.21
|
||||
# yarn: /usr/local/bin/yarn
|
||||
# ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-linux]
|
||||
# ruby: /usr/bin/ruby /usr/lib/x86_64-linux-gnu/ruby /usr/lib/ruby /home/mariam/.rbenv/shims/ruby /usr/share/man/man1/ruby.1.gz
|
||||
# mariam@flippy:~/obdev$
|
||||
#
|
||||
# +firstscaffold:
|
||||
# rails generate lsdslkjdkl Product
|
||||
|
||||
# ben@tempy:~/obdev$ make version
|
||||
# Rails 7.1.2
|
||||
# rails: /usr/bin/rails /home/ben/.rbenv/shims/rails
|
||||
# npm 10.2.4
|
||||
# npm: /usr/bin/npm /usr/share/npm /home/ben/.nvm/versions/node/v20.11.0/bin/npm /usr/share/man/man1/npm.1.gz
|
||||
# yarn 1.22.19
|
||||
# yarn: /usr/bin/yarn /usr/share/yarn
|
||||
# ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-linux]
|
||||
# ruby: /usr/bin/ruby /usr/lib/x86_64-linux-gnu/ruby /usr/lib/ruby /home/ben/.rbenv/shims/ruby /usr/share/man/man1/ruby.1.gz
|
||||
|
|
|
@ -2,3 +2,8 @@
|
|||
//= link_directory ../stylesheets .css
|
||||
//= link_tree ../../javascript .js
|
||||
//= link_tree ../../../vendor/javascript .js
|
||||
//= link rails-ujs.js
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -13,3 +13,12 @@
|
|||
*= require_tree .
|
||||
*= require_self
|
||||
*/
|
||||
|
||||
/* Add your custom styles here */
|
||||
.bg-light-grey {
|
||||
background-color: #e6e5e5da; /* Light grey color */
|
||||
}
|
||||
|
||||
.pagination .page-item.active .page-link {
|
||||
border-color: var(--bs-dark);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
module Admin
|
||||
class UsersController < ApplicationController
|
||||
before_action :authenticate_user!
|
||||
before_action :check_admin
|
||||
|
||||
def new_user
|
||||
@user = User.new
|
||||
end
|
||||
|
||||
def create_user
|
||||
@user = User.new(user_params)
|
||||
if @user.save
|
||||
redirect_to users_path, notice: 'User was successfully created.'
|
||||
else
|
||||
render :new_user
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def user_params
|
||||
params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation, :phone, :company)
|
||||
end
|
||||
|
||||
def check_admin
|
||||
unless current_user.admin?
|
||||
redirect_to root_path, alert: 'Not authorized'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -1,2 +1,7 @@
|
|||
class ApplicationController < ActionController::Base
|
||||
end
|
||||
before_action :authenticate_user!
|
||||
rescue_from CanCan::AccessDenied do |exception|
|
||||
redirect_to root_url, alert: "Access denied."
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
class BankAccountsController < ApplicationController
|
||||
before_action :set_owner
|
||||
before_action :set_bank_account, only: [:edit, :update, :destroy]
|
||||
|
||||
def new
|
||||
@bank_account = BankAccount.new
|
||||
end
|
||||
|
||||
def create
|
||||
@bank_account = @owner.bank_accounts.build(bank_account_params)
|
||||
if @bank_account.save
|
||||
redirect_to owner_path(@owner), notice: 'Bank account was successfully created.'
|
||||
else
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
def index
|
||||
@bank_accounts = @owner.bank_accounts.order(start_date: :desc)
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
@bank_account = BankAccount.find(params[:id])
|
||||
if @bank_account.update(bank_account_params)
|
||||
redirect_to owner_path(@owner), notice: 'Bank account was successfully updated.'
|
||||
else
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@bank_account.destroy
|
||||
redirect_to polymorphic_path([@owner]), notice: 'Bank account was successfully deleted.'
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def set_owner
|
||||
@owner = if params[:participant_id]
|
||||
Participant.find(params[:participant_id])
|
||||
elsif params[:worker_id]
|
||||
Worker.find(params[:worker_id])
|
||||
elsif params[:vendor_id]
|
||||
Vendor.find(params[:vendor_id])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def find_owner
|
||||
params.each do |name, value|
|
||||
if name =~ /(.+)_id$/
|
||||
return $1.classify.constantize.find(value)
|
||||
end
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
def set_bank_account
|
||||
@bank_account = BankAccount.find(params[:id])
|
||||
end
|
||||
|
||||
def bank_account_params
|
||||
params.require(:bank_account).permit(:institution_name, :account_type, :routing_number, :account_number, :start_date, :end_date)
|
||||
end
|
||||
|
||||
def owner_path(owner)
|
||||
case owner
|
||||
when Participant
|
||||
participant_path(owner)
|
||||
when Worker
|
||||
worker_path(owner)
|
||||
when Vendor
|
||||
vendor_path(owner)
|
||||
else
|
||||
root_path # Default path if owner type is unknown
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
class EmployerRecordsController < ApplicationController
|
||||
before_action :set_employer_record, only: [:edit, :update]
|
||||
|
||||
def edit
|
||||
# Logic to edit an EmployerRecord
|
||||
# Display a form to edit the EmployerRecord
|
||||
end
|
||||
|
||||
def update
|
||||
# Logic to update an EmployerRecord
|
||||
# Called when the edit form is submitted
|
||||
if @employer_record.update(employer_record_params)
|
||||
redirect_to employer_path(@employer_record.employer), notice: 'Employer record was successfully updated.'
|
||||
else
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
||||
def link_participant_to_employer
|
||||
# Assuming you have the employer and participant IDs
|
||||
employer_id = params[:employer_id]
|
||||
participant_id = params[:participant_id]
|
||||
|
||||
employer_record = EmployerRecord.new(employer_id: employer_id, participant_id: participant_id, start_date: Date.today)
|
||||
|
||||
if employer_record.save
|
||||
# Redirect or render success message
|
||||
else
|
||||
# Handle error
|
||||
end
|
||||
end
|
||||
|
||||
def link_participant
|
||||
@employer_record = EmployerRecord.new(employer_record_params)
|
||||
if @employer_record.save
|
||||
redirect_to employer_path(@employer_record.employer), notice: 'Participant was successfully linked.'
|
||||
else
|
||||
render 'show' # Or where you want to redirect in case of failure
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def destroy
|
||||
@employer_record = EmployerRecord.find_by(id: params[:id])
|
||||
employer_id = @employer_record&.employer_id
|
||||
|
||||
if @employer_record
|
||||
@employer_record.destroy
|
||||
redirect_to employer_path(employer_id), notice: 'Employer record was successfully deleted.'
|
||||
else
|
||||
# Providing a more descriptive alert message
|
||||
alert_message = "Unable to find the employer record. It may have already been deleted or does not exist."
|
||||
redirect_to employer_path(employer_id), alert: alert_message
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
private
|
||||
|
||||
def set_employer_record
|
||||
@employer_record = EmployerRecord.find(params[:id])
|
||||
end
|
||||
|
||||
def employer_record_params
|
||||
params.require(:employer_record).permit(:employer_id, :participant_id, :start_date, :end_date)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,133 @@
|
|||
class EmployersController < ApplicationController
|
||||
before_action :set_employer, only: [:show, :edit, :update, :destroy]
|
||||
|
||||
# GET /employers
|
||||
def index
|
||||
@employers = Employer.order(:last_name).page(params[:page]).per(5) # Adjust the number per page as needed
|
||||
end
|
||||
|
||||
# GET /employers/:id
|
||||
def show
|
||||
Rails.logger.debug "Employer ID: #{params[:id]}"
|
||||
@employer = Employer.includes(employer_records: :participant).find(params[:id])
|
||||
Rails.logger.debug "Employer: #{@employer.inspect}"
|
||||
end
|
||||
|
||||
|
||||
def new
|
||||
@employer = Employer.new
|
||||
end
|
||||
|
||||
def create
|
||||
@employer = Employer.new(employer_params)
|
||||
if @employer.save
|
||||
assign_role_specific_forms_to(@employer)
|
||||
redirect_to @employer, notice: 'Employer was successfully created.'
|
||||
else
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
if @employer.update(employer_params)
|
||||
redirect_to @employer, notice: 'Employer was successfully updated.'
|
||||
else
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@employer = Employer.find_by(id: params[:id])
|
||||
if @employer
|
||||
@employer.destroy
|
||||
redirect_to employers_url, notice: 'Employer was successfully deleted.'
|
||||
else
|
||||
redirect_to employers_url, alert: 'Employer record not found.'
|
||||
end
|
||||
end
|
||||
|
||||
def search
|
||||
if params[:term].present?
|
||||
@employers = Employer.where(
|
||||
"first_name LIKE :term OR last_name LIKE :term",
|
||||
term: "%#{params[:term]}%"
|
||||
)
|
||||
else
|
||||
@employers = Employer.none
|
||||
end
|
||||
|
||||
render json: @employers.map { |e| { label: e.full_name, value: e.id } }
|
||||
end
|
||||
|
||||
def link_employer
|
||||
@worker = Worker.find(params[:id])
|
||||
employer_record = @worker.employer_records.new(employer_record_params)
|
||||
# Handle the logic for creating the employer_record
|
||||
# ...
|
||||
end
|
||||
|
||||
def link_worker
|
||||
@employer = Employer.find(params[:id])
|
||||
participant_id = params[:employer_record][:participant_id] # Assuming this is passed from the form
|
||||
start_date = params[:employer_record][:start_date]
|
||||
end_date = params[:employer_record][:end_date]
|
||||
|
||||
employer_record = EmployerRecord.new(
|
||||
employer: @employer,
|
||||
participant_id: participant_id,
|
||||
start_date: start_date,
|
||||
end_date: end_date
|
||||
)
|
||||
|
||||
if employer_record.save
|
||||
redirect_to @employer, notice: 'Worker was successfully linked.'
|
||||
else
|
||||
flash.now[:alert] = employer_record.errors.full_messages.to_sentence
|
||||
render :show
|
||||
end
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
# Handle case where Employer is not found
|
||||
redirect_to some_path, alert: 'Employer not found.'
|
||||
end
|
||||
|
||||
def onboarding
|
||||
@employer = employer.find(params[:id])
|
||||
@onboarding_items = @employer.onboarding_items.includes(:form)
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def set_employer
|
||||
@employer = Employer.find(params[:id])
|
||||
end
|
||||
|
||||
def employer_params
|
||||
params.require(:employer).permit(
|
||||
:first_name, :last_name,
|
||||
:address_line_1, :address_line_2,
|
||||
:city, :state, :zip,
|
||||
:phone, :email, :tin, :dob, :ssn, :gender
|
||||
)
|
||||
end
|
||||
|
||||
def employer_record_params
|
||||
params.require(:employer_record).permit(:employer_id, :start_date, :end_date)
|
||||
end
|
||||
|
||||
def assign_role_specific_forms_to(employer)
|
||||
employer_role = FormRole.find_by(name: 'Employer')
|
||||
|
||||
# Fetch forms associated with the "Employer" role
|
||||
forms_for_employer = employer_role.forms
|
||||
|
||||
forms_for_employer.each do |form|
|
||||
# Create an onboarding item for each form for the newly created employer
|
||||
employer.onboarding_items.create(form: form)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,36 @@
|
|||
class EmploymentsController < ApplicationController
|
||||
before_action :set_employment, only: [:edit, :update, :destroy]
|
||||
|
||||
def edit
|
||||
# Edit view will be rendered
|
||||
end
|
||||
|
||||
def update
|
||||
if @employment.update(employment_params)
|
||||
redirect_to participant_path(@employment.participant), notice: 'Employment was successfully updated.'
|
||||
else
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
participant = @employment.participant
|
||||
@employment.destroy
|
||||
redirect_to participant_path(participant), notice: 'Employment was successfully removed.'
|
||||
end
|
||||
|
||||
def index
|
||||
@employments = Employment.all # or however you need to retrieve the data
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_employment
|
||||
@employment = Employment.find(params[:id])
|
||||
end
|
||||
|
||||
def employment_params
|
||||
params.require(:employment).permit(:start_date, :end_date)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
class FormsController < ApplicationController
|
||||
before_action :set_form, only: [:show, :edit, :update, :destroy]
|
||||
|
||||
def index
|
||||
@forms = Form.all
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
|
||||
def new
|
||||
@form = Form.new
|
||||
end
|
||||
|
||||
def create
|
||||
@form = Form.new(form_params)
|
||||
if @form.save
|
||||
redirect_to forms_path, notice: 'Form was successfully created.'
|
||||
else
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
if @form.update(form_params[:id])
|
||||
redirect_to @form, notice: 'Form was successfully updated.'
|
||||
else
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@form = Form.find(params[:id])
|
||||
# Manually delete or handle associated records here
|
||||
@form.onboarding_items.destroy_all
|
||||
@form.forms_roles.destroy_all
|
||||
@form.destroy
|
||||
redirect_to forms_url, notice: 'Form was successfully destroyed.'
|
||||
rescue ActiveRecord::InvalidForeignKey
|
||||
redirect_to forms_url, alert: 'Form could not be deleted. There are dependent records still associated.'
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
def set_form
|
||||
@form = Form.find(params[:id])
|
||||
end
|
||||
|
||||
def form_params
|
||||
params.require(:form).permit(:name, :required, :program, form_role_ids: [])
|
||||
end
|
||||
|
||||
|
||||
def check_admin
|
||||
redirect_to(root_path, alert: "Not authorized") unless current_user.admin?
|
||||
end
|
||||
end
|
|
@ -1,4 +1,6 @@
|
|||
class HomeController < ApplicationController
|
||||
before_action :authenticate_user!
|
||||
|
||||
def index
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
class OnboardingsController < ApplicationController
|
||||
before_action :set_owner, only: [:index, :submit_onboarding]
|
||||
|
||||
def index
|
||||
# Make sure to set @owner first. If not found, you should redirect or handle the error appropriately.
|
||||
set_owner
|
||||
|
||||
if @owner
|
||||
# Initialize onboarding items for each form if they don't exist yet for the owner.
|
||||
@forms = Form.all
|
||||
@forms.each do |form|
|
||||
@owner.onboarding_items.find_or_initialize_by(form: form)
|
||||
end
|
||||
# After building or finding the onboarding items, load them for the view.
|
||||
# This ensures we're only working with items related to the current owner.
|
||||
@onboarding_items = @owner.onboarding_items.includes(:form)
|
||||
else
|
||||
# Handle the scenario where @owner is not found. Redirect or show an error.
|
||||
redirect_to root_path, alert: "Owner not found."
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
# Assuming `onboarding_items_params` method will handle mass assignment
|
||||
@onboarding_item = @owner.onboarding_items.build(onboarding_items_params)
|
||||
|
||||
if @onboarding_item.save
|
||||
redirect_to polymorphic_path([@owner, :onboardings]), notice: 'Onboarding item was successfully created.'
|
||||
else
|
||||
# This assumes you have an instance variable @forms for the form dropdown in the view
|
||||
@forms = Form.all
|
||||
render :index, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def submit_onboarding
|
||||
@owner = find_owner
|
||||
onboarding_items_params.values.each do |item_params|
|
||||
item = OnboardingItem.find_or_initialize_by(id: item_params.delete(:id))
|
||||
item.assign_attributes(item_params)
|
||||
item.owner = @owner
|
||||
item.save
|
||||
end
|
||||
redirect_to polymorphic_path(@owner), notice: 'Onboarding information updated successfully.'
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def set_owner
|
||||
params.each do |name, value|
|
||||
if name =~ /(.+)_id$/
|
||||
model_name = name.match(/(.+)_id$/)[1].classify
|
||||
@owner = model_name.constantize.find(value)
|
||||
break
|
||||
end
|
||||
end
|
||||
unless @owner
|
||||
redirect_to root_path, alert: "Owner not found."
|
||||
end
|
||||
end
|
||||
|
||||
def onboarding_items_params
|
||||
params.permit(onboarding_items: [:id, :note, :date_completed]).fetch(:onboarding_items, {})
|
||||
end
|
||||
|
||||
def find_owner
|
||||
# Check each expected owner type and find the corresponding record
|
||||
if params[:participant_id]
|
||||
@owner = Participant.find(params[:participant_id])
|
||||
elsif params[:employer_id]
|
||||
@owner = Employer.find(params[:employer_id])
|
||||
elsif params[:worker_id]
|
||||
@owner = Worker.find(params[:worker_id])
|
||||
elsif params[:vendor_id]
|
||||
@owner = Vendor.find(params[:vendor_id])
|
||||
else
|
||||
# Handle the case where no recognized owner parameter is provided
|
||||
redirect_to root_path, alert: "Owner not found."
|
||||
return nil
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,233 @@
|
|||
class ParticipantsController < ApplicationController
|
||||
before_action :set_participant, only: [:show, :edit, :update, :destroy]
|
||||
|
||||
def index
|
||||
@participants = Participant.order(:last_name).page(params[:page]).per(5) # Adjust the number per page as needed
|
||||
end
|
||||
|
||||
|
||||
def show
|
||||
@participant = Participant.includes(:employments, :service_contracts).find(params[:id])
|
||||
@workers = @participant.workers # Fetch associated workers
|
||||
@employments = @participant.employments.includes(:worker).order('workers.last_name')
|
||||
@service_contracts = @participant.service_contracts.includes(:vendor) # Fetch associated service contracts
|
||||
@employment = Employment.new # Initialize a new Employment object
|
||||
@service_contract = ServiceContract.new # Initialize a new Service Contract object
|
||||
end
|
||||
|
||||
def new
|
||||
@participant = Participant.new
|
||||
end
|
||||
|
||||
def create
|
||||
@participant = Participant.new(participant_params)
|
||||
|
||||
if ssn_already_taken?(@participant.ssn)
|
||||
flash.now[:alert] = 'SSN is already taken by another participant or employer.'
|
||||
render :new, status: :unprocessable_entity and return
|
||||
end
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
if params[:is_employer] == 'yes'
|
||||
# This assumes you have a method `create_new_employer_for_participant` that handles creating a new employer and setting `@participant.employer_id`.
|
||||
unless create_new_employer_for_participant(@participant)
|
||||
render :new, status: :unprocessable_entity and return
|
||||
end
|
||||
elsif params[:employer_id].present?
|
||||
# Directly assign the existing employer_id to the participant
|
||||
@participant.employer_id = params[:employer_id]
|
||||
end
|
||||
|
||||
if @participant.save
|
||||
# Create an EmployerRecord only if necessary.
|
||||
create_employer_record(@participant) if @participant.employer_id.present?
|
||||
|
||||
redirect_to @participant, notice: 'Participant was successfully created.'
|
||||
else
|
||||
render :new, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
rescue ActiveRecord::RecordInvalid => e
|
||||
flash.now[:alert] = "Failed to create participant: #{e.message}"
|
||||
render :new, status: :unprocessable_entity
|
||||
end
|
||||
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
@participant = Participant.find(params[:id])
|
||||
|
||||
if @participant.update(participant_params)
|
||||
update_employer_details(@participant)
|
||||
|
||||
if @participant.errors.any?
|
||||
# If there are errors (e.g., from updating employer details), re-render the edit form.
|
||||
render :edit
|
||||
else
|
||||
# If everything went well, redirect to the participant's show page.
|
||||
redirect_to @participant, notice: 'Participant and associated employer details were successfully updated.'
|
||||
end
|
||||
else
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
def search
|
||||
if params[:term].present?
|
||||
@participants = Participant.where("first_name LIKE ? OR last_name LIKE ?", "%#{params[:term]}%", "%#{params[:term]}%")
|
||||
else
|
||||
@participants = Participant.none
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
format.json { render json: @participants.map { |participant| { label: participant.full_name, value: participant.id } } }
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@participant = Participant.find(params[:id])
|
||||
begin
|
||||
@participant.destroy
|
||||
redirect_to participants_url, notice: 'Participant was successfully destroyed.'
|
||||
rescue ActiveRecord::InvalidForeignKey
|
||||
# Redirect with an error message if foreign key constraints fail
|
||||
redirect_to participants_url, alert: 'Participant cannot be deleted because it is linked to other records.'
|
||||
end
|
||||
end
|
||||
|
||||
def link_worker
|
||||
@participant = Participant.find(params[:id])
|
||||
@employment = @participant.employments.new(employment_params)
|
||||
|
||||
if @employment.save
|
||||
redirect_to @participant, notice: 'Worker was successfully linked.'
|
||||
else
|
||||
Rails.logger.debug @employment.errors.full_messages
|
||||
flash[:alert] = @employment.errors.full_messages.to_sentence
|
||||
render 'show'
|
||||
end
|
||||
end
|
||||
|
||||
def link_vendor
|
||||
@participant = Participant.find(params[:id])
|
||||
@service_contract = @participant.service_contracts.new(service_contract_params)
|
||||
|
||||
if @service_contract.save
|
||||
redirect_to @participant, notice: 'Vendor was successfully linked.'
|
||||
else
|
||||
flash[:alert] = @service_contract.errors.full_messages.to_sentence
|
||||
render 'show'
|
||||
end
|
||||
end
|
||||
|
||||
def onboarding
|
||||
@participant = Participant.find(params[:id])
|
||||
@onboarding_items = @participant.onboarding_items.includes(:form)
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def handle_employer_creation_for_participant(participant)
|
||||
if params[:is_employer] == 'yes'
|
||||
employer = Employer.create!(employer_params_from_participant(participant))
|
||||
participant.employer_id = employer.id
|
||||
elsif params[:employer_id].present?
|
||||
participant.employer_id = params[:employer_id]
|
||||
end
|
||||
end
|
||||
|
||||
def set_participant
|
||||
@participant = Participant.find(params[:id])
|
||||
end
|
||||
|
||||
def ssn_already_taken?(ssn)
|
||||
Participant.exists?(ssn: ssn) || Employer.exists?(ssn: ssn)
|
||||
end
|
||||
|
||||
def participant_params
|
||||
params.require(:participant).permit(
|
||||
:first_name,
|
||||
:last_name,
|
||||
:address_line_1,
|
||||
:address_line_2,
|
||||
:city,
|
||||
:state,
|
||||
:zip,
|
||||
:phone,
|
||||
:email,
|
||||
:mci,
|
||||
:dob,
|
||||
:ssn,
|
||||
:gender,
|
||||
:employer_id
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
def employer_params_from_participant(participant)
|
||||
{
|
||||
first_name: participant.first_name,
|
||||
last_name: participant.last_name,
|
||||
address_line_1: participant.address_line_1,
|
||||
address_line_2: participant.address_line_2,
|
||||
city: participant.city,
|
||||
state: participant.state,
|
||||
zip: participant.zip,
|
||||
phone: participant.phone,
|
||||
email: participant.email,
|
||||
dob: participant.dob,
|
||||
ssn: participant.ssn,
|
||||
gender: participant.gender
|
||||
}
|
||||
end
|
||||
|
||||
def employment_params
|
||||
params.require(:employment).permit(:worker_id, :start_date, :end_date)
|
||||
end
|
||||
|
||||
def service_contract_params
|
||||
params.require(:service_contract).permit(:vendor_id, :start_date, :end_date)
|
||||
end
|
||||
|
||||
def create_new_employer_for_participant(participant)
|
||||
employer = Employer.create!(employer_params_from_participant(participant))
|
||||
participant.employer_id = employer.id
|
||||
employer.persisted?
|
||||
end
|
||||
|
||||
def create_employer_record(participant)
|
||||
EmployerRecord.create!(participant: participant, employer_id: participant.employer_id, start_date: Date.today)
|
||||
end
|
||||
|
||||
|
||||
def update_employer_details(participant)
|
||||
employer = Employer.find(participant.employer_id)
|
||||
|
||||
update_attrs = {
|
||||
# Include all fields you want to update, excluding SSN
|
||||
first_name: participant.first_name,
|
||||
last_name: participant.last_name,
|
||||
address_line_1: participant.address_line_1,
|
||||
address_line_2: participant.address_line_2,
|
||||
city: participant.city,
|
||||
state: participant.state,
|
||||
zip: participant.zip,
|
||||
phone: participant.phone,
|
||||
email: participant.email,
|
||||
dob: participant.dob,
|
||||
gender: participant.gender,
|
||||
}
|
||||
|
||||
unless employer.update(update_attrs)
|
||||
# If the update fails, add a custom error to the participant object.
|
||||
participant.errors.add(:base, "Employer details could not be updated: #{employer.errors.full_messages.join(', ')}")
|
||||
# You might not need to throw :abort if you're handling this logic in the controller.
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
class ServiceContractsController < ApplicationController
|
||||
before_action :set_service_contract, only: [:edit, :update, :destroy]
|
||||
|
||||
def new
|
||||
@service_contract = ServiceContract.new
|
||||
end
|
||||
|
||||
def create
|
||||
@service_contract = ServiceContract.new(service_contract_params)
|
||||
if @service_contract.save
|
||||
redirect_to participant_path(@service_contract.participant), notice: 'Service contract was successfully created.'
|
||||
else
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
if @service_contract.update(service_contract_params)
|
||||
redirect_to participant_path(@service_contract.participant), notice: 'Service contract was successfully updated.'
|
||||
else
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@service_contract.destroy
|
||||
redirect_to participant_path(@service_contract.participant), notice: 'Service contract was successfully destroyed.'
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_service_contract
|
||||
@service_contract = ServiceContract.find(params[:id])
|
||||
end
|
||||
|
||||
def service_contract_params
|
||||
params.require(:service_contract).permit(:start_date, :end_date, :participant_id, :vendor_id)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
class UsersController < ApplicationController
|
||||
before_action :authenticate_user!
|
||||
before_action :require_admin
|
||||
before_action :set_user, only: [:show, :edit, :update, :destroy]
|
||||
load_and_authorize_resource
|
||||
|
||||
def create
|
||||
@user = User.new(user_params)
|
||||
if @user.save
|
||||
redirect_to users_path, notice: 'User was successfully created.'
|
||||
else
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
# Since @user is set by set_user, there's no need to find the user again
|
||||
end
|
||||
|
||||
def update
|
||||
# Clean up password fields if they are blank
|
||||
cleaned_params = user_params
|
||||
if cleaned_params[:password].blank?
|
||||
cleaned_params.delete(:password)
|
||||
cleaned_params.delete(:password_confirmation)
|
||||
end
|
||||
|
||||
# Attempt to update the user with the cleaned parameters
|
||||
if @user.update(cleaned_params)
|
||||
UserRoleService.new(@user, params[:user][:roles] || []).update_roles # Handle roles separately
|
||||
redirect_to users_path, notice: 'User was successfully updated.'
|
||||
else
|
||||
render :edit # If there's an error, it will render the edit view where you can display error messages
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def destroy
|
||||
@user.destroy
|
||||
redirect_to users_path, notice: 'User was successfully deleted.'
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def set_user
|
||||
@user = User.find(params[:id])
|
||||
end
|
||||
|
||||
def user_params
|
||||
params.require(:user).permit(
|
||||
:email, :password, :password_confirmation, :remember_me,
|
||||
:first_name, :last_name, :phone, :company,
|
||||
:access_revoked, :access_start_date, :access_end_date,
|
||||
access_periods_attributes: [:id, :start_date, :end_date, :_destroy],
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
def require_admin
|
||||
redirect_to root_path, alert: 'Only admins are allowed to access this section.' unless current_user.admin?
|
||||
end
|
||||
end
|
|
@ -0,0 +1,87 @@
|
|||
class VendorsController < ApplicationController
|
||||
def index
|
||||
@vendors = Vendor.order(:name).page(params[:page]).per(5) # Adjust the number per page as needed
|
||||
end
|
||||
|
||||
def show
|
||||
@vendor = Vendor.find(params[:id])
|
||||
@sorted_participants = @vendor.service_contracts.includes(:participant).map(&:participant).sort_by(&:last_name)
|
||||
end
|
||||
|
||||
def new
|
||||
@vendor = Vendor.new
|
||||
end
|
||||
|
||||
def create
|
||||
@vendor = Vendor.new(vendor_params)
|
||||
if @vendor.save
|
||||
assign_role_specific_forms_to(@vendor)
|
||||
redirect_to @vendor, notice: 'Vendor was successfully created.'
|
||||
else
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def edit
|
||||
@vendor = Vendor.find(params[:id])
|
||||
end
|
||||
|
||||
def update
|
||||
@vendor = Vendor.find(params[:id])
|
||||
if @vendor.update(vendor_params)
|
||||
redirect_to @vendor
|
||||
else
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@vendor = Vendor.find(params[:id])
|
||||
@vendor.destroy
|
||||
redirect_to vendors_path
|
||||
end
|
||||
|
||||
def search
|
||||
if params[:term].present?
|
||||
@vendors = Vendor.where("name LIKE ?", "%#{params[:term]}%")
|
||||
else
|
||||
@vendors = Vendor.none
|
||||
end
|
||||
|
||||
# Respond with a JSON array of vendor names and IDs
|
||||
render json: @vendors.map { |vendor| { label: vendor.name, value: vendor.id } }
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
def vendor_params
|
||||
params.require(:vendor).permit(
|
||||
:name,
|
||||
:address_line_1,
|
||||
:address_line_2,
|
||||
:city,
|
||||
:state,
|
||||
:zip,
|
||||
:phone,
|
||||
:email,
|
||||
:dba,
|
||||
:tin,
|
||||
:contact
|
||||
)
|
||||
end
|
||||
|
||||
def assign_role_specific_forms_to(vendor)
|
||||
vendor_role = FormRole.find_by(name: 'Vendor')
|
||||
|
||||
# Fetch forms associated with the "Vendor" role
|
||||
forms_for_vendor = vendor_role.forms
|
||||
|
||||
forms_for_vendor.each do |form|
|
||||
# Create an onboarding item for each form for the newly created vendor
|
||||
vendor.onboarding_items.create(form: form)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
class WorkersController < ApplicationController
|
||||
def index
|
||||
@workers = Worker.order(:last_name).page(params[:page]).per(5) # Adjust the number per page as needed
|
||||
end
|
||||
|
||||
def show
|
||||
@worker = Worker.includes(:participants).find(params[:id])
|
||||
@employer_record = EmployerRecord.new
|
||||
@employments = @worker.employments
|
||||
@employment = Employment.new # Initialize a new Employment instance
|
||||
end
|
||||
|
||||
|
||||
def new
|
||||
@worker = Worker.new
|
||||
end
|
||||
|
||||
def create
|
||||
@worker = Worker.new(worker_params)
|
||||
if @worker.save
|
||||
assign_role_specific_forms_to(@worker)
|
||||
redirect_to @worker, notice: 'Worker was successfully created.'
|
||||
else
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def edit
|
||||
@worker = Worker.find(params[:id])
|
||||
end
|
||||
|
||||
def update
|
||||
@worker = Worker.find(params[:id])
|
||||
if @worker.update(worker_params)
|
||||
redirect_to @worker
|
||||
else
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@worker = Worker.find(params[:id])
|
||||
@worker.destroy
|
||||
redirect_to workers_path
|
||||
end
|
||||
|
||||
def search
|
||||
if params[:term]
|
||||
# Assuming you want to search by first name or last name
|
||||
@workers = Worker.where('first_name LIKE ? OR last_name LIKE ?', "%#{params[:term]}%", "%#{params[:term]}%")
|
||||
else
|
||||
@workers = Worker.all
|
||||
end
|
||||
|
||||
# Format the response as needed by your autocomplete component
|
||||
render json: @workers.map { |worker| { label: "#{worker.first_name} #{worker.last_name}", value: worker.id } }
|
||||
end
|
||||
|
||||
def link_participant
|
||||
@worker = Worker.find(params[:id])
|
||||
|
||||
# Assuming you're submitting the participant ID in your form
|
||||
participant_id = params[:employment][:participant_id]
|
||||
start_date = params[:employment][:start_date]
|
||||
end_date = params[:employment][:end_date]
|
||||
|
||||
# Create the employment relationship
|
||||
@employment = @worker.employments.build(participant_id: participant_id, start_date: start_date, end_date: end_date)
|
||||
|
||||
if @employment.save
|
||||
redirect_to @worker, notice: 'Participant was successfully linked to the worker.'
|
||||
else
|
||||
render 'show', alert: 'Unable to link participant.'
|
||||
end
|
||||
end
|
||||
|
||||
def onboarding
|
||||
@worker = worker.find(params[:id])
|
||||
@onboarding_items = @worker.onboarding_items.includes(:form)
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
def worker_params
|
||||
params.require(:worker).permit(
|
||||
:first_name, :last_name,
|
||||
:address_line_1, :address_line_2, :city, :state, :zip,
|
||||
:phone, :email, :dob, :ssn, :gender
|
||||
)
|
||||
end
|
||||
|
||||
def assign_role_specific_forms_to(worker)
|
||||
worker_role = FormRole.find_by(name: 'Worker')
|
||||
|
||||
# Fetch forms associated with the "Worker" role
|
||||
forms_for_worker = worker_role.forms
|
||||
|
||||
forms_for_worker.each do |form|
|
||||
# Create an onboarding item for each form for the newly created worker
|
||||
worker.onboarding_items.create(form: form)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
module AdminHelper
|
||||
end
|
|
@ -0,0 +1,7 @@
|
|||
module BankAccountsHelper
|
||||
def hide_account_number(account_number)
|
||||
# Example implementation that hides all but the last 4 digits
|
||||
"**** **** **** #{account_number.last(4)}"
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
module EmployerRecordsHelper
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
module EmployersHelper
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
module EmploymentsHelper
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
module FormsHelper
|
||||
end
|
|
@ -0,0 +1,16 @@
|
|||
module OnboardingsHelper
|
||||
def submit_onboarding_polymorphic_path(owner)
|
||||
case owner
|
||||
when Participant
|
||||
submit_onboarding_participant_onboardings_path(owner)
|
||||
when Worker
|
||||
submit_onboarding_worker_onboardings_path(owner)
|
||||
when Vendor
|
||||
submit_onboarding_vendor_onboardings_path(owner)
|
||||
when Employer
|
||||
submit_onboarding_employer_onboardings_path(owner)
|
||||
else
|
||||
root_path # Default path if owner type is unrecognized
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,7 @@
|
|||
module ParticipantsHelper
|
||||
def mask_ssn(ssn)
|
||||
return '' if ssn.blank?
|
||||
|
||||
"*****#{ssn[-4..-1]}"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
module ServiceContractsHelper
|
||||
end
|
|
@ -0,0 +1,6 @@
|
|||
module UsersHelper
|
||||
def display_user_role(user)
|
||||
user.roles.first&.name&.capitalize || "None"
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
module VendorsHelper
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
module WorkersHelper
|
||||
end
|
|
@ -1,3 +1,9 @@
|
|||
// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
|
||||
import "@hotwired/turbo-rails"
|
||||
import "controllers"
|
||||
|
||||
import Rails from '@rails/ujs';
|
||||
Rails.start();
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Ability
|
||||
include CanCan::Ability
|
||||
|
||||
def initialize(user)
|
||||
user ||= User.new # guest user (not logged in)
|
||||
if user.has_role? :admin
|
||||
can :manage, :all
|
||||
can :create, User if user.has_role? :admin
|
||||
else
|
||||
can :read, :all
|
||||
# Define other abilities for other roles
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
class AccessPeriod < ApplicationRecord
|
||||
belongs_to :user
|
||||
|
||||
before_create :set_default_start_date
|
||||
validates :end_date, presence: true, if: -> { user&.access_revoked? }
|
||||
|
||||
private
|
||||
|
||||
def set_default_start_date
|
||||
self.start_date ||= Date.today if self.new_record? && self.start_date.blank?
|
||||
end
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
class BankAccount < ApplicationRecord
|
||||
belongs_to :owner, polymorphic: true
|
||||
end
|
|
@ -0,0 +1,15 @@
|
|||
module AccessControlValidations
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
validate :end_date_after_start_date, if: -> { access_revoked && access_end_date.present? }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def end_date_after_start_date
|
||||
if access_start_date.present? && access_end_date.present? && access_end_date < access_start_date
|
||||
errors.add(:access_end_date, 'must be after the start date')
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,50 @@
|
|||
class Employer < ApplicationRecord
|
||||
# Direct association with participants
|
||||
has_many :direct_participants, class_name: 'Participant'
|
||||
|
||||
# Association through EmployerRecord
|
||||
has_many :employer_records
|
||||
has_many :indirect_participants, through: :employer_records, source: :participant
|
||||
|
||||
# Association with Workers through direct_participants
|
||||
has_many :workers, through: :direct_participants
|
||||
|
||||
# Other methods...
|
||||
def full_name
|
||||
"#{first_name} #{last_name}"
|
||||
end
|
||||
|
||||
has_many :onboarding_items, as: :owner
|
||||
accepts_nested_attributes_for :onboarding_items
|
||||
|
||||
class Employer < ApplicationRecord
|
||||
# Associations and other methods as before...
|
||||
|
||||
validate :unique_as_participant, if: -> { ssn_changed? || new_record? }
|
||||
validates :ssn, uniqueness: { allow_blank: true }, if: -> { ssn.present? }
|
||||
validates :tin, uniqueness: { allow_blank: true }, if: -> { tin.present? }
|
||||
|
||||
private
|
||||
|
||||
def unique_as_participant
|
||||
if Participant.exists?(ssn: ssn) && (id.blank? || Participant.where.not(id: id).exists?(ssn: ssn))
|
||||
errors.add(:ssn, 'A participant with the same SSN already exists')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create_onboarding_items_for_forms
|
||||
# Ensure there's a 'Role' model with an association set up between Forms and Roles.
|
||||
employer_role = Role.find_by(name: 'Employer')
|
||||
return unless employer_role
|
||||
|
||||
# Fetch all forms associated with the 'Employer' role.
|
||||
forms = Form.joins(:roles).where(roles: { id: employer_role.id })
|
||||
forms.each do |form|
|
||||
self.onboarding_items.find_or_create_by(form: form)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
class EmployerRecord < ApplicationRecord
|
||||
belongs_to :employer
|
||||
belongs_to :participant
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
class Employment < ApplicationRecord
|
||||
belongs_to :worker
|
||||
validates :worker, presence: true
|
||||
belongs_to :participant
|
||||
end
|
|
@ -0,0 +1,31 @@
|
|||
class Form < ApplicationRecord
|
||||
# Assuming each form can have many onboarding items associated with different owners.
|
||||
has_many :onboarding_items
|
||||
has_many :forms_roles
|
||||
has_many :form_roles, through: :forms_roles
|
||||
accepts_nested_attributes_for :forms_roles, allow_destroy: true
|
||||
|
||||
validates :name, presence: true
|
||||
# Include more validations as necessary
|
||||
|
||||
after_save :update_onboarding_items
|
||||
|
||||
private
|
||||
|
||||
def form_role_ids=(ids)
|
||||
self.form_roles = ids.reject(&:blank?).map { |id| Role.find(id) }
|
||||
end
|
||||
|
||||
|
||||
|
||||
def update_onboarding_items
|
||||
roles.each do |role|
|
||||
# Assuming `role.name` is 'Participant', 'Worker', 'Vendor', or 'Employer'
|
||||
owner_class = role.name.constantize
|
||||
|
||||
owner_class.find_each do |owner|
|
||||
OnboardingItem.find_or_create_by(owner: owner, form: self)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,4 @@
|
|||
class FormRole < ApplicationRecord
|
||||
has_many :forms_roles
|
||||
has_many :forms, through: :forms_roles
|
||||
end
|
|
@ -0,0 +1,6 @@
|
|||
class FormsRole < ApplicationRecord
|
||||
belongs_to :form
|
||||
belongs_to :form_role
|
||||
attribute :note, :string
|
||||
attribute :date_completed, :date
|
||||
end
|
|
@ -0,0 +1,4 @@
|
|||
class OnboardingItem < ApplicationRecord
|
||||
belongs_to :owner, polymorphic: true
|
||||
belongs_to :form
|
||||
end
|
|
@ -0,0 +1,67 @@
|
|||
class Participant < ApplicationRecord
|
||||
after_create :create_onboarding_items_for_forms
|
||||
|
||||
# Associations
|
||||
belongs_to :employer, optional: false
|
||||
has_many :employments
|
||||
has_many :workers, through: :employments
|
||||
has_many :service_contracts
|
||||
has_many :vendors, through: :service_contracts
|
||||
has_many :employer_records
|
||||
has_many :employers, through: :employer_records
|
||||
has_and_belongs_to_many :programs
|
||||
has_many :bank_accounts, as: :owner
|
||||
has_many :onboarding_items, as: :owner
|
||||
accepts_nested_attributes_for :onboarding_items
|
||||
|
||||
# Validations
|
||||
validates :first_name, :last_name, :ssn, presence: true
|
||||
validates :ssn, uniqueness: { message: "SSN is already taken by another participant" }, unless: :ssn_already_taken_by_employer?
|
||||
validates :employer_id, presence: true
|
||||
|
||||
def full_name
|
||||
"#{first_name} #{last_name}"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ssn_already_taken_by_employer?
|
||||
# Check if the SSN already exists in the Employer model, excluding the current participant's employer
|
||||
Employer.where.not(id: employer_id).exists?(ssn: ssn)
|
||||
end
|
||||
|
||||
def create_onboarding_items_for_forms
|
||||
create_participant_onboarding_items
|
||||
create_employer_onboarding_items_if_applicable
|
||||
end
|
||||
|
||||
def create_participant_onboarding_items
|
||||
participant_role = FormRole.find_by(name: 'Participant')
|
||||
forms = Form.joins(:form_roles).where(form_roles: { id: participant_role.id })
|
||||
forms.each do |form|
|
||||
onboarding_items.find_or_create_by(form: form)
|
||||
end
|
||||
end
|
||||
|
||||
def create_employer_onboarding_items_if_applicable
|
||||
# Assuming there is a method or indicator to check if the participant is also an employer
|
||||
return unless self.is_also_employer?
|
||||
|
||||
employer_role = FormRole.find_by(name: 'Employer')
|
||||
forms = Form.joins(:form_roles).where(form_roles: { id: employer_role.id })
|
||||
forms.each do |form|
|
||||
# Here you need to decide how you want to associate the forms with the employer record
|
||||
# If the employer record is separate from the participant, you may need something like:
|
||||
self.employer.onboarding_items.find_or_create_by(form: form) if self.employer.present?
|
||||
# If the participant itself acts as an employer, then you might directly create onboarding items as done for participant forms
|
||||
end
|
||||
end
|
||||
|
||||
# A method to determine if the participant should also have employer forms
|
||||
def is_also_employer?
|
||||
# Implement logic to determine if the participant is also an employer
|
||||
# This might involve checking if the participant has an associated employer record
|
||||
# or any other logic specific to your application
|
||||
self.employer.present? # Example logic, adjust as needed
|
||||
end
|
||||
end
|
|
@ -0,0 +1,4 @@
|
|||
class Program < ApplicationRecord
|
||||
has_and_belongs_to_many :participants
|
||||
end
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
class Role < ApplicationRecord
|
||||
has_and_belongs_to_many :users, :join_table => :users_roles
|
||||
|
||||
belongs_to :resource,
|
||||
:polymorphic => true,
|
||||
:optional => true
|
||||
|
||||
|
||||
validates :resource_type,
|
||||
:inclusion => { :in => Rolify.resource_types },
|
||||
:allow_nil => true
|
||||
|
||||
scopify
|
||||
end
|
|
@ -0,0 +1,6 @@
|
|||
class ServiceContract < ApplicationRecord
|
||||
belongs_to :participant
|
||||
belongs_to :vendor
|
||||
|
||||
validates :participant_id, uniqueness: { scope: :vendor_id, message: "is already linked to this vendor" }
|
||||
end
|
|
@ -0,0 +1,52 @@
|
|||
class User < ApplicationRecord
|
||||
include AccessControlValidations
|
||||
rolify
|
||||
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable
|
||||
has_many :access_periods, dependent: :destroy
|
||||
accepts_nested_attributes_for :access_periods, allow_destroy: true
|
||||
after_create :assign_default_role
|
||||
before_update :handle_access_revocation
|
||||
|
||||
validate :password_complexity
|
||||
|
||||
# Callback to update the admin attribute based on Rolify role
|
||||
before_save :update_admin_attribute
|
||||
|
||||
# Override Devise method to consider access_revoked
|
||||
def active_for_authentication?
|
||||
super && !access_revoked && allowed_to_login?
|
||||
end
|
||||
|
||||
def admin?
|
||||
has_role?(:admin)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def assign_default_role
|
||||
self.add_role(:user) unless self.has_any_role?
|
||||
end
|
||||
|
||||
def password_complexity
|
||||
return if password.blank? || password =~ /(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9]).{8,}/
|
||||
errors.add :password, 'Complexity requirement not met. Length should be 8 characters and include: 1 uppercase, 1 lowercase, and 1 digit'
|
||||
end
|
||||
|
||||
def update_admin_attribute
|
||||
self.admin = has_role?(:admin)
|
||||
end
|
||||
|
||||
def allowed_to_login?
|
||||
# Assuming 'suspended' is a role that should not log in
|
||||
!has_role?(:suspended)
|
||||
end
|
||||
|
||||
def handle_access_revocation
|
||||
if access_revoked_changed? && access_revoked
|
||||
access_periods.find_or_initialize_by(end_date: nil).update(end_date: Date.today)
|
||||
elsif access_revoked_changed? && !access_revoked
|
||||
access_periods.create(start_date: Date.today)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
class Vendor < ApplicationRecord
|
||||
# Many-to-many relationships
|
||||
has_and_belongs_to_many :employers
|
||||
has_many :service_contracts
|
||||
has_many :participants, through: :service_contracts
|
||||
has_many :bank_accounts, as: :owner
|
||||
has_many :onboarding_items, as: :owner
|
||||
accepts_nested_attributes_for :onboarding_items
|
||||
|
||||
# Validations
|
||||
validates :tin, uniqueness: true, allow_blank: true, presence: true
|
||||
end
|
|
@ -0,0 +1,27 @@
|
|||
class Worker < ApplicationRecord
|
||||
# One-to-many relationship with Employments
|
||||
has_many :employments
|
||||
|
||||
# Many-to-many relationship with Participants through Employments
|
||||
has_many :participants, through: :employments
|
||||
|
||||
# Many-to-many relationship with Employers through Participants
|
||||
has_many :employers, through: :participants, source: :employer
|
||||
has_many :employer_records, through: :participants
|
||||
|
||||
has_many :onboarding_items, as: :owner
|
||||
accepts_nested_attributes_for :onboarding_items
|
||||
|
||||
# Validations
|
||||
validates :first_name, presence: true
|
||||
validates :last_name, presence: true
|
||||
validates :ssn, uniqueness: true, allow_blank: true, presence: true
|
||||
|
||||
# Method to return the full name of the worker
|
||||
def full_name
|
||||
"#{first_name} #{last_name}"
|
||||
end
|
||||
|
||||
has_many :bank_accounts, as: :owner
|
||||
|
||||
end
|
|
@ -0,0 +1,24 @@
|
|||
class UserRoleService
|
||||
def initialize(user, role_names)
|
||||
@user = user
|
||||
@role_names = role_names.reject(&:blank?).uniq
|
||||
end
|
||||
|
||||
def update_roles
|
||||
@user.roles = Role.where(name: @role_names)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def remove_unassigned_roles
|
||||
current_roles = @user.roles.pluck(:name)
|
||||
roles_to_remove = current_roles - @role_names
|
||||
roles_to_remove.each { |role| @user.remove_role(role) }
|
||||
end
|
||||
|
||||
def add_new_roles
|
||||
roles_to_add = @role_names - @user.roles.pluck(:name)
|
||||
roles_to_add.each { |role| @user.add_role(role) }
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
<div class="container mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<h2 class="mb-3 text-center">Create New User</h2>
|
||||
|
||||
<%= form_for(@user, url: admin_users_path, html: { class: 'needs-validation', novalidate: true }) do |f| %>
|
||||
<div class="mb-3">
|
||||
<%= f.label :first_name, 'First Name', class: 'form-label' %>
|
||||
<%= f.text_field :first_name, class: 'form-control', placeholder: 'Enter first name', required: true %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= f.label :last_name, 'Last Name', class: 'form-label' %>
|
||||
<%= f.text_field :last_name, class: 'form-control', placeholder: 'Enter last name', required: true %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= f.label :email, class: 'form-label' %>
|
||||
<%= f.email_field :email, class: 'form-control', placeholder: 'Enter email', required: true, autocomplete: "new-email" %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= f.label :password, 'Password', class: 'form-label' %>
|
||||
<%= f.password_field :password, class: 'form-control', placeholder: 'Password', required: true, autocomplete: "new-password" %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= f.label :password_confirmation, 'Confirm Password', class: 'form-label' %>
|
||||
<%= f.password_field :password_confirmation, class: 'form-control', placeholder: 'Confirm Password', required: true %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= f.label :phone, 'Phone Number', class: 'form-label' %>
|
||||
<%= f.telephone_field :phone, class: 'form-control', placeholder: 'Enter phone number' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= f.label :company, 'Company', class: 'form-label' %>
|
||||
<%= f.text_field :company, class: 'form-control', placeholder: 'Enter company name' %>
|
||||
</div>
|
||||
|
||||
<div class="actions text-center">
|
||||
<%= f.submit "Create User", class: 'btn btn-dark' %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<%# This is to indicate to the User if the passwords didn't match %>
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
const password = document.querySelector('#user_password');
|
||||
const confirmPassword = document.querySelector('#user_password_confirmation');
|
||||
const messageContainer = document.createElement('div');
|
||||
messageContainer.style.color = 'red';
|
||||
|
||||
// Append the messageContainer below the confirmPassword field
|
||||
confirmPassword.parentNode.insertBefore(messageContainer, confirmPassword.nextSibling);
|
||||
|
||||
function validatePassword(){
|
||||
if(password.value !== confirmPassword.value) {
|
||||
messageContainer.textContent = "Passwords need to match!";
|
||||
} else {
|
||||
messageContainer.textContent = "";
|
||||
}
|
||||
}
|
||||
|
||||
password.onchange = validatePassword;
|
||||
confirmPassword.onkeyup = validatePassword;
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,59 @@
|
|||
<%= form_with(model: [@owner, @bank_account], local: true, html: { class: 'needs-validation', novalidate: true }) do |form| %>
|
||||
<% if @bank_account.errors.any? %>
|
||||
<div id="error_explanation" class="alert alert-danger">
|
||||
<h4><%= pluralize(@bank_account.errors.count, "error") %> prohibited this bank account from being saved:</h4>
|
||||
<ul>
|
||||
<% @bank_account.errors.full_messages.each do |message| %>
|
||||
<li><%= message %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= form.label :institution_name, 'Institution Name', class: 'form-label' %>
|
||||
<%= form.text_field :institution_name, class: 'form-control', placeholder: 'Institution Name' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class='form-label'>Account Type</label><br>
|
||||
<%= form.radio_button :account_type, 'Checking', class: 'form-check-input' %>
|
||||
<%= form.label :account_type_checking, 'Checking', class: 'form-check-label' %>
|
||||
<%= form.radio_button :account_type, 'Savings', class: 'form-check-input' %>
|
||||
<%= form.label :account_type_savings, 'Savings', class: 'form-check-label' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= form.label :routing_number, 'Routing Number', class: 'form-label' %>
|
||||
<%= form.text_field :routing_number, class: 'form-control', placeholder: 'Routing Number' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= form.label :routing_number_confirmation, 'Re-enter Routing Number', class: 'form-label' %>
|
||||
<%= form.text_field :routing_number_confirmation, class: 'form-control', placeholder: 'Re-enter Routing Number' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= form.label :account_number, 'Account Number', class: 'form-label' %>
|
||||
<%= form.text_field :account_number, class: 'form-control', placeholder: 'Account Number' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= form.label :account_number_confirmation, 'Re-enter Account Number', class: 'form-label' %>
|
||||
<%= form.text_field :account_number_confirmation, class: 'form-control', placeholder: 'Re-enter Account Number' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= form.label :start_date, 'Start Date', class: 'form-label' %>
|
||||
<%= form.date_field :start_date, class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= form.label :end_date, 'End Date', class: 'form-label' %>
|
||||
<%= form.date_field :end_date, class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= form.submit 'Submit', class: 'btn btn-dark' %>
|
||||
</div>
|
||||
<% end %>
|
|
@ -0,0 +1,2 @@
|
|||
<h1>BankAccounts#create</h1>
|
||||
<p>Find me in app/views/bank_accounts/create.html.erb</p>
|
|
@ -0,0 +1,13 @@
|
|||
<div class="container mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<h1 class="mb-4 text-center">Edit Bank Account</h1>
|
||||
|
||||
<%= render 'form', owner: @owner, bank_account: @bank_account %>
|
||||
|
||||
<div class="mt-3 text-center">
|
||||
<%= link_to 'Back', polymorphic_path(@owner), class: "btn btn-secondary" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,44 @@
|
|||
<div class="container mt-5">
|
||||
<h1 class="mb-4 text-center">Bank Information</h1>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Institution Name</th>
|
||||
<th>Type</th>
|
||||
<th>Routing Number</th>
|
||||
<th>Account Number</th>
|
||||
<th>Start Date</th>
|
||||
<th>End Date</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @bank_accounts.each do |account| %>
|
||||
<tr>
|
||||
<td><%= account.institution_name %></td>
|
||||
<td><%= account.account_type.capitalize %></td>
|
||||
<td><%= account.routing_number %></td>
|
||||
<td><%= hide_account_number(account.account_number) %></td>
|
||||
<td><%= account.start_date.strftime('%B %d, %Y') if account.start_date %></td>
|
||||
<td><%= account.end_date.strftime('%B %d, %Y') if account.end_date %></td>
|
||||
<td>
|
||||
<%= link_to edit_polymorphic_path([@owner, account]), class: 'btn btn-info btn-sm' do %>
|
||||
<i class="bi bi-pencil-fill" style="color: white;"></i>
|
||||
<% end %>
|
||||
<%= link_to polymorphic_path([@owner, account]), method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger btn-sm' do %>
|
||||
<i class="bi bi-trash-fill"></i>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<%= link_to 'Add New Bank Account', new_polymorphic_path([@owner, BankAccount.new]), class: 'btn btn-dark' %>
|
||||
</div>
|
||||
|
||||
<div class="text-center mt-3">
|
||||
<%= link_to 'Back', polymorphic_path(@owner), class: 'btn btn-secondary mt-3' %>
|
||||
</div>
|
||||
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<div class="container mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<h1 class="mb-4 text-center">New Bank Account</h1>
|
||||
|
||||
<%= render 'form', owner: @owner, bank_account: @bank_account %>
|
||||
|
||||
<div class="mt-3 text-center">
|
||||
<%= link_to 'Back', polymorphic_path(@owner), class: "btn btn-secondary" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,2 @@
|
|||
<h1>BankAccounts#update</h1>
|
||||
<p>Find me in app/views/bank_accounts/update.html.erb</p>
|
|
@ -0,0 +1,22 @@
|
|||
<div class="container mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<h2 class="mb-3 text-center">Resend confirmation instructions</h2>
|
||||
|
||||
<%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post, class: 'needs-validation', novalidate: true }) do |f| %>
|
||||
<%= render "devise/shared/error_messages", resource: resource %>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= f.label :email, class: 'form-label' %>
|
||||
<%= f.email_field :email, autofocus: true, autocomplete: "email", value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email), class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="actions text-center">
|
||||
<%= f.submit "Resend confirmation instructions", class: 'btn btn-dark' %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render "devise/shared/links" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,5 @@
|
|||
<p>Welcome <%= @email %>!</p>
|
||||
|
||||
<p>You can confirm your account email through the link below:</p>
|
||||
|
||||
<p><%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %></p>
|
|
@ -0,0 +1,7 @@
|
|||
<p>Hello <%= @email %>!</p>
|
||||
|
||||
<% if @resource.try(:unconfirmed_email?) %>
|
||||
<p>We're contacting you to notify you that your email is being changed to <%= @resource.unconfirmed_email %>.</p>
|
||||
<% else %>
|
||||
<p>We're contacting you to notify you that your email has been changed to <%= @resource.email %>.</p>
|
||||
<% end %>
|
|
@ -0,0 +1,3 @@
|
|||
<p>Hello <%= @resource.email %>!</p>
|
||||
|
||||
<p>We're contacting you to notify you that your password has been changed.</p>
|
|
@ -0,0 +1,8 @@
|
|||
<p>Hello <%= @resource.email %>!</p>
|
||||
|
||||
<p>Someone has requested a link to change your password. You can do this through the link below.</p>
|
||||
|
||||
<p><%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %></p>
|
||||
|
||||
<p>If you didn't request this, please ignore this email.</p>
|
||||
<p>Your password won't change until you access the link above and create a new one.</p>
|
|
@ -0,0 +1,7 @@
|
|||
<p>Hello <%= @resource.email %>!</p>
|
||||
|
||||
<p>Your account has been locked due to an excessive number of unsuccessful sign in attempts.</p>
|
||||
|
||||
<p>Click the link below to unlock your account:</p>
|
||||
|
||||
<p><%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %></p>
|
|
@ -0,0 +1,32 @@
|
|||
<div class="container mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<h2 class="mb-3 text-center">Change your password</h2>
|
||||
|
||||
<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put, class: 'needs-validation', novalidate: true }) do |f| %>
|
||||
<%= render "devise/shared/error_messages", resource: resource %>
|
||||
<%= f.hidden_field :reset_password_token %>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= f.label :password, "New password", class: 'form-label' %>
|
||||
<% if @minimum_password_length %>
|
||||
<em>(<%= @minimum_password_length %> characters minimum)</em><br />
|
||||
<% end %>
|
||||
<%= f.password_field :password, autofocus: true, autocomplete: "new-password", class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= f.label :password_confirmation, "Confirm new password", class: 'form-label' %>
|
||||
<%= f.password_field :password_confirmation, autocomplete: "new-password", class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="actions text-center">
|
||||
<%= f.submit "Change my password", class: 'btn btn-dark' %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render "devise/shared/links" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<div class="container mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<h2 class="mb-3 text-center">Forgot your password?</h2>
|
||||
|
||||
<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post, class: 'needs-validation', novalidate: true }) do |f| %>
|
||||
<%= render "devise/shared/error_messages", resource: resource %>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= f.label :email, class: 'form-label' %>
|
||||
<%= f.email_field :email, autofocus: true, autocomplete: "email", class: 'form-control', placeholder: 'Enter email' %>
|
||||
</div>
|
||||
|
||||
<div class="actions text-center">
|
||||
<%= f.submit "Send me reset password instructions", class: 'btn btn-dark' %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render "devise/shared/links" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,48 @@
|
|||
<div class="container mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<h2 class="mb-3 text-center">Edit <%= resource_name.to_s.humanize %></h2>
|
||||
|
||||
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put, class: 'needs-validation', novalidate: true }) do |f| %>
|
||||
<%= render "devise/shared/error_messages", resource: resource %>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= f.label :email, class: 'form-label' %>
|
||||
<%= f.email_field :email, autofocus: true, autocomplete: "email", class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
|
||||
<div class="alert alert-info">Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
|
||||
<% end %>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= f.label :password, class: 'form-label' %> <i>(leave blank if you don't want to change it)</i>
|
||||
<%= f.password_field :password, autocomplete: "new-password", class: 'form-control' %>
|
||||
<% if @minimum_password_length %>
|
||||
<small class="form-text text-muted"><%= @minimum_password_length %> characters minimum</small>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= f.label :password_confirmation, class: 'form-label' %>
|
||||
<%= f.password_field :password_confirmation, autocomplete: "new-password", class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= f.label :current_password, class: 'form-label' %> <i>(we need your current password to confirm your changes)</i>
|
||||
<%= f.password_field :current_password, autocomplete: "current-password", class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="actions text-center">
|
||||
<%= f.submit "Update", class: 'btn btn-dark' %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<h3 class="mt-4">Cancel my account</h3>
|
||||
<p>Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?", turbo_confirm: "Are you sure?" }, method: :delete, class: 'btn btn-danger' %></p>
|
||||
|
||||
<%= link_to "Back", :back, class: 'btn btn-secondary' %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
<div class="container mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<h2 class="mb-3 text-center">Sign up</h2>
|
||||
|
||||
<%= form_with(model: resource, as: resource_name, url: registration_path(resource_name), local: true, html: { class: 'needs-validation', novalidate: true }) do |f| %>
|
||||
<%= render "devise/shared/error_messages", resource: resource %>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= f.label :email, class: 'form-label' %>
|
||||
<%= f.email_field :email, autofocus: true, autocomplete: "email", class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= f.label :password, class: 'form-label' %>
|
||||
<%= f.password_field :password, autocomplete: "new-password", class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= f.label :password_confirmation, class: 'form-label' %>
|
||||
<%= f.password_field :password_confirmation, autocomplete: "new-password", class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="actions text-center">
|
||||
<%= f.submit "Sign up", class: 'btn btn-dark' %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render "devise/shared/links" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,32 @@
|
|||
<div class="container mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<h2 class="mb-3 text-center">Log in</h2>
|
||||
|
||||
<%= form_with(model: resource, as: resource_name, url: user_session_path, local: true, html: { class: 'needs-validation', novalidate: true }) do |f| %>
|
||||
<div class="mb-3">
|
||||
<%= f.label :email, class: 'form-label' %>
|
||||
<%= f.email_field :email, autofocus: true, autocomplete: "email", class: 'form-control', placeholder: 'Enter email' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= f.label :password, class: 'form-label' %>
|
||||
<%= f.password_field :password, autocomplete: "current-password", class: 'form-control', placeholder: 'Password' %>
|
||||
</div>
|
||||
|
||||
<% if devise_mapping.rememberable? %>
|
||||
<div class="mb-3 form-check">
|
||||
<%= f.check_box :remember_me, class: 'form-check-input' %>
|
||||
<%= f.label :remember_me, class: 'form-check-label' %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="actions text-center">
|
||||
<%= f.submit "Log in", class: 'btn btn-dark' %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render "devise/shared/links" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,15 @@
|
|||
<% if resource.errors.any? %>
|
||||
<div id="error_explanation" class="alert alert-danger" role="alert" data-turbo-cache="false">
|
||||
<h4 class="alert-heading">
|
||||
<%= I18n.t("errors.messages.not_saved",
|
||||
count: resource.errors.count,
|
||||
resource: resource.class.model_name.human.downcase)
|
||||
%>
|
||||
</h4>
|
||||
<ul>
|
||||
<% resource.errors.full_messages.each do |message| %>
|
||||
<li><%= message %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
|
@ -0,0 +1,26 @@
|
|||
<div class="container mt-3">
|
||||
<div class="d-flex flex-column align-items-start">
|
||||
<%- if controller_name != 'sessions' %>
|
||||
<%= link_to "Log in", new_session_path(resource_name), class: "btn btn-link" %>
|
||||
<% end %>
|
||||
|
||||
<%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
|
||||
<%= link_to "Forgot your password?", new_user_password_path(resource_name), class: "btn btn-link" %>
|
||||
<% end %>
|
||||
|
||||
<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
|
||||
<%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name), class: "btn btn-link" %>
|
||||
<% end %>
|
||||
|
||||
<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
|
||||
<%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name), class: "btn btn-link" %>
|
||||
<% end %>
|
||||
|
||||
<%- if devise_mapping.omniauthable? %>
|
||||
<%- resource_class.omniauth_providers.each do |provider| %>
|
||||
<%= button_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), data: { turbo: false }, class: "btn btn-primary mb-2" %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<div class="container mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<h2 class="mb-3 text-center">Resend unlock instructions</h2>
|
||||
|
||||
<%= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post, class: 'needs-validation', novalidate: true }) do |f| %>
|
||||
<%= render "devise/shared/error_messages", resource: resource %>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= f.label :email, class: 'form-label' %>
|
||||
<%= f.email_field :email, autofocus: true, autocomplete: "email", class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="actions text-center">
|
||||
<%= f.submit "Resend unlock instructions", class: 'btn btn-primary' %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render "devise/shared/links" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<div class="container mt-5">
|
||||
<h1>Edit Employer Record</h1>
|
||||
|
||||
<%= form_with(model: @employer_record, class: 'form') do |form| %>
|
||||
<% if @employer_record.errors.any? %>
|
||||
<div id="error_explanation">
|
||||
<h2><%= pluralize(@employer_record.errors.count, "error") %> prohibited this employer record from being saved:</h2>
|
||||
<ul>
|
||||
<% @employer_record.errors.full_messages.each do |message| %>
|
||||
<li><%= message %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="field">
|
||||
<%= form.label :participant_id %>
|
||||
<%= form.number_field :participant_id, class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<%= form.label :employer_id %>
|
||||
<%= form.number_field :employer_id, class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<%= form.label :start_date %>
|
||||
<%= form.date_field :start_date, class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<%= form.label :end_date %>
|
||||
<%= form.date_field :end_date, class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= form.submit 'Save Changes', class: 'btn btn-primary' %>
|
||||
<%= link_to 'Delete Record', employer_record_path(@employer_record),
|
||||
method: :delete,
|
||||
data: { confirm: 'Are you sure?' },
|
||||
class: 'btn btn-danger' %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
|
||||
</div>
|
|
@ -0,0 +1,162 @@
|
|||
<%= form_with(model: employer, local: true, html: { class: 'needs-validation', novalidate: true }) do |form| %>
|
||||
<% if employer.errors.any? %>
|
||||
<div id="error_explanation" class="alert alert-danger" role="alert">
|
||||
<h4><%= pluralize(employer.errors.count, "error") %> prohibited this employer from being saved:</h4>
|
||||
<ul>
|
||||
<% employer.errors.full_messages.each do |message| %>
|
||||
<li><%= message %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= form.label :first_name, 'First Name', class: 'form-label' %>
|
||||
<%= form.text_field :first_name, class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= form.label :last_name, 'Last Name', class: 'form-label' %>
|
||||
<%= form.text_field :last_name, class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= form.label :address_line_1, 'Address Line 1' %>
|
||||
<%= form.text_field :address_line_1, class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= form.label :address_line_2, 'Address Line 2' %>
|
||||
<%= form.text_field :address_line_2, class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= form.label :city %>
|
||||
<%= form.text_field :city, class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= form.label :state %>
|
||||
<%= form.text_field :state, class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= form.label :zip, 'ZIP' %>
|
||||
<%= form.text_field :zip, class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= form.label :phone, class: 'form-label' %>
|
||||
<%= form.telephone_field :phone, id: 'phone-field', class: 'form-control', placeholder: '(XXX)-XX-XXXX' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= form.label :email, class: 'form-label' %>
|
||||
<%= form.email_field :email, id: 'email-field', class: 'form-control', required: true, placeholder: 'Make sure to include @ sign' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= form.label :tin, 'TIN', class: 'form-label' %>
|
||||
<%= form.text_field :tin, id: 'tin-field', class: 'form-control', maxlength: 10, placeholder: 'XX-XXXXXXX' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= form.label :dob, 'Date of Birth', class: 'form-label' %>
|
||||
<%= form.date_field :dob, class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= form.label :ssn, 'Social Security Number', class: 'form-label' %>
|
||||
<%= form.text_field :ssn, id: 'ssn-field', class: 'form-control', maxlength: 11, placeholder: 'XXX-XX-XXXX' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= form.label :gender, class: 'form-label' %>
|
||||
<%= form.select :gender, ['Unknown', 'Female', 'Male', 'Non-Binary', 'Other'], {}, { class: 'form-select' } %>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= form.submit class: 'btn btn-dark' %>
|
||||
</div>
|
||||
|
||||
|
||||
<% end %>
|
||||
|
||||
|
||||
|
||||
<%# This is to correct phone number entry %>
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
const phoneField = document.getElementById('phone-field');
|
||||
|
||||
phoneField.addEventListener('input', function() {
|
||||
let input = phoneField.value.replace(/\D/g, ''); // Remove non-numeric characters
|
||||
const inputLength = input.length;
|
||||
|
||||
if (inputLength > 3 && inputLength <= 6) {
|
||||
input = `(${input.slice(0, 3)}) ${input.slice(3)}`;
|
||||
} else if (inputLength > 6) {
|
||||
input = `(${input.slice(0, 3)}) ${input.slice(3, 6)}-${input.slice(6, 10)}`;
|
||||
}
|
||||
|
||||
phoneField.value = input;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<%# This is for auto resizing the address field %>
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
const textareas = document.querySelectorAll('.auto-expand');
|
||||
|
||||
const resizeTextarea = function(el) {
|
||||
el.style.height = 'auto';
|
||||
el.style.height = (el.scrollHeight) + 'px';
|
||||
}
|
||||
|
||||
textareas.forEach(textarea => {
|
||||
textarea.addEventListener('input', function() {
|
||||
resizeTextarea(textarea);
|
||||
});
|
||||
|
||||
// Initial resize
|
||||
resizeTextarea(textarea);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<%# This is for Social Security formatting and # of digits %>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const ssnField = document.getElementById('ssn-field');
|
||||
|
||||
ssnField.addEventListener('input', () => {
|
||||
let ssn = ssnField.value.split('-').join(''); // Remove dashes
|
||||
ssn = ssn.replace(/\D/g, ''); // Keep numbers only
|
||||
|
||||
if (ssn.length > 3 && ssn.length <= 5) {
|
||||
ssn = ssn.slice(0, 3) + '-' + ssn.slice(3);
|
||||
} else if (ssn.length > 5) {
|
||||
ssn = ssn.slice(0, 3) + '-' + ssn.slice(3, 5) + '-' + ssn.slice(5, 9);
|
||||
}
|
||||
ssnField.value = ssn; // Update the field value
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<%# This is to format the TIN correctly %>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const tinField = document.getElementById('tin-field');
|
||||
|
||||
tinField.addEventListener('input', () => {
|
||||
let tin = tinField.value.split('-').join(''); // Remove dashes
|
||||
tin = tin.replace(/\D/g, ''); // Keep numbers only
|
||||
|
||||
if (tin.length > 2) {
|
||||
tin = tin.slice(0, 2) + '-' + tin.slice(2, 9);
|
||||
}
|
||||
tinField.value = tin; // Update the field value
|
||||
});
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,14 @@
|
|||
<div class="container mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<h1 class="mb-4 text-center">Edit Employer</h1>
|
||||
|
||||
<%= render 'form', employer: @employer %>
|
||||
|
||||
<div class="mt-3 d-flex justify-content-between">
|
||||
<%= link_to 'Back to List', employers_path, class: "btn btn-secondary" %>
|
||||
<%= link_to 'Destroy', @employer, method: :delete, data: { confirm: 'Are you sure?' }, class: "btn btn-danger" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,43 @@
|
|||
<div class="container mt-5">
|
||||
<h1 class="mb-4 text-center">Employers</h1>
|
||||
|
||||
<div class="text-center mt-3">
|
||||
<%= link_to 'New Employer', new_employer_path, class: 'btn btn-dark mb-3' %>
|
||||
</div>
|
||||
|
||||
<%= paginate @employers %>
|
||||
|
||||
<table class="table table-striped table-hover">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>First Name</th>
|
||||
<th>Last Name</th>
|
||||
<th>Address</th>
|
||||
<th>Phone</th>
|
||||
<th>Email</th>
|
||||
<th>DOB</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @employers.each do |employer| %>
|
||||
<tr>
|
||||
<td><%= employer.first_name %></td>
|
||||
<td><%= employer.last_name %></td>
|
||||
<td><%= [employer.address_line_1, employer.address_line_2, employer.city, employer.state, employer.zip].reject(&:blank?).join(', ') %></td>
|
||||
<td><%= employer.phone %></td>
|
||||
<td><%= employer.email %></td>
|
||||
<td><%= employer.dob.strftime('%B %d, %Y') if employer.dob %></td>
|
||||
<td>
|
||||
<%= link_to employer, class: 'btn btn-sm btn-secondary' do %>
|
||||
<i class="bi bi-eye"></i><!-- Eyeball icon for 'Show' -->
|
||||
<% end %>
|
||||
<%= link_to edit_employer_path(employer), class: 'btn btn-sm btn-info' do %>
|
||||
<i class="bi bi-pencil-fill" style="color: white;"></i> <!-- Pencil icon for 'Edit' with white color -->
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
|
@ -0,0 +1,13 @@
|
|||
<div class="container mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<h1 class="mb-4 text-center">New Employer</h1>
|
||||
|
||||
<%= render 'form', employer: @employer %>
|
||||
|
||||
<div class="mt-3 text-center">
|
||||
<%= link_to 'Back to List', employers_path, class: "btn btn-secondary" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,252 @@
|
|||
<div class="dropdown">
|
||||
<button class="btn btn-secondary dropdown-toggle" type="button" id="demographicsDropdown" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
Demographics
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="demographicsDropdown">
|
||||
<li><a class="dropdown-item" href="<%= polymorphic_path([@employer, :onboardings]) %>">Onboarding</a></li>
|
||||
<!-- Add other links as needed -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container mt-5">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h1 class="mb-4 text-center">Employer Details</h1>
|
||||
</div>
|
||||
|
||||
<!-- Employer Information Table -->
|
||||
<div class="col-12 mb-4">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<td><%= @employer.first_name %> <%= @employer.last_name %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Address</th>
|
||||
<td>
|
||||
<%= @employer.address_line_1 %><%= ', ' + @employer.address_line_2 unless @employer.address_line_2.blank? %>
|
||||
<br>
|
||||
<%= "#{@employer.city}, #{@employer.state} #{@employer.zip}" %>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Phone</th>
|
||||
<td><%= @employer.phone %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Email</th>
|
||||
<td><%= @employer.email %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>TIN</th>
|
||||
<td><%= @employer.tin %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>DOB</th>
|
||||
<td><%= @employer.dob.strftime('%B %d, %Y') if @employer.dob.present? %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>SSN</th>
|
||||
<td><%= mask_ssn(@employer.ssn) %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Gender</th>
|
||||
<td><%= @employer.gender %></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="row">
|
||||
<div class="col-12 d-flex justify-content-between mb-4">
|
||||
<%= link_to 'Edit', edit_employer_path(@employer), class: "btn btn-dark" %>
|
||||
<%= link_to 'Back to List', employers_path, class: "btn btn-secondary" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="container mt-5">
|
||||
<div class="row">
|
||||
<!-- Linked Participants Section -->
|
||||
<div class="col-md-6">
|
||||
<h2 class="mt-4">Linked Participants</h2>
|
||||
<% if @employer.employer_records.any? %>
|
||||
<table class="table table-striped">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Participant Name</th>
|
||||
<th>Start Date</th>
|
||||
<th>End Date</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @employer.employer_records.each do |employer_record| %>
|
||||
<tr>
|
||||
<% participant = employer_record.participant %>
|
||||
<td><%= "#{participant.first_name} #{participant.last_name}" %></td>
|
||||
<td><%= employer_record.start_date.strftime('%B %d, %Y') if employer_record.start_date %></td>
|
||||
<td><%= employer_record.end_date.strftime('%B %d, %Y') if employer_record.end_date %></td>
|
||||
<td>
|
||||
<%= link_to participant_path(participant), class: 'btn btn-sm btn-secondary' do %>
|
||||
<i class="bi bi-eye"></i> <!-- Eyeball icon for 'Show' -->
|
||||
<% end %>
|
||||
<%= link_to edit_employer_record_path(employer_record), class: 'btn btn-sm btn-info' do %>
|
||||
<i class="bi bi-pencil-fill" style="color: white;"></i> <!-- Pencil icon for 'Edit' with white color -->
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% else %>
|
||||
<p>No linked participants.</p>
|
||||
<% end %>
|
||||
|
||||
|
||||
<%= form_with(model: [@employer, EmployerRecord.new], url: link_participant_employer_records_path, method: :post, class: 'row g-3') do |form| %>
|
||||
<div class="col-md-6">
|
||||
<%= form.label :participant_name, "Add New Participant", class: 'form-label' %>
|
||||
<%= text_field_tag :participant_name, nil, id: 'participant-autocomplete', class: 'form-control', placeholder: 'Start typing participant name...' %>
|
||||
<%= hidden_field_tag 'employer_record[participant_id]', nil, id: 'selected-participant-id' %>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3">
|
||||
<%= form.label :start_date, class: 'form-label' %>
|
||||
<%= form.date_field :start_date, class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3">
|
||||
<%= form.label :end_date, class: 'form-label' %>
|
||||
<%= form.date_field :end_date, class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<%= form.submit "Link Participant", class: 'btn btn-dark' %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<h2 class="mt-4">Linked Workers</h2>
|
||||
<% if @employer.workers.any? %>
|
||||
<table class="table table-striped">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Worker Name</th>
|
||||
<th>Start Date</th>
|
||||
<th>End Date</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @employer.workers.each do |worker| %>
|
||||
<% worker.employments.joins(:participant).where(participants: { employer_id: @employer.id }).each do |employment| %>
|
||||
<tr>
|
||||
<td><%= worker.full_name %></td>
|
||||
<td><%= employment.start_date.strftime('%B %d, %Y') if employment.start_date %></td>
|
||||
<td><%= employment.end_date.strftime('%B %d, %Y') if employment.end_date %></td>
|
||||
<td>
|
||||
<%= link_to worker_path(worker), class: 'btn btn-sm btn-secondary' do %>
|
||||
<i class="bi bi-eye"></i> <!-- Eyeball icon for 'Show' -->
|
||||
<% end %>
|
||||
<%= link_to edit_employment_path(employment), class: 'btn btn-sm btn-info' do %>
|
||||
<i class="bi bi-pencil-fill" style="color: white;"></i> <!-- Pencil icon for 'Edit' with white color -->
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% else %>
|
||||
<p>No linked workers.</p>
|
||||
<% end %>
|
||||
|
||||
<%= form_with(model: EmployerRecord.new, url: link_worker_employer_path(@employer), method: :post, class: 'row g-3') do |form| %>
|
||||
<div class="col-md-6">
|
||||
<%= form.label :worker_name, "Add New Worker", class: 'form-label' %>
|
||||
<%= text_field_tag :worker_name, nil, id: 'worker-autocomplete', class: 'form-control', placeholder: 'Start typing worker name...' %>
|
||||
<%= hidden_field_tag 'employer_record[worker_id]', nil, id: 'selected-worker-id' %>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3">
|
||||
<%= form.label :start_date, class: 'form-label' %>
|
||||
<%= form.date_field :start_date, class: 'form-control', name: 'employer_record[start_date]' %>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3">
|
||||
<%= form.label :end_date, class: 'form-label' %>
|
||||
<%= form.date_field :end_date, class: 'form-control', name: 'employer_record[end_date]' %>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<%= form.submit "Link Worker", class: 'btn btn-dark' %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<%# JavaScript for Participant Autocomplete %>
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<script src="https://code.jquery.com/ui/1.13.0/jquery-ui.min.js"></script>
|
||||
<link rel="stylesheet" href="//code.jquery.com/ui/1.13.0/themes/base/jquery-ui.css">
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#participant-autocomplete').autocomplete({
|
||||
source: function(request, response) {
|
||||
$.ajax({
|
||||
url: '/participants/search', // Updated endpoint for searching participants
|
||||
dataType: "json",
|
||||
data: { term: request.term },
|
||||
success: function(data) {
|
||||
response(data);
|
||||
}
|
||||
});
|
||||
},
|
||||
minLength: 2, // Minimum characters to trigger the search
|
||||
select: function(event, ui) {
|
||||
// Function to handle selection
|
||||
$('#participant-autocomplete').val(ui.item.label); // ui.item.label should contain the name of the participant
|
||||
$('#selected-participant-id').val(ui.item.value); // Set the participant ID in the hidden field
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<%# JavaScript for Worker Autocomplete %>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#worker-autocomplete').autocomplete({
|
||||
source: function(request, response) {
|
||||
$.ajax({
|
||||
url: '/workers/search', // Endpoint for searching workers
|
||||
dataType: "json",
|
||||
data: { term: request.term },
|
||||
success: function(data) {
|
||||
response(data);
|
||||
}
|
||||
});
|
||||
},
|
||||
minLength: 2, // Minimum characters to trigger the search
|
||||
select: function(event, ui) {
|
||||
// Function to handle selection
|
||||
$('#worker-autocomplete').val(ui.item.label); // Worker's name
|
||||
$('#selected-worker-id').val(ui.item.value); // Worker's ID
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
<div class="container mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<h1 class="mb-4 text-center">Edit Employment</h1>
|
||||
|
||||
<%= form_with(model: @employment, url: employment_path(@employment), method: :patch, local: true, html: { class: 'needs-validation', novalidate: true }) do |form| %>
|
||||
<% if @employment.errors.any? %>
|
||||
<div id="error_explanation" class="alert alert-danger" role="alert">
|
||||
<h4><%= pluralize(@employment.errors.count, "error") %> prohibited this employment from being saved:</h4>
|
||||
<ul>
|
||||
<% @employment.errors.full_messages.each do |message| %>
|
||||
<li><%= message %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= form.label :start_date, class: 'form-label' %>
|
||||
<%= form.date_field :start_date, class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= form.label :end_date, class: 'form-label' %>
|
||||
<%= form.date_field :end_date, class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= form.submit "Update Employment", class: 'btn btn-dark' %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="mt-3 d-flex justify-content-between">
|
||||
<%= link_to 'Back to Participant', participant_path(@employment.participant), class: 'btn btn-secondary' %>
|
||||
<%= link_to 'Delete Employment', employment_path(@employment), method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger' %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,36 @@
|
|||
<%= form_with(model: form, local: true, html: { class: 'needs-validation', novalidate: true }) do |f| %>
|
||||
<% if form.errors.any? %>
|
||||
<div id="error_explanation" class="alert alert-danger">
|
||||
<h4><%= pluralize(form.errors.count, "error") %> prohibited this form from being saved:</h4>
|
||||
<ul>
|
||||
<% form.errors.full_messages.each do |message| %>
|
||||
<li><%= message %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= f.label :name, 'Form Name', class: 'form-label' %>
|
||||
<%= f.text_field :name, class: 'form-control', placeholder: 'Enter form name' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= f.label :required, 'Required', class: 'form-label' %>
|
||||
<%= f.check_box :required, class: 'form-check-input' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= f.label :program, 'Program', class: 'form-label' %>
|
||||
<%= f.text_field :program, class: 'form-control', placeholder: 'Enter program name' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= f.label :form_role_ids, 'Roles', class: 'form-label' %>
|
||||
<%= f.collection_select :form_role_ids, FormRole.all, :id, :name, {}, { multiple: true, class: "form-control" } %>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= f.submit 'Save', class: 'btn btn-dark' %>
|
||||
</div>
|
||||
<% end %>
|
|
@ -0,0 +1,2 @@
|
|||
<h1>Forms#create</h1>
|
||||
<p>Find me in app/views/forms/create.html.erb</p>
|
|
@ -0,0 +1,2 @@
|
|||
<h1>Forms#destroy</h1>
|
||||
<p>Find me in app/views/forms/destroy.html.erb</p>
|
|
@ -0,0 +1,13 @@
|
|||
<div class="container mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<h1 class="mb-4 text-center">Edit Form</h1>
|
||||
|
||||
<%= render 'form', form: @form %>
|
||||
|
||||
<div class="mt-3 text-center">
|
||||
<%= link_to 'Back to List', forms_path, class: "btn btn-secondary" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,38 @@
|
|||
<div class="container mt-5">
|
||||
<h1 class="mb-4 text-center">Forms</h1>
|
||||
|
||||
<div class="text-center mt-3">
|
||||
<%= link_to 'New Form', new_form_path, class: 'btn btn-dark mb-3' %>
|
||||
</div>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Form Name</th>
|
||||
<th>Required/Optional</th>
|
||||
<th>Program</th>
|
||||
<th>Who/Role</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @forms.each do |form| %>
|
||||
<tr>
|
||||
<td><%= form.name %></td>
|
||||
<td><%= form.required ? 'Required' : 'Optional' %></td>
|
||||
<td><%= form.program %></td>
|
||||
<td><%= form.form_roles.map(&:name).join(", ") %></td>
|
||||
<td>
|
||||
<%= link_to edit_form_path(form), class: 'btn btn-info btn-sm' do %>
|
||||
<i class="bi bi-pencil-fill" style="color: white;"></i>
|
||||
<% end %>
|
||||
<%= link_to form, method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger btn-sm' do %>
|
||||
<i class="bi bi-trash-fill"></i>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<div class="container mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<h1 class="mb-4 text-center">New Form</h1>
|
||||
|
||||
<%= render 'form', form: @form %>
|
||||
|
||||
<div class="mt-3 text-center">
|
||||
<%= link_to 'Back to List', forms_path, class: "btn btn-secondary" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,30 @@
|
|||
<div class="container mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h1 class="card-title"><%= @form.name %></h1>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="card-text">
|
||||
<strong>Required/Optional:</strong>
|
||||
<%= @form.required ? 'Required' : 'Optional' %>
|
||||
</p>
|
||||
<p class="card-text">
|
||||
<strong>Program:</strong>
|
||||
<%= @form.program %>
|
||||
</p>
|
||||
<p class="card-text">
|
||||
<strong>Who/Role:</strong>
|
||||
<%# Assuming you have adjusted @form.role to handle multiple roles %>
|
||||
<%= @form.roles.map(&:name).join(', ') %>
|
||||
</p>
|
||||
</div>
|
||||
<div class="card-footer text-muted d-flex justify-content-between">
|
||||
<%= link_to 'Edit', edit_form_path(@form), class: 'btn btn-info' %>
|
||||
<%= link_to 'Back to Forms', forms_path, class: 'btn btn-secondary' %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,2 @@
|
|||
<h1>Forms#update</h1>
|
||||
<p>Find me in app/views/forms/update.html.erb</p>
|
|
@ -1,3 +1,4 @@
|
|||
<h1>Home#index</h1>
|
||||
<p>Hi Mariam. This is me. You should know this as you are sitting next to me.</p>
|
||||
<p>Boy I have a hard time remembering anything!</p>
|
||||
<p>Boy I have a hard time remembering anything!</p>
|
||||
<p>You are all nerds and I am the SUPREME BEING! - Not said by Jonathan :)</p>
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<%# Link to the "First" page
|
||||
- available local variables
|
||||
url: url to the first page
|
||||
current_page: a page object for the currently displayed page
|
||||
total_pages: total number of pages
|
||||
per_page: number of items to fetch per page
|
||||
remote: data-remote
|
||||
-%>
|
||||
<span class="first">
|
||||
<%= link_to_unless current_page.first?, t('views.pagination.first').html_safe, url, remote: remote %>
|
||||
</span>
|
|
@ -0,0 +1,8 @@
|
|||
<%# Non-link tag that stands for skipped pages...
|
||||
- available local variables
|
||||
current_page: a page object for the currently displayed page
|
||||
total_pages: total number of pages
|
||||
per_page: number of items to fetch per page
|
||||
remote: data-remote
|
||||
-%>
|
||||
<span class="page gap"><%= t('views.pagination.truncate').html_safe %></span>
|
|
@ -0,0 +1,11 @@
|
|||
<%# Link to the "Last" page
|
||||
- available local variables
|
||||
url: url to the last page
|
||||
current_page: a page object for the currently displayed page
|
||||
total_pages: total number of pages
|
||||
per_page: number of items to fetch per page
|
||||
remote: data-remote
|
||||
-%>
|
||||
<span class="last">
|
||||
<%= link_to_unless current_page.last?, t('views.pagination.last').html_safe, url, remote: remote %>
|
||||
</span>
|
|
@ -0,0 +1,11 @@
|
|||
<%# Link to the "Next" page
|
||||
- available local variables
|
||||
url: url to the next page
|
||||
current_page: a page object for the currently displayed page
|
||||
total_pages: total number of pages
|
||||
per_page: number of items to fetch per page
|
||||
remote: data-remote
|
||||
-%>
|
||||
<span class="next">
|
||||
<%= link_to_unless current_page.last?, t('views.pagination.next').html_safe, url, rel: 'next', remote: remote %>
|
||||
</span>
|
|
@ -0,0 +1,12 @@
|
|||
<%# Link showing page number
|
||||
- available local variables
|
||||
page: a page object for "this" page
|
||||
url: url to this page
|
||||
current_page: a page object for the currently displayed page
|
||||
total_pages: total number of pages
|
||||
per_page: number of items to fetch per page
|
||||
remote: data-remote
|
||||
-%>
|
||||
<span class="page<%= ' current' if page.current? %>">
|
||||
<%= link_to_unless page.current?, page, url, {remote: remote, rel: page.rel} %>
|
||||
</span>
|
|
@ -0,0 +1,35 @@
|
|||
<%# The container tag
|
||||
- available local variables
|
||||
current_page: a page object for the currently displayed page
|
||||
total_pages: total number of pages
|
||||
per_page: number of items to fetch per page
|
||||
remote: data-remote
|
||||
paginator: the paginator that renders the pagination tags inside
|
||||
-%>
|
||||
<%= paginator.render do -%>
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination">
|
||||
<li class="page-item <%= 'disabled' if current_page.first? %>">
|
||||
<%= link_to 'First', participants_path(page: 1), class: 'page-link bg-secondary text-white' unless current_page.first? %>
|
||||
</li>
|
||||
<li class="page-item <%= 'disabled' if current_page.first? %>">
|
||||
<%= link_to 'Previous', participants_path(page: current_page.number - 1), class: 'page-link bg-secondary text-white' unless current_page.first? %>
|
||||
</li>
|
||||
<% each_page do |page| -%>
|
||||
<% if page.display_tag? -%>
|
||||
<li class="page-item <%= 'active' if page.number == current_page.number %>">
|
||||
<%= link_to page.number, participants_path(page: page.number), class: 'page-link bg-secondary text-white' %>
|
||||
</li>
|
||||
<% elsif !page.was_truncated? -%>
|
||||
<li class="page-item disabled"><span class="page-link bg-secondary text-white">…</span></li>
|
||||
<% end -%>
|
||||
<% end -%>
|
||||
<li class="page-item <%= 'disabled' if current_page.last? %>">
|
||||
<%= link_to 'Next', participants_path(page: current_page.number + 1), class: 'page-link bg-secondary text-white' unless current_page.last? %>
|
||||
</li>
|
||||
<li class="page-item <%= 'disabled' if current_page.last? %>">
|
||||
<%= link_to 'Last', participants_path(page: total_pages), class: 'page-link bg-secondary text-white' unless current_page.last? %>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<% end -%>
|
|
@ -0,0 +1,11 @@
|
|||
<%# Link to the "Previous" page
|
||||
- available local variables
|
||||
url: url to the previous page
|
||||
current_page: a page object for the currently displayed page
|
||||
total_pages: total number of pages
|
||||
per_page: number of items to fetch per page
|
||||
remote: data-remote
|
||||
-%>
|
||||
<span class="prev">
|
||||
<%= link_to_unless current_page.first?, t('views.pagination.previous').html_safe, url, rel: 'prev', remote: remote %>
|
||||
</span>
|
|
@ -0,0 +1,48 @@
|
|||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<div class="container-fluid">
|
||||
<%= link_to 'Home', root_path, class: 'navbar-brand' %>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto mb-2 mb-lg-0">
|
||||
<!-- Existing links -->
|
||||
<li class="nav-item">
|
||||
<%= link_to 'Participants', participants_path, class: 'nav-link' %>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<%= link_to 'Employers', employers_path, class: 'nav-link' %>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<%= link_to 'Workers', workers_path, class: 'nav-link' %>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<%= link_to 'Vendors', vendors_path, class: 'nav-link' %>
|
||||
</li>
|
||||
|
||||
<!-- Admin Dropdown Menu -->
|
||||
<% if user_signed_in? && current_user.has_role?(:admin) %>
|
||||
<li class="nav-item dropdown">
|
||||
<%= link_to 'Admin', '#', class: 'nav-link dropdown-toggle', id: 'adminDropdown', role: 'button', data: { bs_toggle: 'dropdown' }, aria: { haspopup: 'true', expanded: 'false' } %>
|
||||
<ul class="dropdown-menu" aria-labelledby="adminDropdown">
|
||||
<li><%= link_to 'Forms', forms_path, class: 'dropdown-item' %></li>
|
||||
<li><%= link_to 'Users', users_path, class: 'dropdown-item' %></li>
|
||||
</ul>
|
||||
</li>
|
||||
<% end %>
|
||||
|
||||
|
||||
<!-- Authentication links -->
|
||||
<% if user_signed_in? %>
|
||||
<li class="nav-item">
|
||||
<%= link_to 'Sign Out', destroy_user_session_path, method: :delete, class: 'nav-link' %>
|
||||
</li>
|
||||
<% else %>
|
||||
<li class="nav-item">
|
||||
<%= link_to 'Sign In', new_user_session_path, class: 'nav-link' %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
|
@ -1,16 +1,52 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Obdev</title>
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
|
||||
<%= csrf_meta_tags %>
|
||||
<%= csp_meta_tag %>
|
||||
|
||||
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
|
||||
<%= javascript_importmap_tags %>
|
||||
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
|
||||
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
|
||||
<%= javascript_include_tag 'rails-ujs', 'data-turbolinks-track': 'reload' %>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<%= yield %>
|
||||
<body class="bg-light-grey">
|
||||
|
||||
<% if user_signed_in? %>
|
||||
<%= render 'layouts/navbar' %>
|
||||
<% end %>
|
||||
|
||||
<div class="container mt-4">
|
||||
<%= yield %>
|
||||
</div>
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
<% if notice %>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-auto">
|
||||
<div class="alert alert-info" role="alert"><%= notice %></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if alert %>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-auto">
|
||||
<div class="alert alert-warning" role="alert"><%= alert %></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
<div class="container mt-5">
|
||||
<h1 class="mb-4 text-center">Onboarding</h1>
|
||||
</div>
|
||||
|
||||
<%= form_with(model: [@owner, OnboardingItem.new], url: submit_onboarding_polymorphic_path(@owner), local: true, html: { class: 'needs-validation', novalidate: true }) do |form| %>
|
||||
<table class="table">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Form Name</th>
|
||||
<th>Notes</th>
|
||||
<th>Date Completed</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @onboarding_items.each_with_index do |item, index| %>
|
||||
<tr>
|
||||
<td><%= item.form.name %></td>
|
||||
<td>
|
||||
<%= text_area_tag "onboarding_items[#{index}][note]", item.note, id: "onboarding_items_#{index}_note", class: "form-control", rows: 1 %>
|
||||
</td>
|
||||
<td>
|
||||
<%= date_field_tag "onboarding_items[#{index}][date_completed]", item.date_completed, id: "onboarding_items_#{index}_date_completed", class: "form-control" %>
|
||||
</td>
|
||||
<%= hidden_field_tag "onboarding_items[#{index}][id]", item.id %>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="actions mt-4">
|
||||
<%= form.submit 'Save', class: 'btn btn-dark' %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="mt-3 text-center">
|
||||
<%= link_to 'Back', polymorphic_path(@owner), class: 'btn btn-secondary' %>
|
||||
</div>
|
||||
|
||||
|
||||
<%# This is for resizing Notes area %>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.querySelectorAll('textarea.form-control').forEach(function(textarea) {
|
||||
function autoResize() {
|
||||
// Reset height to ensure shrinking if text is deleted
|
||||
textarea.style.height = 'auto';
|
||||
// Set height based on scroll height
|
||||
textarea.style.height = textarea.scrollHeight + 'px';
|
||||
}
|
||||
|
||||
// Call autoResize on input event
|
||||
textarea.addEventListener('input', autoResize);
|
||||
|
||||
// Initialize autoResize in case of any pre-filled values
|
||||
autoResize();
|
||||
});
|
||||
});
|
||||
</script>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue