Commit 8d685ee8 by Thanh Hung Pham

Merge branch 'favorite-history' into 'master'

favorite-history funtion

See merge request !10
parents f99a3f7b e8c0ce57
Pipeline #1439 canceled with stages
in 0 seconds
...@@ -14,6 +14,7 @@ gem 'babosa' ...@@ -14,6 +14,7 @@ gem 'babosa'
gem 'active_storage_validations' gem 'active_storage_validations'
gem 'mini_magick', '>= 4.9.5' gem 'mini_magick', '>= 4.9.5'
gem 'devise' gem 'devise'
# Use sqlite3 as the database for Active Record # Use sqlite3 as the database for Active Record
gem 'mysql2', '~> 0.5.3' gem 'mysql2', '~> 0.5.3'
# Use Puma as the app server # Use Puma as the app server
...@@ -52,6 +53,7 @@ group :development do ...@@ -52,6 +53,7 @@ group :development do
gem 'listen', '~> 3.3' gem 'listen', '~> 3.3'
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
gem 'spring' gem 'spring'
gem 'bullet'
end end
group :test do group :test do
......
...@@ -76,6 +76,9 @@ GEM ...@@ -76,6 +76,9 @@ GEM
popper_js (>= 2.9.2, < 3) popper_js (>= 2.9.2, < 3)
sassc-rails (>= 2.0.0) sassc-rails (>= 2.0.0)
builder (3.2.4) builder (3.2.4)
bullet (6.1.5)
activesupport (>= 3.0.0)
uniform_notifier (~> 1.11)
byebug (11.1.3) byebug (11.1.3)
capybara (3.35.3) capybara (3.35.3)
addressable addressable
...@@ -221,6 +224,7 @@ GEM ...@@ -221,6 +224,7 @@ GEM
turbolinks-source (5.2.0) turbolinks-source (5.2.0)
tzinfo (2.0.4) tzinfo (2.0.4)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
uniform_notifier (1.14.2)
warden (1.2.9) warden (1.2.9)
rack (>= 2.0.9) rack (>= 2.0.9)
web-console (4.1.0) web-console (4.1.0)
...@@ -254,6 +258,7 @@ DEPENDENCIES ...@@ -254,6 +258,7 @@ DEPENDENCIES
babosa babosa
bootsnap (>= 1.4.4) bootsnap (>= 1.4.4)
bootstrap (~> 5.0.1) bootstrap (~> 5.0.1)
bullet
byebug byebug
capybara (>= 3.26) capybara (>= 3.26)
devise devise
......
...@@ -60,6 +60,6 @@ class ApplyJobsController < ApplicationController ...@@ -60,6 +60,6 @@ class ApplyJobsController < ApplicationController
private private
def apply_params def apply_params
params.require(:apply_job).permit(:name, :email, :cv, :job_id, :id) params.require(:apply_job).permit(:name, :email, :cv, :job_id)
end end
end end
\ No newline at end of file
class FavoriteJobsController < ApplicationController
include ApplicationHelper
before_action :check_params_job, only: %i[update destroy]
def index
@favorites = favorite_query.order_favorite(current_user).page(params[:page])
end
def update
favorite = favorite_query.find_favorite(job_params, current_user)
if favorite.nil?
FavoriteJob.create(job: @job, user: current_user)
else
favorite.destroy
end
respond_to do |format|
format.html { redirect_to new_user_session_path, alert: 'You need to sign in or sign up before continuing.' }
format.js {}
end
end
def destroy
@favorite = favorite_query.find_favorite(job_params, current_user).destroy
redirect_to favorite_url
flash[:success] = "#{@favorite.job.title} was completed and destroyed."
end
private
def job_params
params.permit(:job_id)
end
def favorite_query
@favorite_query ||= FavoriteQuery.new
end
def check_params_job
@job = Job.find_by(id: params[:job_id]) or not_found
end
end
class HistoryJobsController < ApplicationController
def index
@histories = history_query.order_history(current_user)
end
private
def history_query
@history_query ||= HistoryQuery.new
end
end
class JobsController < ApplicationController class JobsController < ApplicationController
include ApplicationHelper
after_action :history_action, only: [:show]
def index def index
if params[:city_slug].present? if params[:city_slug].present?
city = City.find_by(slug: params[:city_slug]) city = City.find_by(slug: params[:city_slug])
...@@ -8,12 +11,33 @@ class JobsController < ApplicationController ...@@ -8,12 +11,33 @@ class JobsController < ApplicationController
industry = Industry.find_by(slug: params[:industry_slug]) industry = Industry.find_by(slug: params[:industry_slug])
jobs = industry.jobs jobs = industry.jobs
@result = industry.name @result = industry.name
end end
@total = jobs.count @total = jobs.count
@jobs = jobs.latest_jobs.page(params[:page]) @jobs = jobs.latest_jobs.page(params[:page])
end end
def show def show
@job = Job.latest_jobs.find_by(slug: params[:job_slug]) @job = Job.find_by(slug: params[:job_slug]) or not_found
end
private
def history_action
history = history_query.find_history(job_params, current_user)
if history.nil?
HistoryJob.create(job: Job.find(params[:job_slug]), user: current_user)
else
history.touch(:updated_at)
end
HistoryJob.first.destroy if HistoryJob.count > HistoryJob::LIMIT_HISTORY
end
def job_params
params.permit(:job_slug)
end
def history_query
@history_query ||= HistoryQuery.new
end end
end end
...@@ -24,4 +24,8 @@ module ApplicationHelper ...@@ -24,4 +24,8 @@ module ApplicationHelper
def render_404 def render_404
render file: "#{Rails.root}/public/404.html", status: :not_found render file: "#{Rails.root}/public/404.html", status: :not_found
end end
def favorite_text(job)
FavoriteJob.find_by(job: job, user: current_user).present? ? 'Unfavorite' : 'Favorite'
end
end end
...@@ -3,11 +3,17 @@ ...@@ -3,11 +3,17 @@
// a relevant structure within app/javascript and only use these pack files to reference // a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled. // that code so it'll be compiled.
import Rails from "@rails/ujs" // import Rails from "@rails/ujs"
import Turbolinks from "turbolinks" // import Turbolinks from "turbolinks"
import * as ActiveStorage from "@rails/activestorage" // import * as ActiveStorage from "@rails/activestorage"
import "channels" // import "channels"
Rails.start() // Rails.start()
Turbolinks.start() // Turbolinks.start()
ActiveStorage.start() // ActiveStorage.start()
require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")
require("jquery")
class HistoryJob < ApplicationRecord class HistoryJob < ApplicationRecord
belongs_to :user belongs_to :user
belongs_to :job belongs_to :job
LIMIT_HISTORY = 20
end end
class FavoriteQuery
def initialize(favorites = FavoriteJob)
@favorites = favorites.includes(job: %i[cities cities_jobs])
end
def find_favorite(params, current_user)
@favorites.find_by(job: Job.find(params[:job_id]), user: current_user)
end
def find_favorite_slug(params, current_user)
@favorites.find_by(job: Job.find(params[:job_slug]), user: current_user)
end
def order_favorite(current_user)
@favorites.where(user: current_user).order('favorite_jobs.created_at DESC')
end
end
\ No newline at end of file
class HistoryQuery
def initialize(histories = HistoryJob)
@histories = histories.includes(job: %i[cities cities_jobs])
end
def order_history(current_user)
@histories.where(user: current_user).order('history_jobs.updated_at DESC')
end
def find_history(params, current_user)
@histories.find_by(job: Job.find(params[:job_slug]), user: current_user)
end
end
\ No newline at end of file
...@@ -17,7 +17,6 @@ h2.text-center ...@@ -17,7 +17,6 @@ h2.text-center
p.my-1 p.my-1
= f.label :cv, "Your CV" = f.label :cv, "Your CV"
br br
= f.hidden_field :id, value: @blob.id
= @apply_job.cv.filename = @apply_job.cv.filename
.span.p-3.text-center .span.p-3.text-center
= link_to "Back", apply_path(job_id: @apply_job.job_id), class: "btn btn-primary btn-space" = link_to "Back", apply_path(job_id: @apply_job.job_id), class: "btn btn-primary btn-space"
......
= link_to favorite_text(job), favorite_update_path(job_id: job.id), id: "favorite-#{job.id}", remote: user_signed_in?, class: "btn btn-outline-primary btn-lg"
\ No newline at end of file
- provide :title, 'Favorite jobs'
h3.p-3.text-center
| Favorite Jobs
.d-flex.justify-content-center
= paginate @favorites, window: 1
= form_with(url: apply_path, method: :get) do |f|
- @favorites.each do |favorite|
.row.bg-white
.col-1.p-3.card-body.text-dark.text-center.align-self-center
= f.radio_button :job_id, favorite.job.id, required: true, class: "form-check-input mt-0"
.col-9.p-3.align-self-center
h5.mb-1
= link_to favorite.job.title, detail_path(favorite.job.slug)
p.mb-1
i.fas.fa-dollar-sign.m-1
| Lương:
= favorite.job.salary
p.mb-1
i.fas.fa-map-marker-alt.m-1
= favorite.job.cities.map(&:name).uniq.join(' | ')
p.mb-1
= truncate(favorite.job.overview, length: 250)
.col-2.p-3.text-center.align-self-center
= link_to "Remove", unfavorite_path(job_id: favorite.job.id), method: :delete, data: { confirm: 'Are you sure?' }, class: "btn btn-outline-primary"
-if @favorites.any?
.d-flex.justify-content-center.p-2
= page_entries_info @favorites
.d-flex.justify-content-center
= paginate @favorites, window: 1
.span.p-3.text-center
= f.submit "Apply job", class: "btn btn-primary btn-lg"
-else
h4.text-center
| You haven't favorite jobs
| $("#favorite-#{@job.id}").text("
= favorite_text(@job)
| ");
\ No newline at end of file
- provide :title, 'History jobs'
h3.p-3.text-center
| History Jobs
= form_with(url: apply_path, method: :get) do |f|
- @histories.each do |history|
.row.bg-white
.col-1.p-3.card-body.text-dark.text-center.align-self-center
= f.radio_button :job_id, history.job.id, required: true, class: "form-check-input mt-0"
.col-11.p-3.align-self-center
h5.mb-1
= link_to history.job.title, detail_path(history.job.slug)
p.mb-1
i.fas.fa-dollar-sign.m-1
| Lương:
= history.job.salary
p.mb-1
i.fas.fa-map-marker-alt.m-1
= history.job.cities.map(&:name).uniq.join(' | ')
p.mb-1
= truncate(history.job.overview, length: 250)
-if @histories.any?
.span.p-3.text-center
= f.submit "Apply job", class: "btn btn-primary btn-lg"
-else
h4.text-center
| You haven't history jobs
\ No newline at end of file
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
.job-list .job-list
- @jobs.each do |job| - @jobs.each do |job|
.row.bg-white .row.bg-white
.col-10.p-3.border.card-body.text-dark .col-10.p-3.card-body.text-dark
h5.mb-1 h5.mb-1
= link_to job.title, detail_path(job.slug) = link_to job.title, detail_path(job.slug)
p.mb-1 p.mb-1
...@@ -27,9 +27,9 @@ ...@@ -27,9 +27,9 @@
= link_to job.cities.map(&:name).uniq.join(' | '), "#" = link_to job.cities.map(&:name).uniq.join(' | '), "#"
p.mb-1 p.mb-1
= truncate(job.overview, length: 250) = truncate(job.overview, length: 250)
.col-sm-2.p-3.border.favourite .col-sm-2.p-3.favourite
= link_to "Farourite", "#", class: "btn btn-outline-primary" = render partial: "favorite_jobs/favorite", locals: { job: job }
h6.offset-md-4.px-5 h6.offset-md-4.px
= page_entries_info @jobs = page_entries_info @jobs
h6.offset-md-4 h6.offset-md-4
= paginate @jobs, window: 1 = paginate @jobs, window: 1
\ No newline at end of file
...@@ -50,7 +50,5 @@ ...@@ -50,7 +50,5 @@
.row.bg-white.p-4 .row.bg-white.p-4
.col.text-end .col.text-end
= link_to "Apply this Job", apply_path(job_id: @job.id), class: "btn btn-outline-primary btn-lg" = link_to "Apply this Job", apply_path(job_id: @job.id), class: "btn btn-outline-primary btn-lg"
.col .col.text-start
= link_to "Favourite", "#", class: "btn btn-outline-primary btn-lg" = render partial: "favorite_jobs/favorite", locals: { job: @job }
\ No newline at end of file
...@@ -8,9 +8,9 @@ header ...@@ -8,9 +8,9 @@ header
li li
= link_to "Profile", my_path = link_to "Profile", my_path
li li
= link_to "Favourite",'#' = link_to "Favorite", favorite_path
li li
= link_to "History", '#' = link_to "History", history_path
li li
= link_to('Logout', destroy_user_session_path, method: :delete) = link_to('Logout', destroy_user_session_path, method: :delete)
- else - else
......
- provide :title, 'Reconfirm Email'
.row.p-3 .row.p-3
.col-md-6.offset-md-3.form-apply .col-md-6.offset-md-3.form-apply
= form_for(resource, as: resource_name) do |f| = form_for(resource, as: resource_name) do |f|
......
- provide :title, 'Reset Password'
h2.p-3.text-center h2.p-3.text-center
| Change your password | Change your password
.row .row
......
- provide :title, 'Reset Password'
h2.p-3.text-center h2.p-3.text-center
| Forgot your password | Forgot your password
.row .row
......
- provide :title, 'Edit User'
h2.p-3.text-center h2.p-3.text-center
| Edit My Page | Edit My Page
.row .row
......
- provide :title, 'Register'
h2.p-3.text-center h2.p-3.text-center
| Register | Register
.row .row
......
- provide :title, 'Rgister'
h5.p-5.fw-normal.border.bg-white h5.p-5.fw-normal.border.bg-white
| Thank you for register our service, an confirmation email with registration link | Thank you for register our service, an confirmation email with registration link
has been sent to your email. Please check your email within 24 hours. has been sent to your email. Please check your email within 24 hours.
......
- provide :title, 'Login'
h2.p-3.text-center h2.p-3.text-center
| Log in | Log in
.row .row
......
- provide :title, 'Profile User'
h2.p-3.text-center h2.p-3.text-center
| My Page | My Page
.row .row
.col-md-6.offset-md-3.form-apply .col-md-6.offset-md-3.form-apply
= form_with(scope: @user, local:true) do |f| = form_with(scope: :user, local:true) do |f|
.card .card
.card-body .card-body
.field .field
= f.label :email = f.label :email
br br
= f.email_field :email, disabled: true, class: 'form-control' = f.email_field :email, readonly: true, class: 'form-control'
.field .field
= f.label :name, "Full Name" = f.label :name, "Full Name"
br br
= f.text_field :name, disabled: true, class: 'form-control' = f.text_field :name, readonly: true, class: 'form-control'
.field .field
-if @user.cv.attached? -if @user.cv.attached?
= f.label :cv, "CV" = f.label :cv, "CV"
......
...@@ -84,4 +84,11 @@ Rails.application.configure do ...@@ -84,4 +84,11 @@ Rails.application.configure do
# Uncomment if you wish to allow Action Cable access from any origin. # Uncomment if you wish to allow Action Cable access from any origin.
# config.action_cable.disable_request_forgery_protection = true # config.action_cable.disable_request_forgery_protection = true
config.after_initialize do
Bullet.enable = true
Bullet.bullet_logger = true
Bullet.raise = true # raise an error if n+1 query occurs
Bullet.unused_eager_loading_enable = false
end
end end
...@@ -8,6 +8,10 @@ Rails.application.routes.draw do ...@@ -8,6 +8,10 @@ Rails.application.routes.draw do
get 'apply', to: 'apply_jobs#new' get 'apply', to: 'apply_jobs#new'
post 'confirm', to: 'apply_jobs#confirm' post 'confirm', to: 'apply_jobs#confirm'
post 'done', to: 'apply_jobs#done' post 'done', to: 'apply_jobs#done'
get 'job_favorite', to: 'favorite_jobs#update', as: 'favorite_update'
get 'favorite', to: 'favorite_jobs#index', as: 'favorite'
delete 'unfavorite', to: 'favorite_jobs#destroy'
get 'history', to: 'history_jobs#index', as: 'history'
devise_for :users, skip: %i[sessions registrations passwords], controllers: { confirmations: 'users/confirmations' } devise_for :users, skip: %i[sessions registrations passwords], controllers: { confirmations: 'users/confirmations' }
get '/my', to: 'users#show' get '/my', to: 'users#show'
devise_scope :user do devise_scope :user do
......
const { environment } = require('@rails/webpacker') const { environment } = require('@rails/webpacker')
const webpack = require('webpack')
environment.plugins.prepend('Provide',
new webpack.ProvidePlugin({
$: 'jquery/src/jquery',
jQuery: 'jquery/src/jquery'
})
)
module.exports = environment module.exports = environment
{ {
"name": "ve-njob", "name": "ve-njob",
"license": "MIT",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@rails/actioncable": "^6.0.0", "@rails/actioncable": "^6.0.0",
...@@ -7,12 +8,14 @@ ...@@ -7,12 +8,14 @@
"@rails/ujs": "^6.0.0", "@rails/ujs": "^6.0.0",
"@rails/webpacker": "5.4.0", "@rails/webpacker": "5.4.0",
"bootstrap": "^5.0.2", "bootstrap": "^5.0.2",
"jquery": "^3.6.0",
"turbolinks": "^5.2.0", "turbolinks": "^5.2.0",
"webpack": "^4.46.0", "webpack": "^4.46.0",
"webpack-cli": "^3.3.12" "webpack-cli": "^3.3.12"
}, },
"version": "0.1.0", "version": "0.1.0",
"devDependencies": { "devDependencies": {
"webpack-dev-server": "^3.11.2" "@webpack-cli/serve": "^1.5.2",
"webpack-dev-server": "^4.0.0"
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment