Skip to content

Job posting and job application flow #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 36 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
5bd8b76
feat: add initial models and migrations for application tracking system
aditya-vishwakarma-lab Apr 8, 2025
d04c083
feat: add employer home controller, views, and routes
aditya-vishwakarma-lab Apr 8, 2025
263fa9c
feat: implement authentication system for employers
aditya-vishwakarma-lab Apr 9, 2025
3b6caca
feat: enhance employer session management and UI
aditya-vishwakarma-lab Apr 9, 2025
d805828
feat: enhance password management and session handling for employers
aditya-vishwakarma-lab Apr 9, 2025
5e8004e
fix: standardize code formatting across controllers, mailers, and models
aditya-vishwakarma-lab Apr 9, 2025
c98a754
feat: implement job posts management for employers
aditya-vishwakarma-lab Apr 10, 2025
8c583c5
refactor: standardize controller namespacing according to rails
aditya-vishwakarma-lab Apr 11, 2025
97b63d8
fix: improve flash message handling in Stimulus controller
aditya-vishwakarma-lab Apr 11, 2025
5f49253
feat: enhance job posts management with show, edit, and update actions
aditya-vishwakarma-lab Apr 11, 2025
008b75c
feat: enhance job posts index view application count view
aditya-vishwakarma-lab Apr 11, 2025
99e73f0
feat: enhance job post creation and management features
aditya-vishwakarma-lab Apr 14, 2025
a64f506
feat: add status field to job post parameters
aditya-vishwakarma-lab Apr 14, 2025
e0b0ad9
feat: implement dropdown component for job type and work mode selection
aditya-vishwakarma-lab Apr 14, 2025
89845a5
feat: add job post show view and enhance new job post form
aditya-vishwakarma-lab Apr 15, 2025
7d5a75c
feat: implement dialog component for job post management
aditya-vishwakarma-lab Apr 15, 2025
0dddc3b
feat: enhance job post views with improved styling and navigation
aditya-vishwakarma-lab Apr 16, 2025
2b1f672
feat: add clipboard functionality for job post sharing
aditya-vishwakarma-lab Apr 16, 2025
0583a07
fix: correct organization attributes parameter in employer registrations
aditya-vishwakarma-lab Apr 16, 2025
476db38
feat: implement job applications management for employers
aditya-vishwakarma-lab Apr 16, 2025
40bed6e
feat: enhance job application form and validations
aditya-vishwakarma-lab Apr 16, 2025
25b7645
feat: implement resume upload functionality in job application form
aditya-vishwakarma-lab Apr 17, 2025
20647dc
feat: refactor job post status display with shared partial
aditya-vishwakarma-lab Apr 17, 2025
f07fc3c
refactor: change job posts status badge partial location
aditya-vishwakarma-lab Apr 17, 2025
5f031a7
feat: enhance job application index views for modern UI
aditya-vishwakarma-lab Apr 17, 2025
a002fd0
feat: integrate Ransack for job application filtering
aditya-vishwakarma-lab Apr 17, 2025
3bc724e
feat: add Stimulus controller for search functionality
aditya-vishwakarma-lab Apr 17, 2025
3b9693d
fix: correct mailer namespace in password reset functionality
aditya-vishwakarma-lab Apr 21, 2025
67a5dd1
feat: implement skills management functionality
aditya-vishwakarma-lab Apr 22, 2025
05cba06
fix: update the show job application page for better UI and fix routi…
aditya-vishwakarma-lab Apr 22, 2025
22b05ab
feat: enhance employer registration form with organization details
aditya-vishwakarma-lab Apr 23, 2025
8b06c09
chore: set up RSpec testing framework
aditya-vishwakarma-lab Apr 24, 2025
e7ac48d
feat: add factories and system tests for employer authentication
aditya-vishwakarma-lab Apr 24, 2025
8f53f82
refactor: changed directory structure
aditya-vishwakarma-lab Apr 24, 2025
e8f5f8b
test: add system tests for job posts
aditya-vishwakarma-lab Apr 25, 2025
dae1afc
feat: add job application system tests
aditya-vishwakarma-lab Apr 25, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .rspec
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--require spec_helper
8 changes: 7 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ gem "tailwindcss-rails"
gem "jbuilder"

# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword]
# gem "bcrypt", "~> 3.1.7"
gem "bcrypt", "~> 3.1.7"

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem "tzinfo-data", platforms: %i[ windows jruby ]
Expand All @@ -42,6 +42,8 @@ gem "thruster", require: false
# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images]
# gem "image_processing", "~> 1.2"

gem "ransack"

group :development, :test do
# See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
gem "debug", platforms: %i[ mri windows ], require: "debug/prelude"
Expand All @@ -51,6 +53,9 @@ group :development, :test do

