Skip to content
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

Feature: Job Posts #115

Draft
wants to merge 31 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
3e90872
Initial commit (scaffolding)
chtzvt Dec 31, 2023
2f75bb3
add models for job posts and applications
chtzvt Mar 11, 2024
8c6daa0
Job posts scaffolding
chtzvt Mar 12, 2024
b3c43df
Merge branch 'main' into job-posts
chtzvt Apr 1, 2024
3ca13a7
Merge branch 'main' into job-posts
chtzvt Apr 2, 2024
dc45221
Add views and crud controller functions for job posts
malexander15 Apr 2, 2024
a82f50d
Merge branch 'main' of github.com:TampaDevs/talent.tampa.dev into job…
malexander15 Apr 2, 2024
35c9c87
Merge branch 'job-posts' of github.com:TampaDevs/talent.tampa.dev int…
malexander15 Apr 2, 2024
de935c8
Refactor JobPosts controller, add route under /jobs
chtzvt Apr 2, 2024
d397d48
/job_posts_path/jobs_path/
chtzvt Apr 2, 2024
f115f4c
Add title to job posts
chtzvt Apr 2, 2024
1ad760a
Add the first basic view for businesses
malexander15 Apr 3, 2024
58fe7f7
Add edit button for job post functionality
malexander15 Apr 5, 2024
381be41
In Progress: Edit/create job_post functionality biz side
malexander15 Apr 9, 2024
f734203
Add stimulusJS controller for job post job_role
malexander15 Apr 10, 2024
39e73e8
Add job post show and applicant index page
malexander15 Apr 16, 2024
c44051d
Bug Fix: Job post role type and reimbursement fields are accurately r…
malexander15 Apr 16, 2024
9d02534
add style changes to job index
malexander15 Apr 16, 2024
f029ae2
Working on job post filter feature
malexander15 Apr 24, 2024
062380b
Wire up pg_search for Job Posts
chtzvt Apr 24, 2024
0cfd1f4
Update job post query
chtzvt Apr 24, 2024
e0999b0
Add status change feature for applicants of job posts.
malexander15 Apr 29, 2024
913359f
Add status change feature for applicants of job posts.
malexander15 Apr 29, 2024
ca0176c
Add job applicant filter for applicants page and add styling fixes to…
malexander15 May 2, 2024
e24384b
Add job post filter - need to make fixedfee filter adjustment
malexander15 May 14, 2024
cc9cc17
create devcontainer setup
chtzvt Mar 20, 2024
e7e720a
Update Gemfile
chtzvt Mar 23, 2024
523d397
update capybara and fix Chrome test options
chtzvt Mar 23, 2024
7229b53
complete devcontainer setup
chtzvt May 16, 2024
d48e484
Add more changes to job filter
malexander15 May 21, 2024
296423b
Add developer feature to filter job post by application
malexander15 May 29, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 4 additions & 21 deletions Dockerfile → .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM ruby:3.2.2
FROM --platform=linux/amd64 ghcr.io/rails/devcontainer/images/ruby:3.3.1

RUN set -xe \
&& apt update && apt -y upgrade
Expand All @@ -9,6 +9,7 @@ RUN echo "America/New_York" > /etc/timezone
ENV DEBIAN_FRONTEND=noninteractive

# Install Base Dependencies

RUN set -xe \
&& apt -y install --no-install-recommends curl gnupg2

Expand All @@ -28,13 +29,12 @@ RUN set -xe \

RUN set -xe \
&& curl -s https://dl-ssl.google.com/linux/linux_signing_key.pub | gpg --dearmor | tee /usr/share/keyrings/google.gpg >/dev/null \
&& echo "deb [arch=amd64 signed-by=/usr/share/keyrings/google.gpg] http://dl.google.com/linux/chrome/deb/ stable main" | tee -a /etc/apt/sources.list.d/google.list \
&& echo "deb [signed-by=/usr/share/keyrings/google.gpg] http://dl.google.com/linux/chrome/deb/ stable main" | tee /etc/apt/sources.list.d/google.list \
&& apt update \
&& apt -y install --no-install-recommends google-chrome-stable

# Create a User
RUN set -xe \
&& useradd -u 1000 -g 100 -G sudo --shell /bin/bash --no-create-home --home-dir /tmp user \
&& echo 'ALL ALL = (ALL:ALL) NOPASSWD: ALL' >> /etc/sudoers

# Install NodeJS
Expand All @@ -48,21 +48,4 @@ RUN set -xe \

