Commit eabd44f2 by Mai Hoang Thai Ha

done

parent 0cb127f4
@import "bootstrap"; @import "bootstrap";
@import "font-awesome"; @import "font-awesome";
@import "./scss/style.scss"; @import "./scss/style.scss";
/*
* This is a manifest file that'll be compiled into application.css, which will include all the files .ribbon {
* listed below. text-align: center;
* ul {
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's list-style: none;
* vendor/assets/stylesheets directory can be referenced here using a relative path. display: flex;
* justify-content: center;
* You're free to add application-wide styles to this file and they'll appear at the bottom of the align-items: center;
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS width: 100%;
* files in this directory. Styles in this file should be added after the last require_* statement. margin: 0;
* It is generally better to create a new file per style scope. padding: 0;
*= .item {
*= require top display: block;
*= require_self float: left;
*= require_tree . width: 30%;
*= require font-awesome height: 100%;
*/ background: #f3f5fa;
\ No newline at end of file text-align: center;
padding: 8px;
position: relative;
font-size: 16px;
font-weight: 700;
text-decoration: none;
color: #808080;
.circle {
display: inline-flex;
-ms-flex-line-pack: center;
align-content: center;
-ms-flex-pack: center;
justify-content: center;
width: 1.6em;
height: 1.6em;
padding: 0.25em 0;
margin-right: 10px;
line-height: 1em;
font-size: 1em;
color: #808080;
background-color: #e0e0e0;
border-radius: 50%;
}
&:after {
content: "";
border-top: 21px solid transparent;
border-bottom: 21px solid transparent;
border-left: 21px solid #f3f5fa;
position: absolute;
right: -21px;
top: 0;
z-index: 1;
}
&:last-child::after {
display: none;
}
&:first-child::before {
content: "";
border-top: 21px solid transparent;
border-bottom: 21px solid transparent;
border-left: 21px solid #fff;
position: absolute;
left: 0;
top: 0;
}
}
.active {
background: #0d6efd;
color: #fff;
.circle {
color: #0d6efd;
background-color: #fff;
}
&::after {
border-left-color: #0d6efd;
color: #fff;
}
}
}
}
.btn-height {
height: 50px;
}
.invalid {
.form-msg {
color: #f33a58;
}
input {
border-color: #f33a58;
}
}
.logout {
border: none;
padding: 0;
background-color: white;
outline: none;
}
.flash {
position: absolute;
top: 0;
right: 0;
left: 0;
z-index: 1000;
background-color: white;
}
.hide {
display: none;
}
.alert-notice {
color: #155724;
background-color: #d4edda;
border-color: #c3e6cb;
}
\ No newline at end of file
// Place all the styles related to the Favorite_industries controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: https://sass-lang.com/
...@@ -42,7 +42,7 @@ select { ...@@ -42,7 +42,7 @@ select {
border: 1px solid #EDEDED; border: 1px solid #EDEDED;
border-radius: 0; border-radius: 0;
background-color: $white; background-color: $white;
background-image: url("../images/icons/arrow-down.png"); // background-image: url("../images/icons/arrow-down.png");
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: right center; background-position: right center;
background-size: auto; background-size: auto;
......
...@@ -113,6 +113,9 @@ ...@@ -113,6 +113,9 @@
@media #{$small-mobile} { @media #{$small-mobile} {
& .salary-type { & .salary-type {
margin-left: auto; margin-left: auto;
& .badge {
font-size: 10px;
}
} }
& .content { & .content {
......
class FavoriteIndustriesController < ApplicationController
before_action :authenticate_user!
before_action :load_industry, only: %i[create destroy]
def index
@favorite_industries = current_user.favorite_industries
.page(params[:page]).per(Job::JOB_PER_PAGE)
end
def create
@favorite_industry = current_user.favorite_industries.build(industry_id: @industry.id)
respond_to :js if @favorite_industry.save
end
def destroy
@favorite_industry = current_user.favorite_industries.find_by(industry_id: @industry.id)
respond_to :js if @favorite_industry.destroy
end
private
def load_industry
@industry = Industry.find_by(id: params[:industry_id])
end
end
class FavoriteJobsController < ApplicationController class FavoriteJobsController < ApplicationController
# before_action :logged_in_user
before_action :authenticate_user! before_action :authenticate_user!
before_action :load_job, only: %i[create destroy] before_action :load_job, only: %i[create destroy]
......
class JobsController < ApplicationController class JobsController < ApplicationController
before_action :history, only: :show before_action :history, only: :show
before_action :views_count, only: :show
before_action :salary_search before_action :salary_search
before_action :city_industry_list before_action :city_industry_list
before_action :name, only: :index before_action :name, only: :index
...@@ -31,6 +32,13 @@ class JobsController < ApplicationController ...@@ -31,6 +32,13 @@ class JobsController < ApplicationController
history.update(updated_at: Time.current) history.update(updated_at: Time.current)
end end
def views_count
job = Job.find_by(id: params[:id])
count = job.views_count + 1
job.update_attribute :views_count, count
end
def name def name
@name = if params[:city_slug] @name = if params[:city_slug]
City.find_by(slug: params[:city_slug]).name City.find_by(slug: params[:city_slug]).name
......
class TopController < ApplicationController class TopController < ApplicationController
before_action :salary_search before_action :salary_search
before_action :city_industry_list before_action :city_industry_list
before_action :solr
def index def index
solr = Solr.new(params) @latest_jobs = get_jobs(@solr.latest_jobs)
@latest_jobs = get_jobs(solr.latest_jobs) @attractive_jobs = Job.top_views
@total_job = solr.query_all['response']['numFound'] @total_job = @solr.query_all['response']['numFound']
@top_cities = solr.facet_query('city_id')['vietnam'].take(City::TOP_JOB_COUNT) @top_cities = @solr.facet_query('city_id')['vietnam'].take(City::TOP_JOB_COUNT)
@top_industries = solr.facet_query('industry_id').take(Industry::TOP_JOB_COUNT) @top_industries = @solr.facet_query('industry_id').take(Industry::TOP_JOB_COUNT)
@member = User.count @member = User.count
@resume = ApplyJob.count @resume = ApplyJob.count
@company = Company.count @company = Company.count
suggest
end end
private private
def suggest
return unless user_signed_in? && current_user.industries?
industry_ids = current_user.fav_industries_ids
@suggest_jobs = get_jobs(@solr.suggest_jobs(industry_ids))
end
def solr
@solr = Solr.new(params)
end
def get_jobs(query) def get_jobs(query)
jobs_ids = query['response']['docs'].map { |j| j['job_id'] } jobs_ids = query['response']['docs'].map { |j| j['job_id'] }
Job.eager_load(:cities, :cities_jobs, :company).find(jobs_ids) Job.includes(:cities, :cities_jobs, :company).find(jobs_ids)
end end
end end
module FavoriteIndustriesHelper
end
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
$body = $('body'), $body = $('body'),
$mainWrapper = $('.main-wrapper'), $mainWrapper = $('.main-wrapper'),
$headerHeight = $('.header').outerHeight(); $headerHeight = $('.header').outerHeight();
/*______________________________ */
/*-- /*--
Custom script to call Background Custom script to call Background
Image form html data attribute Image form html data attribute
...@@ -38,6 +38,8 @@ ...@@ -38,6 +38,8 @@
} }
}); });
/*-- /*--
Mobile OffCanvas Open & Close Mobile OffCanvas Open & Close
-----------------------------------*/ -----------------------------------*/
...@@ -89,19 +91,6 @@ ...@@ -89,19 +91,6 @@
mobileOffCanvasMenu(); mobileOffCanvasMenu();
/*-- /*--
Login & Register Modal
-----------------------------------*/
$('#loginSignupModal').on('show.bs.modal', function (event) {
var $button = $(event.relatedTarget),
$target = $button.data('target-sub'),
$modal = $(this);
$modal.find('.nav-link').removeClass('active');
$modal.find('.nav-link[href="' + $target + '"]').addClass('active');
$modal.find('.tab-pane').removeClass('active show');
$modal.find('.tab-pane' + $target).addClass('active show');
})
/*--
Slick Slider Activation Slick Slider Activation
-----------------------------------*/ -----------------------------------*/
...@@ -241,97 +230,9 @@ ...@@ -241,97 +230,9 @@
}); });
/*-- /*--
MailChimp
-----------------------------------*/
$('#mc-form').ajaxChimp({
language: 'en',
callback: mailChimpResponse,
// ADD YOUR MAILCHIMP URL BELOW HERE!
url: 'http://devitems.us11.list-manage.com/subscribe/post?u=6bbb9b6f5827bd842d9640c82&amp;id=05d85f18ef'
});
function mailChimpResponse(resp) {
if (resp.result === 'success') {
$('.mailchimp-success').html('' + resp.msg).fadeIn(900);
$('.mailchimp-error').fadeOut(400);
} else if (resp.result === 'error') {
$('.mailchimp-error').html('' + resp.msg).fadeIn(900);
}
}
/*--
Scroll Up Scroll Up
-----------------------------------*/ -----------------------------------*/
$.scrollUp({ $.scrollUp({
scrollText: '<i class="fa fa-long-arrow-up"></i>', scrollText: '<i class="fa fa-long-arrow-up"></i>',
}); });
/*--
Google Map
-----------------------------------*/
$('.google-map').each(function () {
if ($(this).length) {
var $this = $(this),
$id = $this.attr('id'),
$zoom = $this.data('zoom') ? $this.data('zoom') : 12,
$lat = $this.data('lat') ? $this.data('lat') : 21.0277214,
$long = $this.data('long') ? $this.data('long') : 105.8342015;
function initialize() {
var mapOptions = {
zoom: $zoom,
scrollwheel: false,
center: new google.maps.LatLng($lat, $long),
};
var map = new google.maps.Map(document.getElementById($id), mapOptions);
var marker = new google.maps.Marker({
position: map.getCenter(),
map: map
//animation: google.maps.Animation.BOUNCE
});
}
google.maps.event.addDomListener(window, 'load', initialize);
}
});
/*--
Ajax Contact Form
-----------------------------------*/
$(function () {
// Get the form.
var form = $('#contact-form');
// Get the messages div.
var formMessages = $('.form-messege');
// Set up an event listener for the contact form.
$(form).submit(function (e) {
// Stop the browser from submitting the form.
e.preventDefault();
// Serialize the form data.
var formData = $(form).serialize();
// Submit the form using AJAX.
$.ajax({
type: 'POST',
url: $(form).attr('action'),
data: formData
})
.done(function (response) {
// Make sure that the formMessages div has the 'success' class.
formMessages.removeClass('error text-danger').addClass('success text-success mt-3').text(response);
// Clear the form.
form.find('input:not([type="submit"]), textarea').val('');
})
.fail(function (data) {
// Make sure that the formMessages div has the 'error' class.
formMessages.removeClass('success text-success').addClass('error text-danger mt-3');
// Set the message text.
if (data.responseText !== '') {
formMessages.text(data.responseText);
} else {
formMessages.text('Oops! An error occured and your message could not be sent.');
}
});
});
});
})(jQuery); })(jQuery);
class FavoriteIndustry < ApplicationRecord
belongs_to :user
belongs_to :industry
end
...@@ -2,6 +2,8 @@ class Industry < ApplicationRecord ...@@ -2,6 +2,8 @@ class Industry < ApplicationRecord
TOP_JOB_COUNT = 9 TOP_JOB_COUNT = 9
has_and_belongs_to_many :jobs has_and_belongs_to_many :jobs
has_many :favorite_industries, dependent: :destroy
validates :slug, presence: true, uniqueness: { case_sensitive: true } validates :slug, presence: true, uniqueness: { case_sensitive: true }
......
...@@ -14,4 +14,8 @@ class Job < ApplicationRecord ...@@ -14,4 +14,8 @@ class Job < ApplicationRecord
has_many :apply_jobs, dependent: :destroy has_many :apply_jobs, dependent: :destroy
has_many :favorite_jobs, dependent: :destroy has_many :favorite_jobs, dependent: :destroy
has_many :history_jobs, dependent: :destroy has_many :history_jobs, dependent: :destroy
def self.top_views
includes(:cities, :cities_jobs, :company).order(views_count: :desc).limit(LATEST_JOBS_LIMIT)
end
end end
...@@ -7,6 +7,7 @@ class User < ApplicationRecord ...@@ -7,6 +7,7 @@ class User < ApplicationRecord
has_many :apply_jobs, dependent: :destroy has_many :apply_jobs, dependent: :destroy
has_many :favorite_jobs, dependent: :destroy has_many :favorite_jobs, dependent: :destroy
has_many :history_jobs, dependent: :destroy has_many :history_jobs, dependent: :destroy
has_many :favorite_industries, dependent: :destroy
has_one_attached :cv has_one_attached :cv
...@@ -32,6 +33,20 @@ class User < ApplicationRecord ...@@ -32,6 +33,20 @@ class User < ApplicationRecord
@favorite_job_ids.include?(job.id) @favorite_job_ids.include?(job.id)
end end
def fav_industry?(industry_slug)
industry_id = Industry.find_by(slug: industry_slug).id
@fav_industry_ids ||= Set.new(favorite_industries.pluck(:industry_id))
@fav_industry_ids.include?(industry_id)
end
def industries?
favorite_industries.exists?
end
def fav_industries_ids
favorite_industries.pluck(:industry_id)
end
protected protected
def password_required? def password_required?
......
...@@ -87,6 +87,16 @@ class Solr ...@@ -87,6 +87,16 @@ class Solr
send_request(q, fq) send_request(q, fq)
end end
def suggest_jobs(arr)
parsed = arr.join(' ')
q = "industry_id: #{parsed}"
fq = []
facet = nil
sort = 'max_salary desc'
rows = 5
send_request(q, fq, facet, sort, rows)
end
def facet_query(facet_param) def facet_query(facet_param)
q = '*:*' q = '*:*'
fq = '*:*' fq = '*:*'
......
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
- provide(:title, 'All applies jobs') - provide(:title, 'All applies jobs')
/ search / search
.container.mt-5 = render 'shared/page_heading', title: 'Applies jobs', url: history_jobs_path
.section.section-padding
.container
= form_with(url: admin_applies_jobs_path, method: :get, local: true) do |f| = form_with(url: admin_applies_jobs_path, method: :get, local: true) do |f|
.row.mb-2.form-group .row.mb-2.form-group
.col-2 .col-2
...@@ -40,17 +42,14 @@ ...@@ -40,17 +42,14 @@
.col-6.d-flex.justify-content-center .col-6.d-flex.justify-content-center
= f.submit 'Export', name: 'csv',class: 'btn btn-primary w-50 my-4 btn-height',data: { disable_with: false } = f.submit 'Export', name: 'csv',class: 'btn btn-primary w-50 my-4 btn-height',data: { disable_with: false }
/result /result
.container .container.mb-3
h2.my-5.text-center
| All applies jobs
.container
.no-padding.d-flex.align-items-center.flex-column .no-padding.d-flex.align-items-center.flex-column
.page-info.p-2 .page-info.p-2
= page_entries_info @apply_jobs = page_entries_info @apply_jobs
.page-info.p-2 .page-info.p-2
= paginate @apply_jobs = paginate @apply_jobs
.container .container
- @apply_jobs.each do |apply| - @apply_jobs.each do |apply|
.apply-item .apply-item
.apply-job-title .apply-job-title
...@@ -81,7 +80,7 @@ ...@@ -81,7 +80,7 @@
span.fw-normal.text-dark span.fw-normal.text-dark
= apply.created_at.strftime('%d/%m/%Y') = apply.created_at.strftime('%d/%m/%Y')
hr hr
.container .container
.no-padding.d-flex.align-items-center.flex-column .no-padding.d-flex.align-items-center.flex-column
.page-info.p-2 .page-info.p-2
= page_entries_info @apply_jobs = page_entries_info @apply_jobs
......
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
.section.section-padding .section.section-padding
.container .container
h2 .row.justify-content-center
| Resend confirmation instructions .col-lg-6.col-sm-6.col-12.flex-grow-1.mb-4
= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| = form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f|
= render "admins/shared/error_messages", resource: resource = render "admins/shared/error_messages", resource: resource
.field .field
......
- provide(:title, 'Admin Forgot password') - provide(:title, 'Admin Forgot password')
= render 'shared/page_heading', title: 'Forgot password', url: login_path
.container .section.section-padding
.container
.row.justify-content-center .row.justify-content-center
.col-6 .col-lg-6.col-sm-6.col-12.flex-grow-1.mb-4
h2.text-center.my-5
| Forgot password
= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| = form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f|
= render 'admins/shared/error_messages', resource: resource = render 'admins/shared/error_messages', resource: resource
.field.row.form-group.mb-4 .field.row.form-group.mb-4
.col-2 .col-lg-2.col-sm-2.col-12
= f.label :email, class: 'form-label' = f.label :email, class: 'form-label'
.col-10 .col-lg-10.col-sm-10.col-12
= f.email_field :email, autofocus: true, autocomplete: 'email', class: 'form-control mb-2' = f.email_field :email, autofocus: true, autocomplete: 'email', class: 'form-control mb-2'
span.form-msg span.form-msg
- if devise_mapping.confirmable? && controller_name != 'confirmations' - if devise_mapping.confirmable? && controller_name != 'confirmations'
p p
= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name), class: 'text-decoration-none' = link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name), class: 'text-decoration-none'
.actions.row.justify-content-end .actions.row.justify-content-end
.col-10.d-flex.justify-content-center .col-lg-10.col-12.d-flex.justify-content-around
= f.submit 'Confirm your email', class: 'btn btn-primary w-75 my-4', data: { disable_with: false } = f.submit 'Confirm your email', class: 'btn btn-primary w-100 my-4', data: { disable_with: false }
javascript: javascript:
Validator({ Validator({
......
- provide(:title, 'Admin Sign Up') - provide(:title, 'Admin Sign Up')
.container = render 'shared/page_heading', title: 'Sign up', url: new_admin_registration_path
.section.section-padding
.container
.row.justify-content-center .row.justify-content-center
.col-6 .col-lg-6.col-sm-6.col-12.flex-grow-1.mb-4
h2.text-center.my-5
| Sign up
= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| = form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f|
= render 'users/shared/error_messages', resource: resource = render 'users/shared/error_messages', resource: resource
.field.row.form-group.mb-4 .field.row.form-group.mb-4
.col-2 .col-lg-2.col-sm-2.col-12
= f.label :email, class: 'form-label' = f.label :email, class: 'form-label'
.col-10 .col-lg-10.col-sm-10.col-12
= f.email_field :email, autofocus: true, autocomplete: 'email', class: 'form-control mb-2' = f.email_field :email, autofocus: true, autocomplete: 'email', class: 'form-control mb-2'
span.form-msg span.form-msg
.field.row.form-group.mb-4 .field.row.form-group.mb-4
.col-2 .col-lg-2.col-sm-2.col-12
= f.label :password, class: 'form-label' = f.label :password, class: 'form-label'
.col-10 .col-lg-10.col-sm-10.col-12
= f.password_field :password, autocomplete: 'new-password', class: 'form-control mb-2' = f.password_field :password, autocomplete: 'new-password', class: 'form-control mb-2'
span.form-msg span.form-msg
.field.row.form-group.mb-4 .field.row.form-group.mb-4
.col-2 .col-lg-2.col-sm-2.col-12
= f.label :password_confirmation, class: 'form-label' = f.label :password_confirmation, class: 'form-label'
.col-10 .col-lg-10.col-sm-10.col-12
= f.password_field :password_confirmation, autocomplete: 'new-password', class: 'form-control mb-2' = f.password_field :password_confirmation, autocomplete: 'new-password', class: 'form-control mb-2'
span.form-msg span.form-msg
.actions .actions.row.justify-content-end
.col-lg-10.col-12.d-flex.justify-content-around
= f.submit 'Sign up', class: 'btn btn-primary w-100 my-5' = f.submit 'Sign up', class: 'btn btn-primary w-100 my-5'
javascript: javascript:
......
- provide(:title, 'Log in') - provide(:title, 'Log in')
.container = render 'shared/page_heading', title: 'Admin Login', url: admin_login_path
.section.section-padding
.container
.row.justify-content-center .row.justify-content-center
.col-6 .col-lg-6.col-sm-6.col-12.flex-grow-1.mb-4
h2.text-center.my-5
| Log in Admin
= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| = form_for(resource, as: resource_name, url: session_path(resource_name)) do |f|
.field.row.form-group.mb-4 .field.row.form-group.mb-4
.col-2 .col-lg-2.col-sm-2.col-12
= f.label :email, class: 'form-label' = f.label :email, class: 'form-label'
.col-10 .col-lg-10.col-sm-10.col-12
= f.email_field :email, autofocus: true, autocomplete: 'email', class: 'form-control mb-2' = f.email_field :email, autofocus: true, autocomplete: 'email', class: 'form-control mb-2'
span.form-msg span.form-msg
.field.row.form-group.mb-4 .field.row.form-group.mb-4
.col-2 .col-lg-2.col-sm-2.col-12
= f.label :password, class: 'form-label' = f.label :password, class: 'form-label'
.col-10 .col-lg-10.col-sm-10.col-12
= f.password_field :password, autocomplete: 'current-password', class: 'form-control mb-2' = f.password_field :password, autocomplete: 'current-password', class: 'form-control mb-2'
span.form-msg span.form-msg
- if devise_mapping.rememberable? - if devise_mapping.rememberable?
.field .field
= f.check_box :remember_me = f.check_box :remember_me
= f.label :remember_me, class: 'form-label mx-2' = f.label :remember_me, class: 'form-label mx-2'
.d-flex.justify-content-between
- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' - if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations'
= link_to 'Forgot password?', forgot_password_path, class: 'text-decoration-none' = link_to 'Forgot password?', new_admin_password_path, class: 'text-decoration-none'
= link_to 'Sign up', new_registration_path(resource_name), class: 'text-decoration-none'
.actions.row.justify-content-end .actions.row.justify-content-end
.col-10.d-flex.justify-content-around .col-lg-10.col-12.d-flex.justify-content-around
= f.submit 'Log in', class: 'btn btn-primary w-25', data: { disable_with: false } = f.submit 'Log in', class: 'btn btn-primary w-100', data: { disable_with: false }
= link_to 'Sign up', new_registration_path(resource_name), class: 'text-decoration-none w-25 btn btn-secondary'
javascript: javascript:
Validator({ Validator({
......
- provide(:title, 'Confirmation') - provide(:title, 'Confirmation')
.container = render 'shared/page_heading', title: 'Confirm', url: '#'
.section
.container
= render 'ribbon' = render 'ribbon'
.container .container
h1.my-5.text-center
| Confirmation
.col .col
= form_with(model: @apply, scope: :apply_job, url: done_job_path, local: true) do |f| = form_with(model: @apply, scope: :apply_job, url: done_job_path, local: true) do |f|
...@@ -31,7 +32,7 @@ ...@@ -31,7 +32,7 @@
.col-2 .col-2
= f.label :cv, 'Cv: ', class: 'form-label label' = f.label :cv, 'Cv: ', class: 'form-label label'
.col-10 .col-10
span.form-control span
= url_for(@apply.cv) = url_for(@apply.cv)
= link_to 'Edit', apply_job_path(job_id: @job.id), class: 'btn btn-secondary w-25 btn-height mr-5 my-5' = link_to 'Edit', apply_job_path(job_id: @job.id), class: 'btn btn-secondary w-25 btn-height mr-5 my-5'
......
- provide(:title, 'Done') - provide(:title, 'Done')
.container = render 'shared/page_heading', title: 'Done', url: '#'
.section.py-5
.container
=render 'ribbon' =render 'ribbon'
.container.text-center .container.text-center
h3.my-4 h3.my-4
| You have successfully applied for the #{@job.title} | You have successfully applied for the #{@job.title}
p Good luck! Thank you for using our service p Good luck! Thank you for using our service
......
- provide(:title, 'Apply job') - provide(:title, 'Apply job')
.container = render 'shared/page_heading', title: 'Apply form', url: '#'
.section
.container.py-5
= render 'ribbon' = render 'ribbon'
.container .container
h1.my-5.text-center h3.fs-5.fw-bold.mb-4.text-center
| Apply Form
p.fs-5.fw-bold.mb-4.text-center
= @job.title = @job.title
.col .col
= form_with(model: @apply, url: confirm_job_path, local: true, id: 'apply-form') do |f| = form_with(model: @apply, url: confirm_job_path, local: true, id: 'apply-form') do |f|
...@@ -29,7 +30,7 @@ ...@@ -29,7 +30,7 @@
.col-2 .col-2
= f.label :cv, class: 'form-label label' = f.label :cv, class: 'form-label label'
.col-10 .col-10
= f.file_field :cv, files: @blob, accept: ApplyJob::ACCEPT_CONTENT_TYPE, class: 'form-control' = f.file_field :cv, files: @blob, accept: ApplyJob::ACCEPT_CONTENT_TYPE
span.form-msg span.form-msg
br br
= f.submit 'Confirm', class: 'btn btn-primary w-25 my-4 btn-height',data: { disable_with: false } = f.submit 'Confirm', class: 'btn btn-primary w-25 my-4 btn-height',data: { disable_with: false }
......
div id="favorite-industry-#{industry_id}"
= button_to favorite_industries_path(industry_id: industry_id, format: :js),
method: :post,
remote: true,
class: 'btn' do
i.fa.fa-heart-o.mr-1
\ No newline at end of file
div id="unfavorite-industry-#{industry_id}"
= button_to favorite_industry_path(current_user, industry_id: industry_id, format: :js),
method: :delete,
remote: true,
class: 'btn' do
i.fa.fa-heart.mr-1
\ No newline at end of file
$("#favorite-industry-<%= @industry.id %>").html("<%= escape_javascript(render('unfavorite', industry_id: @industry.id)) %>");
$("#unfavorite-industry-<%= @industry.id %>").html("<%= escape_javascript(render('favorite', industry_id: @industry.id)) %>");
...@@ -8,6 +8,18 @@ ...@@ -8,6 +8,18 @@
- @job_quantity_by_industry.each do |industry| - @job_quantity_by_industry.each do |industry|
.col-lg-6.col-sm-6.col-12.text-center .col-lg-6.col-sm-6.col-12.text-center
.mt-5 .mt-5
h3.h4.mb-2.see-more-text= link_to industry[0], industry_jobs_path(industry_slug: industry[1]) , class:'text-decoration-none fw-normal text-reset' .row
.col-10
h5.mb-2.see-more-text= link_to industry[0], industry_jobs_path(industry_slug: industry[1]) , class:'text-decoration-none fw-normal text-reset'
p.text-muted.mb-0= pluralize(industry[2], 'job') p.text-muted.mb-0= pluralize(industry[2], 'job')
.col-2
- if user_signed_in? && current_user.fav_industry?(industry[1])
= render 'favorite_industries/unfavorite', industry_id: Industry.find_by(slug: industry[1]).id
- else
= render 'favorite_industries/favorite', industry_id: Industry.find_by(slug: industry[1]).id
hr.divider.my-4 hr.divider.my-4
/ h3.h4.mb-2.see-more-text= link_to industry[0], industry_jobs_path(industry_slug: industry[1]) , class:'text-decoration-none fw-normal text-reset'
/ p.text-muted.mb-0= pluralize(industry[2], 'job')
/ hr.divider.my-4
...@@ -16,7 +16,9 @@ ...@@ -16,7 +16,9 @@
.col-lg-3.col-sm-6.col-12 .col-lg-3.col-sm-6.col-12
.footer-widget .footer-widget
.footer-widget-about .footer-widget-about
img[src="assets/images/logo/logo-light.png" alt=""] = link_to image_tag('logo.png', alt: 'Zigexn logo', width: '150'),
- root_path
p p
| Lorem ipsum dolor sit amet consecte tur adipisicing elit. Maiores officiis quod quo id inventore quis. | Lorem ipsum dolor sit amet consecte tur adipisicing elit. Maiores officiis quod quo id inventore quis.
ul.footer-socail ul.footer-socail
...@@ -35,52 +37,43 @@ ...@@ -35,52 +37,43 @@
.col-lg-3.col-sm-6.col-12 .col-lg-3.col-sm-6.col-12
.footer-widget .footer-widget
h6.title h6.title
| Quick links | Column 1
.footer-widget-link .footer-widget-link
ul ul
li li
a[href="#"] = link_to 'Item link', '#'
| Post New Job
li li
a[href="#"] = link_to 'Item link', '#'
| Jobs List
li li
a[href="#"] = link_to 'Item link', '#'
| Candidate List
li li
a[href="#"] = link_to 'Item link', '#'
| Employer List
li li
a[href="#"] = link_to 'Item link', '#'
| Browse Categories
.col-lg-3.col-sm-6.col-12 .col-lg-3.col-sm-6.col-12
.footer-widget .footer-widget
h6.title h6.title
| Tranding Jobs | Column 2
.footer-widget-link .footer-widget-link
ul ul
li li
a[href="#"] = link_to 'Item link', '#'
| Designer
li li
a[href="#"] = link_to 'Item link', '#'
| UI & UX Expert
li li
a[href="#"] = link_to 'Item link', '#'
| Develpoer
li li
a[href="#"] = link_to 'Item link', '#'
| iOS developer
li li
a[href="#"] = link_to 'Item link', '#'
| Front-End developer
.col-lg-3.col-sm-6.col-12 .col-lg-3.col-sm-6.col-12
.footer-widget .footer-widget
h6.title h6.title
| Newsletter | Newsletter
.footer-widget-newsletter .footer-widget-newsletter
p p
| Subscribe to Lawson to get all latest Job, Resume, Company Listing & Blog post to stay update. | Lorem ipsum dolor sit amet consecte tur adipisicing elit. Maiores officiis quod quo id inventore quis.
form#mc-form.mc-form form#mc-form.mc-form
input#mc-email[autocomplete="off" type="email" placeholder="Enter your e-mail address"] input#mc-email[autocomplete="off" type="email" placeholder="Enter your e-mail address"]
button#mc-submit.btn button#mc-submit.btn
...@@ -95,4 +88,3 @@ ...@@ -95,4 +88,3 @@
.col-12 .col-12
p.footer-copyright.text-center p.footer-copyright.text-center
| This is a sample website. Some functions won't work | This is a sample website. Some functions won't work
= link_to "Log out", destroy_user_session_path, method: :delete
...@@ -37,10 +37,10 @@ header.header ...@@ -37,10 +37,10 @@ header.header
.header-logo .header-logo
= link_to image_tag('logo.png', alt: 'Zigexn logo', width: '150'), = link_to image_tag('logo.png', alt: 'Zigexn logo', width: '150'),
- root_path - root_path
- unless user_signed_in? || admin_signed_in?
.col-auto.d-lg-none.d-flex.align-items-center .col-auto.d-lg-none.d-flex.align-items-center
button.offcanvas-toggle button.offcanvas-toggle
span span
- unless user_signed_in? || admin_signed_in?
.header-links.col-auto.order-lg-3 .header-links.col-auto.order-lg-3
= link_to "Log in", login_path = link_to "Log in", login_path
span or span or
...@@ -64,8 +64,9 @@ header.header ...@@ -64,8 +64,9 @@ header.header
ul.sub-menu ul.sub-menu
li.has-children li.has-children
= link_to "Applies job", admin_applies_jobs_path = link_to "Applies job", admin_applies_jobs_path
hr
li.has-children li.has-children
= button_to "Sign out", destroy_admin_session_path, method: :delete = button_to "Sign out", destroy_admin_session_path, class: 'logout', method: :delete
- if user_signed_in? - if user_signed_in?
li li
= link_to "Profile", user_profile_path = link_to "Profile", user_profile_path
...@@ -78,9 +79,9 @@ header.header ...@@ -78,9 +79,9 @@ header.header
= link_to "Favorite", favorite_jobs_path = link_to "Favorite", favorite_jobs_path
li.has-children li.has-children
= link_to "Profile", user_profile_path = link_to "Profile", user_profile_path
hr
li.has-children li.has-children
= button_to "Log out", destroy_user_session_path, method: :delete = button_to "Log out", destroy_user_session_path, class: 'logout', method: :delete
= link_to "Log out", destroy_user_session_path, data: {method: 'delete'}
#offcanvas.offcanvas-section #offcanvas.offcanvas-section
button.offcanvas-close[data-target="#offcanvas"] button.offcanvas-close[data-target="#offcanvas"]
......
...@@ -12,8 +12,13 @@ html ...@@ -12,8 +12,13 @@ html
= yield(:head) = yield(:head)
body body
= render 'layouts/header' = render 'layouts/header'
.flash
- flash.each do |message_type, message| - flash.each do |message_type, message|
div class=("text-center alert alert-#{message_type}") = message div class=("m-0 text-center alert alert-#{message_type}")
= message
.text-center
a.btn-close close
= yield = yield
= render 'layouts/footer' = render 'layouts/footer'
= javascript_pack_tag 'main' = javascript_pack_tag 'main'
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
li.breadcrumb-item li.breadcrumb-item
= link_to 'Home', root_path = link_to 'Home', root_path
li.breadcrumb-item.active li.breadcrumb-item.active
= link_to title, url = link_to title, url: '#'
- if params[:city_slug] || params[:industry_slug] - if params[:city_slug] || params[:industry_slug]
li.breadcrumb-item.active li.breadcrumb-item.active
= name = name
\ No newline at end of file
.section.section-padding
.container
.section-title
h2.title
= title
p
= desc
.job-list-wrap
- jobs.each do |job|
= link_to job, class: 'job-list' do
.company-logo.col-auto
= image_tag('company-logo', width: '70', height: '70')
.salary-type.col-auto.order-sm-3
span.salary-range
= job.salary
span.badge.badge-success
= job.job_type
.content.col
h6.title
= job.title
ul.meta
li
strong.text-primary
= job.company.name
li
i.fa.fa-map-marker
- city_list = job.cities
= show_location(job.cities)
.text-center.mt-4.mt-lg-5
= link_to 'View All Jobs', jobs_path , class: 'btn btn-primary'
...@@ -17,37 +17,29 @@ ...@@ -17,37 +17,29 @@
= render 'shared/search' = render 'shared/search'
/ latest jobs / latest jobs
.section.section-padding = render 'section_jobs', title: 'Latest Jobs',
desc: "Here's the most recent job listed on the website.",
jobs: @latest_jobs
/ quotes
.section.section-padding.bg-parallax[data-bg-image="assets/banner-5.jpg" data-overlay="50"]
.container .container
.section-title .funfact-wrap.row
h2.title .funfact.col-12
| Latest Jobs span.counter
p | Something quotes
| Here's the most recent job listed on the website. span.title
.job-list-wrap | Something quotes
- @latest_jobs.each do |job|
= link_to job, class: 'job-list' do
.company-logo.col-auto
= image_tag('company-logo', width: '70', height: '70')
.salary-type.col-auto.order-sm-3
span.salary-range
= job.salary
span.badge.badge-success
= job.job_type
.content.col
h6.title
= job.title
ul.meta
li
strong.text-primary
= job.company.name
li
i.fa.fa-map-marker
- city_list = job.cities
= show_location(job.cities)
.text-center.mt-4.mt-lg-5
= link_to 'View All Jobs', jobs_path , class: 'btn btn-primary'
/ suggest or topviews
- if user_signed_in? && current_user.industries?
= render 'section_jobs', title: 'Recommend for you',
desc: 'Here are the hot jobs based on your favorite industries',
jobs: @suggest_jobs
- else
= render 'section_jobs', title: 'Attractive jobs',
desc: "Here's the most viewed jobs",
jobs: @attractive_jobs
/ count / count
.section.section-padding.bg-parallax[data-bg-image="assets/banner-2.jpg" data-overlay="50"] .section.section-padding.bg-parallax[data-bg-image="assets/banner-2.jpg" data-overlay="50"]
.container .container
......
- provide(:title, 'Sign Up') - provide(:title, 'Sign Up')
= render 'shared/page_heading', title: 'Signup', url: signup_path = render 'shared/page_heading', title: 'Sign up', url: signup_path
.section.section-padding .section.section-padding
......
.container.text-center - provide(:title, 'Send email')
h2.my-5
| Register = render 'shared/page_heading', title: 'Check you email'
.section.section-padding
.container.text-center
p p
| 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. | 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.
p p
......
...@@ -27,6 +27,7 @@ Rails.application.routes.draw do ...@@ -27,6 +27,7 @@ Rails.application.routes.draw do
resources :cities, only: %i[index] resources :cities, only: %i[index]
resources :industries, only: %i[index] resources :industries, only: %i[index]
resources :favorite_jobs, only: %i[index create destroy] resources :favorite_jobs, only: %i[index create destroy]
resources :favorite_industries, only: %i[index create destroy]
resources :jobs, only: %i[index show] do resources :jobs, only: %i[index show] do
collection do collection do
get 'city/:city_slug', action: :index, as: :city get 'city/:city_slug', action: :index, as: :city
......
class AddViewsCountToJobs < ActiveRecord::Migration[6.1]
def change
add_column :jobs, :views_count, :integer
end
end
class CreateFavoriteIndustries < ActiveRecord::Migration[6.1]
def change
create_table :favorite_industries do |t|
t.references :user, null: false, foreign_key: true
t.references :industry, null: false, foreign_key: true
t.timestamps
end
end
end
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2021_09_27_111928) do ActiveRecord::Schema.define(version: 2021_12_04_210000) do
create_table "active_storage_attachments", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| create_table "active_storage_attachments", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.string "name", null: false t.string "name", null: false
...@@ -91,6 +91,15 @@ ActiveRecord::Schema.define(version: 2021_09_27_111928) do ...@@ -91,6 +91,15 @@ ActiveRecord::Schema.define(version: 2021_09_27_111928) do
t.datetime "updated_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false
end end
create_table "favorite_industries", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.bigint "user_id", null: false
t.bigint "industry_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["industry_id"], name: "index_favorite_industries_on_industry_id"
t.index ["user_id"], name: "index_favorite_industries_on_user_id"
end
create_table "favorite_jobs", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| create_table "favorite_jobs", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.bigint "job_id", null: false t.bigint "job_id", null: false
t.bigint "user_id", null: false t.bigint "user_id", null: false
...@@ -143,6 +152,7 @@ ActiveRecord::Schema.define(version: 2021_09_27_111928) do ...@@ -143,6 +152,7 @@ ActiveRecord::Schema.define(version: 2021_09_27_111928) do
t.datetime "updated_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false
t.integer "min_salary" t.integer "min_salary"
t.integer "max_salary" t.integer "max_salary"
t.integer "views_count"
t.index ["company_id"], name: "index_jobs_on_company_id" t.index ["company_id"], name: "index_jobs_on_company_id"
end end
...@@ -183,6 +193,8 @@ ActiveRecord::Schema.define(version: 2021_09_27_111928) do ...@@ -183,6 +193,8 @@ ActiveRecord::Schema.define(version: 2021_09_27_111928) do
add_foreign_key "apply_jobs", "users" add_foreign_key "apply_jobs", "users"
add_foreign_key "cities_jobs", "cities" add_foreign_key "cities_jobs", "cities"
add_foreign_key "cities_jobs", "jobs" add_foreign_key "cities_jobs", "jobs"
add_foreign_key "favorite_industries", "industries"
add_foreign_key "favorite_industries", "users"
add_foreign_key "favorite_jobs", "jobs" add_foreign_key "favorite_jobs", "jobs"
add_foreign_key "favorite_jobs", "users" add_foreign_key "favorite_jobs", "users"
add_foreign_key "history_jobs", "jobs" add_foreign_key "history_jobs", "jobs"
......
# This file should contain all the record creation needed to seed the database with its default values. # reset views count of jobs
# The data can then be loaded with the bin/rails db:seed command (or created alongside the database with db:setup).
# Job.find_in_batches do |jobs|
# Examples: jobs.each do |job|
# job.update_attribute :views_count, 0
# movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }]) end
# Character.create(name: 'Luke', movie: movies.first) end
require 'rsolr' require 'rsolr'
namespace :solr do namespace :solr do
# rails solr:[task]
desc 'solr index data' desc 'solr index data'
task add_data: :environment do task add_data: :environment do
logger.info "start at #{Time.current}" logger.info "start at #{Time.current}"
......
...@@ -116,6 +116,7 @@ namespace :crawler do ...@@ -116,6 +116,7 @@ namespace :crawler do
benefit: benefits, benefit: benefits,
requirement: requirement, requirement: requirement,
other_info: other_info, other_info: other_info,
views_count: 0,
company_id: company_object.id }) company_id: company_object.id })
industry_objects = industries.map { |industry| Industry.find_or_create_by(name: industry, slug: industry.to_slug) } industry_objects = industries.map { |industry| Industry.find_or_create_by(name: industry, slug: industry.to_slug) }
job_object.industries << industry_objects job_object.industries << industry_objects
...@@ -123,6 +124,7 @@ namespace :crawler do ...@@ -123,6 +124,7 @@ namespace :crawler do
cities = job_page.css('.job-detail-content .detail-box .map p a').map(&:text) cities = job_page.css('.job-detail-content .detail-box .map p a').map(&:text)
city_objects = cities.map { |city| City.find_or_create_by(name: city, slug: city.to_slug) } city_objects = cities.map { |city| City.find_or_create_by(name: city, slug: city.to_slug) }
job_object.cities << city_objects job_object.cities << city_objects
rescue URI::InvalidURIError => e rescue URI::InvalidURIError => e
puts "[Error] #{e.message}" puts "[Error] #{e.message}"
logger.error "URI must be ascii only : #{url}" logger.error "URI must be ascii only : #{url}"
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
"name": "ven-job", "name": "ven-job",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@babel/plugin-proposal-private-methods": "^7.16.0",
"@popperjs/core": "^2.9.2", "@popperjs/core": "^2.9.2",
"@rails/actioncable": "^6.0.0", "@rails/actioncable": "^6.0.0",
"@rails/activestorage": "^6.0.0", "@rails/activestorage": "^6.0.0",
......
require "test_helper"
class FavoriteIndustriesControllerTest < ActionDispatch::IntegrationTest
# test "the truth" do
# assert true
# end
end
# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
one:
user: one
industry: one
two:
user: two
industry: two
require "test_helper"
class FavoriteIndustryTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
end
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