# Omakase Ruby styling [https://github.com/rails/rubocop-rails-omakase/]
gem "rubocop-rails-omakase", require: false
gem "rspec-rails"
gem "factory_bot_rails"
gem "faker"
end

group :development do
Expand All @@ -62,4 +67,5 @@ group :test do
# Use system testing [https://guides.rubyonrails.org/testing.html#system-testing]
gem "capybara"
gem "selenium-webdriver"
gem "shoulda-matchers"
end
38 changes: 38 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ GEM
public_suffix (>= 2.0.2, < 7.0)
ast (2.4.3)
base64 (0.2.0)
bcrypt (3.1.20)
bcrypt_pbkdf (1.1.1)
bcrypt_pbkdf (1.1.1-arm64-darwin)
bcrypt_pbkdf (1.1.1-x86_64-darwin)
Expand Down Expand Up @@ -103,12 +104,20 @@ GEM
debug (1.10.0)
irb (~> 1.10)
reline (>= 0.3.8)
diff-lcs (1.6.1)
dotenv (3.1.7)
drb (2.2.1)
ed25519 (1.3.0)
erubi (1.13.1)
et-orbi (1.2.11)
tzinfo
factory_bot (6.5.1)
activesupport (>= 6.1.0)
factory_bot_rails (6.4.4)
factory_bot (~> 6.5)
railties (>= 5.0.0)
faker (3.5.1)
i18n (>= 1.8.11, < 2)
fugit (1.11.1)
et-orbi (~> 1, >= 1.2.11)
raabro (~> 1.4)
Expand Down Expand Up @@ -249,12 +258,33 @@ GEM
zeitwerk (~> 2.6)
rainbow (3.1.1)
rake (13.2.1)
ransack (4.3.0)
activerecord (>= 6.1.5)
activesupport (>= 6.1.5)
i18n
rdoc (6.13.1)
psych (>= 4.0.0)
regexp_parser (2.10.0)
reline (0.6.0)
io-console (~> 0.5)
rexml (3.4.1)
rspec-core (3.13.3)
rspec-support (~> 3.13.0)
rspec-expectations (3.13.3)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-mocks (3.13.2)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-rails (7.1.1)
actionpack (>= 7.0)
activesupport (>= 7.0)
railties (>= 7.0)
rspec-core (~> 3.13)
rspec-expectations (~> 3.13)
rspec-mocks (~> 3.13)
rspec-support (~> 3.13)
rspec-support (3.13.2)
rubocop (1.75.1)
json (~> 2.3)
language_server-protocol (~> 3.17.0.2)
Expand Down Expand Up @@ -292,6 +322,8 @@ GEM
rexml (~> 3.2, >= 3.2.5)
rubyzip (>= 1.2.2, < 3.0)
websocket (~> 1.0)
shoulda-matchers (6.4.0)
activesupport (>= 5.2.0)
solid_cable (3.0.7)
actioncable (>= 7.2)
activejob (>= 7.2)
Expand Down Expand Up @@ -372,19 +404,25 @@ PLATFORMS
x86_64-linux-musl

DEPENDENCIES
bcrypt (~> 3.1.7)
bootsnap
brakeman
capybara
debug
factory_bot_rails
faker
importmap-rails
jbuilder
kamal
pg (~> 1.1)
propshaft
puma (>= 5.0)
rails (~> 8.0.2)
ransack
rspec-rails
rubocop-rails-omakase
selenium-webdriver
shoulda-matchers
solid_cable
solid_cache
solid_queue
Expand Down
46 changes: 46 additions & 0 deletions app/assets/stylesheets/application.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,49 @@
*
* Consider organizing styles into separate files for maintainability.
*/

.field_with_errors {
display: contents;
}

/* Prevent scrolling while dialog is open */
body:has(dialog[data-dialog-target="dialog"][open]) {
overflow: hidden;
}

/* Customize the dialog backdrop */
dialog {
box-shadow: 0 0 0 100vw rgb(0 0 0 / 0.5);
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
margin: 0;
}

@keyframes fade-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}

@keyframes fade-out {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}

/* Add animations */
dialog[data-dialog-target="dialog"][open] {
animation: fade-in 200ms forwards;
}

dialog[data-dialog-target="dialog"][closing] {
animation: fade-out 200ms forwards;
}
16 changes: 16 additions & 0 deletions app/channels/application_cable/connection.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user

def connect
set_current_user || reject_unauthorized_connection
end