# Install Application Dependencies
RUN set -xe \
&& apt -y install --no-install-recommends libpq-dev imagemagick libvips-dev libvips-tools libvips42 chromium-driver

# TEMPORARY: Install Redis & Postgres
RUN set -xe \
&& apt -y install --no-install-recommends postgresql redis

RUN set -xe \
&& rm -rf /var/lib/apt/lists/*

COPY . /app

# Install Application Gems and Yarn Packages
RUN set -xe \
&& cd /app \
&& gem install bundler --conservative \
&& bundle check || bundle install \
&& yarn install \
&& gem install foreman
&& apt -y install --no-install-recommends libpq-dev imagemagick libvips-dev libvips-tools libvips42 ruby-chromedriver-helper ruby-foreman
5 changes: 5 additions & 0 deletions .devcontainer/boot.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
bundle install

. ${NVM_DIR}/nvm.sh && nvm install --lts
yarn install

39 changes: 39 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "Tampa Devs Talent",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"remoteUser": "vscode",
"runArgs": ["--platform=linux/amd64" ],
"workspaceFolder": "/talent.tampa.dev",
"postCreateCommand": ".devcontainer/boot.sh",
"forwardPorts": [
3000,
5432,
6379
],
"features": {
"ghcr.io/devcontainers/features/github-cli:1": {},
"ghcr.io/devcontainers/features/node:1": {
"version": "latest"
}
},

"customizations": {
"vscode": {
"settings": {
"files.associations": {
"*.html.erb": "erb"
},
"ruby.format": true
},
"extensions": [
"Shopify.ruby-lsp",
"misogi.ruby-rubocop",
"redhat.vscode-yaml",
"GitHub.codespaces",
"GitHub.copilot",
"GitHub.copilot-chat"
]
}
}
}
42 changes: 42 additions & 0 deletions .devcontainer/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
version: '3.1'

services:
postgres:
container_name: tdt-postgres
restart: always
image: postgres:latest
environment:
POSTGRES_PASSWORD: tdtalent
volumes:
- tdt-pg:/var/lib/postgresql/data
ports:
- 5432:5432
redis:
container_name: tdt-redis
image: redis:6.2-alpine
restart: always
ports:
- '6379:6379'
command: redis-server --save 20 1 --loglevel warning
volumes:
- tdt-redis:/data
app:
user: vscode
build:
context: ..
dockerfile: .devcontainer/Dockerfile
volumes:
- ..:/talent.tampa.dev:cached
command: sleep infinity
links:
- postgres
- redis
environment:
- DATABASE_URL=postgres://postgres:tdtalent@postgres/
- RAILS_ENV=development
- REDIS_URL=redis://redis:6379/1
volumes:
tdt-redis:
driver: local
tdt-pg:
driver: local
2 changes: 1 addition & 1 deletion .ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.2.2
3.3.1
4 changes: 3 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby "3.2.2"
ruby "3.3.1"

gem "rails", "~> 7.0.8.1"

Expand Down Expand Up @@ -74,3 +74,5 @@ gem "timezone_finder"
gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw, :jruby]

gem "analytics-ruby", "~> 2.4"

gem "psych", "~> 5.1"
6 changes: 5 additions & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,8 @@ GEM
method_source (~> 1.0)
pry-rails (0.3.9)
pry (>= 0.10.4)
psych (5.1.2)
stringio
public_suffix (5.0.4)
puma (6.4.2)
nio4r (~> 2.0)
Expand Down Expand Up @@ -453,6 +455,7 @@ GEM
rubocop-performance (~> 1.20.2)
stimulus-rails (0.7.2)
rails (>= 6.0.0)
stringio (3.1.0)
stripe (8.0.0)
tarpon (0.4.0)
http (~> 4.4)
Expand Down Expand Up @@ -533,6 +536,7 @@ DEPENDENCIES
prawn-rails
pretender
pry-rails
psych (~> 5.1)
puma
pundit
rack-attack
Expand All @@ -558,7 +562,7 @@ DEPENDENCIES
webmock

RUBY VERSION
ruby 3.2.2p53
ruby 3.3.1p55

BUNDLED WITH
2.3.25
1 change: 1 addition & 0 deletions app/assets/images/icons/solid/dollar_bill.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions app/assets/images/icons/solid/geo_indicator.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions app/assets/images/icons/solid/office_building.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 40 additions & 0 deletions app/components/job_posts/job_post_component.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<div class="bg-white hover:bg-blue-50 px-6 py-4 border-b border-gray-100 shadow rounded-lg mb-4">
<div class="flex items-center space-x-4">
<%= render AvatarComponent.new(avatarable: @job_post.business, variant: :medium, classes: "h-12 w-12 rounded-full") %>
<div class="flex-1 min-w-0">
<h3 class="text-lg font-medium text-blue-900 truncate" title="<%= @job_post.title %>">
<%= link_to @job_post.title, job_path(@job_post) %>
</h3>
<span class="text-sm text-gray-600"><%= @job_post.business.company %></span>
</div>
</div>

<div class="mt-4 space-y-2">
<div class="flex items-center">
<%= image_tag("icons/solid/briefcase.svg", class: "h-5 w-5 text-gray-700 mr-2") %>
<span class="text-sm font-medium text-gray-700"><%= @job_post.role_type.humanize %></span>
</div>
<div class="flex items-center">
<%= image_tag("icons/solid/dollar_bill.svg", class: "h-5 w-5 text-gray-700 mr-2") %>
<span class="text-sm font-medium text-gray-700"><%= formatted_reimbursement %></span>
</div>
<div class="flex items-center">
<%= image_tag("icons/solid/geo_indicator.svg", class: "h-5 w-5 text-gray-700 mr-2") %>
<span class="text-sm font-medium text-gray-700"><%= @job_post.role_location.humanize %></span>
</div>
<div class="flex items-center">
<%= image_tag("icons/solid/office_building.svg", class: "h-5 w-5 text-gray-700 mr-2") %>
<span class="text-sm font-medium text-gray-700"><%= @job_post.role_level.level.to_s.humanize %></span>
</div>
</div>

<div class="mt-4 flex justify-end space-x-2">
<% if @current_user.present? && @job_post.business == @current_user.business %>
<%= link_to "Applications", applicants_job_path(@job_post), class: "px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500" %>
<%= link_to "Edit", edit_job_path(@job_post), class: "px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-green-600 hover:bg-green-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500" %>
<% end %>
<% if @user_signed_in && @current_user&.developer.present? && !@job_post.job_applications.where(developer: @current_user.developer).exists? %>
<%= link_to "Apply", job_path(@job_post), method: :post, class: "px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-blue-500 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500" %>
<% end %>
</div>
</div>
16 changes: 16 additions & 0 deletions app/components/job_posts/job_post_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# app/components/jobpost/job_post_component.rb
class JobPosts::JobPostComponent < ViewComponent::Base
def initialize(job_post:, current_user:, user_signed_in:)
@job_post = job_post
@current_user = current_user
@user_signed_in = user_signed_in
end

def formatted_reimbursement
if @job_post.fixed_fee.present?
number_to_currency(@job_post.fixed_fee)
else
"#{number_to_currency(@job_post.salary_range_min)} - #{number_to_currency(@job_post.salary_range_max)}"
end
end
end
83 changes: 83 additions & 0 deletions app/components/job_posts/job_posts_filter_component.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<div class="px-4 sm:px-6">
<%= form_with url: jobs_path, id: form_id, method: :get do |form| %>
<h1 class="text-lg leading-6 font-medium text-blue-900 border-b border-gray-200 py-2">Filter Job Posts</h1>

<!-- Role Level with Collapse -->
<div class="py-6" data-controller="toggle accessibility" data-toggle-visibility-class="hidden">
<div class="pt-2">
<h3 class="-mx-2 -my-3 flow-root">
<%= render CollapseControlComponent.new("Role Level", collapsed: false) %>
</h3>
<div data-toggle-target="element">
<div class="space-y-4 pt-6">
<%= form.collection_check_boxes :role_level, role_levels, :last, :first, include_hidden: false do |b| %>
<div class="flex items-center">
<%= b.check_box checked: role_level_selected?(b.value), class: "h-4 w-4 border-gray-300 rounded text-blue-950 focus:ring-blue-500" %>
<%= b.label(class: "ml-3 text-blue-950 text-sm") { b.text } %>
</div>
<% end %>
</div>
</div>
</div>
</div>

<!-- Location with Collapse -->
<div class="border-t border-gray-200 py-6" data-controller="toggle accessibility" data-toggle-visibility-class="hidden">
<h3 class="-mx-2 -my-3 flow-root">
<%= render CollapseControlComponent.new("Location", collapsed: false) %>
</h3>
<div data-toggle-target="element">
<div class="space-y-4 pt-6">
<%= form.collection_check_boxes :role_location, locations, :first, :last, include_hidden: false do |b| %>
<div class="flex items-center">
<%= b.check_box checked: location_selected?(b.value), class: "h-4 w-4 border-gray-300 rounded text-blue-950 focus:ring-blue-500" %>
<%= b.label(class: "ml-3 text-blue-950 text-sm") { b.text } %>
</div>
<% end %>
</div>
</div>
</div>

<!-- Job Type with Collapse -->
<div class="border-t border-gray-200 py-6" data-controller="toggle accessibility" data-toggle-visibility-class="hidden">
<div>
<h3 class="-mx-2 -my-3 flow-root">
<%= render CollapseControlComponent.new("Role Type", collapsed: false) %>
</h3>
<div data-toggle-target="element">
<div class="space-y-4 pt-6" data-controller="role-type">
<%= form.collection_radio_buttons :role_type, role_types, :last, :first, include_hidden: false do |b| %>
<div class="flex items-center">
<%= b.radio_button checked: role_type_selected?(b.value), data: { action: "change->role-type#toggleFields", role_type_target: "roleTypeSelect" } %>
<%= b.label(class: "ml-3 text-blue-950 text-sm") { b.text } %>
</div>
<% end %>

<!-- Fixed Fee Section -->
<div data-role-type-target="fixedFee" class="hidden">
<%= form.label :fixed_fee_min, "Fixed Fee Minimum", class: "block text-sm font-medium text-gray-700" %>
<%= form.number_field :fixed_fee_min, min: 0, value: params[:fixed_fee_min] || @query.options.dig(:fixed_fee, :min), class: "mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md" %>
<%= form.label :fixed_fee_max, "Fixed Fee Maximum", class: "block text-sm font-medium text-gray-700" %>
<%= form.number_field :fixed_fee_max, min: 0, value: params[:fixed_fee_max] || @query.options.dig(:fixed_fee, :max), class: "mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md" %>
</div>

<!-- Salary Range Section -->
<div data-role-type-target="salaryRange" class="hidden">
<%= form.label :salary_range_min, "Minimum Salary", class: "block text-sm font-medium text-gray-700" %>
<%= form.number_field :salary_range_min, min: 0, value: params[:salary_range_min] || @query.options.dig(:salary_range, :min), class: "mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md" %>
<%= form.label :salary_range_max, "Maximum Salary", class: "block text-sm font-medium text-gray-700" %>
<%= form.number_field :salary_range_max, min: 0, value: params[:salary_range_max] || @query.options.dig(:salary_range, :max), class: "mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md" %>
</div>
</div>
</div>
</div>
</div>


<!-- Submit Button -->
<div class="flex justify-end space-x-2 pb-8">
<%= form.submit "Filter", class: "inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-blue-500 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500" %>
<%= link_to "Clear", jobs_path, class: "inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-gray-500 hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500" %>
</div>
<% end %>
</div>
44 changes: 44 additions & 0 deletions app/components/job_posts/job_posts_filter_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
module JobPosts
class JobPostsFilterComponent < ViewComponent::Base
attr_reader :form_id, :query, :user

def initialize(query:, user:, form_id: 'job-filter-form')
@query = query
@user = user
@form_id = form_id
@developer_signed_in = user.developer.present?
end

def role_level_selected?(level)
query.options[:role_level]&.include?(level.to_s)
end

def role_type_selected?(type)
query.options[:role_type]&.include?(type.to_s)
end

def location_selected?(location)
query.options[:role_location]&.include?(location)
end

def role_levels
RoleLevel::TYPES.map { |type| [type.to_s.humanize, type] }
end

def role_types
RoleType::TYPES.map { |type| [type.to_s.humanize, type] }
end

def locations
Businesses::JobPost.role_locations.keys.map { |type| [type, type.humanize] }
end

def applied_filter_active?
params[:filter] == 'applied'
end

def all_filter_active?
params[:filter].blank? || params[:filter] == 'all'
end
end
end
1 change: 1 addition & 0 deletions app/components/nav_bar/base_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ def links
links = []
links << Link.new(t(".home"), root_path) if helpers.turbo_native_app?
links << Link.new(t(".developers"), developers_path)
links << Link.new(t(".jobposts"), jobs_path)
links << Link.new(t(".pricing"), pricing_path)
links << Link.new(t(".bootcamps"), bootcamps_path)
links << Link.new(t(".affiliates"), affiliates_path)
Expand Down