diff --git a/Gemfile b/Gemfile
index 0b71dab..aaecd97 100644
--- a/Gemfile
+++ b/Gemfile
@@ -19,10 +19,14 @@ gem "validate_url", "~> 1.0"
gem "rexml", ">= 3.3.2"
group :development, :test do
+ gem "byebug", "~> 11.1", ">= 11.1.3"
+ gem "database_cleaner-active_record", "1.8.0.beta"
gem "debug", "~> 1.9", ">= 1.9.2", platforms: %i[mri windows]
gem "dotenv", "~> 3.1", ">= 3.1.2"
gem "factory_bot_rails", "~> 6.4", ">= 6.4.3"
gem "faker", "~> 3.4"
+ gem "mocha", "~> 1.2", ">= 1.2.1"
+ gem "rails-controller-testing", "~> 0.0.3"
gem "rubocop-rails-omakase", "~> 1.0", require: false, group: [:development]
gem "minitest-reporters", "~> 1.6", ">= 1.6.1"
end
diff --git a/Gemfile.lock b/Gemfile.lock
index dcfca61..f90fa71 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -98,11 +98,16 @@ GEM
bundler-audit (0.9.1)
bundler (>= 1.2.0, < 3)
thor (~> 1.0)
+ byebug (11.1.3)
childprocess (5.0.0)
colorize (1.1.0)
concurrent-ruby (1.2.3)
connection_pool (2.4.1)
crass (1.0.6)
+ database_cleaner (1.8.5)
+ database_cleaner-active_record (1.8.0.beta)
+ activerecord
+ database_cleaner (~> 1.8.0.beta)
date (3.3.4)
debug (1.9.2)
irb (~> 1.10)
@@ -171,6 +176,7 @@ GEM
builder
minitest (>= 5.0)
ruby-progressbar
+ mocha (1.16.1)
msgpack (1.7.2)
mutex_m (0.2.0)
net-imap (0.4.13)
@@ -236,6 +242,8 @@ GEM
activesupport (= 7.1.3.4)
bundler (>= 1.15.0)
railties (= 7.1.3.4)
+ rails-controller-testing (0.0.3)
+ rails (>= 4.2)
rails-dom-testing (2.2.0)
activesupport (>= 5.0.0)
minitest
@@ -351,7 +359,9 @@ DEPENDENCIES
bootsnap (~> 1.18, >= 1.18.3)
brakeman
bundler-audit (~> 0.9.1)
+ byebug (~> 11.1, >= 11.1.3)
colorize (~> 1.1)
+ database_cleaner-active_record (= 1.8.0.beta)
debug (~> 1.9, >= 1.9.2)
devise (~> 4.9)
dotenv (~> 3.1, >= 3.1.2)
@@ -362,10 +372,12 @@ DEPENDENCIES
jbuilder (~> 2.12)
letter_opener (~> 1.10)
minitest-reporters (~> 1.6, >= 1.6.1)
+ mocha (~> 1.2, >= 1.2.1)
pg (~> 1.5, >= 1.5.6)
phlex-rails (~> 1.2)
puma (~> 6.4, >= 6.4.2)
rails (~> 7.1, >= 7.1.3.4)
+ rails-controller-testing (~> 0.0.3)
rexml (>= 3.3.2)
rubocop (~> 1.63, >= 1.63.5)
rubocop-factory_bot (~> 2.25, >= 2.25.1)
diff --git a/README.md b/README.md
index 4d1a6ba..65eb0ff 100644
--- a/README.md
+++ b/README.md
@@ -20,7 +20,7 @@
Job Tracker is a simple, powerful, and user-friendly web application designed to help job seekers efficiently manage their job search process. Built with Ruby on Rails and enhanced with modern web technologies, this tool streamlines the often overwhelming task of tracking multiple job applications.
-
+
## Key Features
diff --git a/app/controllers/job_applications_controller.rb b/app/controllers/job_applications_controller.rb
index c56b68f..3e162bb 100644
--- a/app/controllers/job_applications_controller.rb
+++ b/app/controllers/job_applications_controller.rb
@@ -96,7 +96,7 @@ def set_job_application
end
def job_application_params
- params.require(:job_application).permit(:date_applied, :company_name, :method_of_contact, :email_address, :point_of_contact, :website_link, :position_type, :position_title)
+ params.require(:job_application).permit(:date_applied, :company_name, :method_of_contact, :email_address, :point_of_contact, :website_link, :position_type, :position_title, :claimed_for_unemployment, :status)
end
def filter_and_sort_job_applications
@@ -105,6 +105,9 @@ def filter_and_sort_job_applications
job_applications = job_applications.search(params[:search]) if params[:search].present?
job_applications = job_applications.by_method_of_contact(params[:method_of_contact]) if params[:method_of_contact].present?
job_applications = job_applications.by_position_type(params[:position_type]) if params[:position_type].present?
+ job_applications = job_applications.claimed_for_unemployment if params[:claimed_for_unemployment] == "true"
+ job_applications = job_applications.not_claimed_for_unemployment if params[:claimed_for_unemployment] == "false"
+ job_applications = job_applications.by_status(params[:status]) if params[:status].present?
sort_column = sort_column(params[:sort])
sort_direction = sort_direction(params[:direction])
@@ -119,7 +122,7 @@ def filter_and_sort_job_applications
end
def sort_column(column)
- %w[date_applied company_name position_title created_at].include?(column) ? column : "created_at"
+ %w[date_applied company_name position_title created_at claimed_for_unemployment status].include?(column) ? column : "created_at"
end
def sort_direction(direction)
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 27a777f..fd7da3a 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -32,14 +32,31 @@ def progress_bar_class(type)
end
def sort_link_to(name, column)
- direction = (column.to_s == params[:sort] && params[:direction] == "asc") ? "desc" : "asc"
- link_to name,
- request.params.merge(sort: column, direction: direction),
- class: "text-gray-600 hover:text-gray-900",
+ current_column = params[:sort]
+ current_direction = params[:direction]
+
+ is_current_column = column.to_s == current_column
+ next_direction = (is_current_column && current_direction == "asc") ? "desc" : "asc"
+
+ icon = if is_current_column
+ (current_direction == "asc") ? "↑" : "↓"
+ else
+ ""
+ end
+
+ link_to request.params.merge(sort: column, direction: next_direction),
+ class: "text-gray-600 hover:text-gray-900 inline-flex items-center",
data: {
turbo_frame: "job_applications_table",
turbo_action: "replace"
- }
+ } do
+ content_tag(:span, class: "flex items-center") do
+ safe_join([
+ content_tag(:span, name, class: "mr-1"),
+ content_tag(:span, icon, class: "sort-icon")
+ ])
+ end
+ end
end
def safe_url(url)
diff --git a/app/helpers/job_applications_helper.rb b/app/helpers/job_applications_helper.rb
index 1e267ed..0a90069 100644
--- a/app/helpers/job_applications_helper.rb
+++ b/app/helpers/job_applications_helper.rb
@@ -1,2 +1,11 @@
module JobApplicationsHelper
+ def display_position_type(position_type)
+ case position_type
+ when "full_time" then "Full-time"
+ when "part_time" then "Part-time"
+ when "internship" then "Internship"
+ else
+ position_type
+ end
+ end
end
diff --git a/app/models/job_application.rb b/app/models/job_application.rb
index 989af3b..3cefb91 100644
--- a/app/models/job_application.rb
+++ b/app/models/job_application.rb
@@ -1,18 +1,50 @@
class JobApplication < ApplicationRecord
+ attribute :status, :string
+
validates :date_applied, :company_name, :method_of_contact, :position_type, :position_title, presence: true
validates :email_address, presence: true, if: -> { method_of_contact == "email" }
validates :point_of_contact, presence: true, if: -> { ["email", "phone", "recruiter", "other"].include?(method_of_contact) }
- validates :website_link, presence: true, if: -> { method_of_contact == "internet job application" }
+ validates :website_link, presence: true, if: -> { method_of_contact == "internet_job_application" }
validates :website_link, url: {
allow_blank: true,
schemes: ["http", "https"],
no_local: true,
public_suffix: true
}
- enum method_of_contact: {email: "email", phone: "phone", internet_job_application: "internet job application", recruiter: "recruiter", other: "other"}
- enum position_type: {full_time: "full-time", part_time: "part-time", internship: "internship"}
+ validates :claimed_for_unemployment, inclusion: {in: [true, false]}
+ validates :status, inclusion: {in: %w[hired interviewing job_offer no_response not_hired]}
+
+ enum method_of_contact: {
+ email: "email",
+ internet_job_application: "internet job application",
+ other: "other",
+ phone: "phone",
+ recruiter: "recruiter"
+ }
+ enum position_type: {
+ full_time: "full_time",
+ internship: "internship",
+ part_time: "part_time"
+ }
+ enum status: {
+ hired: "hired",
+ interviewing: "interviewing",
+ job_offer: "job offer",
+ no_response: "no response",
+ not_hired: "not hired"
+ }
- scope :search, ->(query) { where("company_name ILIKE ? OR position_title ILIKE ?", "%#{query}%", "%#{query}%") }
scope :by_method_of_contact, ->(method) { where(method_of_contact: method) }
scope :by_position_type, ->(type) { where(position_type: type) }
+ scope :by_status, ->(status) { where(status: status) }
+ scope :claimed_for_unemployment, -> { where(claimed_for_unemployment: true) }
+ scope :not_claimed_for_unemployment, -> { where(claimed_for_unemployment: false) }
+ scope :search, ->(query) {
+ where("company_name ILIKE :query OR
+ position_title ILIKE :query OR
+ email_address ILIKE :query OR
+ point_of_contact ILIKE :query OR
+ website_link ILIKE :query OR
+ status ILIKE :query", query: "%#{query}%")
+ }
end
diff --git a/app/views/job_applications/_form.html.erb b/app/views/job_applications/_form.html.erb
index 251ec95..6ad9f4f 100644
--- a/app/views/job_applications/_form.html.erb
+++ b/app/views/job_applications/_form.html.erb
@@ -44,12 +44,22 @@
| - <%= sort_link_to 'Date Applied', 'date_applied' %> - | -- <%= sort_link_to 'Company Name', 'company_name' %> - | -- <%= sort_link_to 'Position', 'position_title' %> - | -- Type - | -- Contact Method - | -- P.o.C. - | -- Email - | -- Website - | -- Actions - | -
|---|
- <%= "No results match your search criteria." if params[:search].present? || params[:method_of_contact].present? || params[:position_type].present? %> -
-+ <%= "No results match your search criteria." if params[:search].present? || params[:method_of_contact].present? || params[:position_type].present? %> +
+