private
def set_current_user
if session = Session.find_by(id: cookies.signed[:session_id])
self.current_user = session.user
end
end
end
end
1 change: 1 addition & 0 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
class ApplicationController < ActionController::Base
include Authentication
# Only allow modern browsers supporting webp images, web push, badges, import maps, CSS nesting, and CSS :has.
allow_browser versions: :modern
end
52 changes: 52 additions & 0 deletions app/controllers/concerns/authentication.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
module Authentication
extend ActiveSupport::Concern

included do
before_action :require_authentication
helper_method :authenticated?
end

class_methods do
def allow_unauthenticated_access(**options)
skip_before_action :require_authentication, **options
end
end

private
def authenticated?
resume_session
end

def require_authentication
resume_session || request_authentication
end

def resume_session
Current.session ||= find_session_by_cookie
end

def find_session_by_cookie
Session.find_by(id: cookies.signed[:session_id]) if cookies.signed[:session_id]
end

def request_authentication
session[:return_to_after_authenticating] = request.url
redirect_to new_employer_session_path
end

def after_authentication_url
session.delete(:return_to_after_authenticating) || root_url
end

def start_new_session_for(user)
user.sessions.create!(user_agent: request.user_agent, ip_address: request.remote_ip).tap do |session|
Current.session = session
cookies.signed.permanent[:session_id] = { value: session.id, httponly: true, same_site: :lax }
end
end

def terminate_session
Current.session.destroy
cookies.delete(:session_id)
end
end
12 changes: 12 additions & 0 deletions app/controllers/employer/confirmations_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class Employer::ConfirmationsController < ApplicationController
allow_unauthenticated_access

def show
if user = User.find_by(email_confirmation_token: params[:token])
user.confirm_email!
redirect_to new_employer_session_path, notice: "Email confirmed successfully. You can now sign in."
else
redirect_to new_employer_session_path, alert: "Invalid confirmation token."
end
end
end
48 changes: 48 additions & 0 deletions app/controllers/employer/job_applications_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
class Employer::JobApplicationsController < ApplicationController
allow_unauthenticated_access only: %i[ new create ]
before_action :set_job_post, only: [ :index, :show, :new, :create ]

def index
@q = @job_post.job_applications.ransack(params[:q])
@job_applications = @q.result.order(created_at: :desc)
end

def show
@job_application = @job_post.job_applications.find(params[:id])
end

def new
@job_application = @job_post.job_applications.new
end

def create
@job_application = @job_post.job_applications.new(job_application_params)
@job_application.status = :pending

if @job_application.save
flash[:notice] = "Job application submitted successfully"
redirect_back_or_to root_path
else
render :new, status: :unprocessable_entity
end
end

private

def job_application_params
params.expect(
job_application: [
:name, :email, :phone, :resume,
:date_of_birth, :gender, :permanent_address,
:current_address, :linkedin_profile,
:preferred_start_date, :highest_education,
:institution_name, :degree, :graduation_year,
:major, :gpa, :experience
]
)
end

def set_job_post
@job_post = JobPost.find(params[:job_post_id])
end
end
68 changes: 68 additions & 0 deletions app/controllers/employer/job_posts_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
class Employer::JobPostsController < ApplicationController
def index
@job_type = params[:job_type].to_i || JobPost.job_types[:full_time]
@job_posts = Current.user.organization.job_posts
.where(job_type: @job_type)
.order(created_at: :desc)

@stats = {
active_opportunities: Current.user.organization.job_posts.active.count,
total_applications: Current.user.organization.job_posts.joins(:job_applications).count,
closed_opportunities: Current.user.organization.job_posts.closed.count
}
end

def show
@job_post = Current.user.organization.job_posts.find(params[:id])
end

def new
@job_post = JobPost.new
end

def create
@job_post = Current.user.organization.job_posts.new(job_post_params)
@job_post.user = Current.user
@job_post.status = :active

if @job_post.save
redirect_to employer_job_posts_path, notice: "Job post was successfully created."
else
render :new, status: :unprocessable_entity
end
end

def edit
@job_post = Current.user.organization.job_posts.find(params[:id])
end

def update
@job_post = Current.user.organization.job_posts.find(params[:id])

if @job_post.update(job_post_params)
redirect_to employer_job_posts_path, notice: "Job post was successfully updated."
else
render :edit, status: :unprocessable_entity
end
end

def destroy
@job_post = Current.user.organization.job_posts.find(params[:id])
@job_post.destroy

redirect_to employer_job_posts_path, notice: "Job post was successfully deleted."
end

private

def job_post_params
params.expect(
job_post: [
:title, :job_type, :location, :min_experience, :max_experience,
:openings, :work_mode, :application_deadline, :salary_range,
:contact_number, :description, :candidate_preference, :status,
job_post_skills_attributes: [ [ :skill_id ] ]
]
)
end
end
Loading
Loading