Skip to content

Commit

Permalink
feat: let participant participate in recruiting process (#1306)
Browse files Browse the repository at this point in the history
  • Loading branch information
djaiss committed Sep 6, 2021
1 parent 43c4ee2 commit 89da2f4
Show file tree
Hide file tree
Showing 12 changed files with 316 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public function index(): Response
'workFromHome' => DashboardMeViewHelper::workFromHome($employee),
'question' => DashboardMeViewHelper::question($employee),
'jobOpeningsAsSponsor' => DashboardMeViewHelper::jobOpeningsAsSponsor($company, $employee),
'jobOpeningsAsParticipant' => DashboardMeViewHelper::jobOpeningsAsParticipant($employee),
]);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

namespace App\Http\Controllers\Company\Dashboard\Me;

use Illuminate\Http\Request;
use App\Helpers\InstanceHelper;
use Illuminate\Http\JsonResponse;
use App\Http\Controllers\Controller;
use App\Services\Company\Adminland\JobOpening\CreateCandidateStageNote;

class DashboardMeRecruitingController extends Controller
{
/**
* Add a note as a participant of a recruiting process.
*
* @param Request $request
* @param int $companyId
* @param int $jobOpeningId
* @param int $candidateId
* @param int $candidateStageId
* @return JsonResponse
*/
public function store(Request $request, int $companyId, int $jobOpeningId, int $candidateId, int $candidateStageId): JsonResponse
{
$company = InstanceHelper::getLoggedCompany();
$employee = InstanceHelper::getLoggedEmployee();

$data = [
'author_id' => $employee->id,
'company_id' => $company->id,
'job_opening_id' => $jobOpeningId,
'candidate_id' => $candidateId,
'candidate_stage_id' => $candidateStageId,
'note' => $request->input('note'),
];

(new CreateCandidateStageNote)->execute($data);

return response()->json([
'data' => true,
], 200);
}
}
38 changes: 38 additions & 0 deletions app/Http/ViewHelpers/Dashboard/DashboardMeViewHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use App\Models\Company\ECoffeeMatch;
use App\Models\Company\OneOnOneEntry;
use App\Models\Company\EmployeeStatus;
use App\Models\Company\CandidateStageParticipant;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use App\Services\Company\Employee\OneOnOne\CreateOneOnOneEntry;

Expand Down Expand Up @@ -510,4 +511,41 @@ public static function jobOpeningsAsSponsor(Company $company, Employee $employee

return $jobsOpeningCollection;
}

/**
* Get the information about the job openings as a participant.
*
* @param Employee $employee
* @return Collection
*/
public static function jobOpeningsAsParticipant(Employee $employee): Collection
{
$stages = CandidateStageParticipant::where('participant_id', $employee->id)
->where('participated', false)
->with('candidateStage')
->with('candidateStage.candidate')
->with('candidateStage.candidate.jobOpening')
->get();

$jobOpeningsCollection = collect();
foreach ($stages as $stage) {
$jobOpening = $stage->candidateStage->candidate->jobOpening;
if (! $jobOpening->active) {
continue;
}

$jobOpeningsCollection->push([
'id' => $jobOpening->id,
'candidate_stage_id' => $stage->candidate_stage_id,
'title' => $jobOpening->title,
'participated' => false,
'candidate' => [
'id' => $stage->candidateStage->candidate->id,
'name' => $stage->candidateStage->candidate->name,
],
]);
}

return $jobOpeningsCollection;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class CreateCandidateStageNote extends BaseService
protected Candidate $candidate;
protected CandidateStage $candidateStage;
protected CandidateStageNote $candidateStageNote;
protected bool $isParticipant;

/**
* Get the validation rules that apply to the service.
Expand Down Expand Up @@ -48,6 +49,7 @@ public function execute(array $data): CandidateStageNote
$this->data = $data;
$this->validate();
$this->create();
$this->markParticipated();
$this->log();

return $this->candidateStageNote;
Expand All @@ -74,15 +76,15 @@ private function validate(): void
->exists();

// check if the author is a participant of the recruiting process
$isParticipant = DB::table('candidate_stage_participants')
$this->isParticipant = DB::table('candidate_stage_participants')
->where('participant_id', $this->data['author_id'])
->where('candidate_stage_id', $this->data['candidate_stage_id'])
->exists();

$this->author = Employee::where('company_id', $this->data['company_id'])
->findOrFail($this->data['author_id']);

if (! $isSponsor && ! $isParticipant) {
if (! $isSponsor && ! $this->isParticipant) {
$this->author = Employee::where('company_id', $this->data['company_id'])
->where('permission_level', '<=', config('officelife.permission_level.hr'))
->findOrFail($this->data['author_id']);
Expand All @@ -99,6 +101,19 @@ private function create(): void
]);
}

private function markParticipated(): void
{
if ($this->isParticipant) {
DB::table('candidate_stage_participants')
->where('participant_id', $this->data['author_id'])
->where('candidate_stage_id', $this->data['candidate_stage_id'])
->update([
'participated' => true,
'participated_at' => Carbon::now(),
]);
}
}

private function log(): void
{
LogAccountAudit::dispatch([
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions resources/js/Pages/Dashboard/Me/Index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@
:e-coffee="eCoffee"
/>

<job-openings-as-participant
v-if="jobOpeningsAsParticipant.length > 0"
:job-openings="jobOpeningsAsParticipant"
/>

<job-openings-as-sponsor
v-if="jobOpeningsAsSponsor.length > 0"
:job-openings="jobOpeningsAsSponsor"
Expand Down Expand Up @@ -86,6 +91,7 @@ import DashboardMenu from '@/Pages/Dashboard/Partials/DashboardMenu';
import ECoffee from '@/Pages/Dashboard/Me/Partials/ECoffee';
import Projects from '@/Pages/Dashboard/Me/Partials/Projects';
import JobOpeningsAsSponsor from '@/Pages/Dashboard/Me/Partials/JobOpeningSponsor';
import JobOpeningsAsParticipant from '@/Pages/Dashboard/Me/Partials/JobOpeningParticipant';
export default {
components: {
Expand All @@ -102,6 +108,7 @@ export default {
ECoffee,
Projects,
JobOpeningsAsSponsor,
JobOpeningsAsParticipant,
},
props: {
Expand Down Expand Up @@ -177,6 +184,10 @@ export default {
type: Object,
default: null,
},
jobOpeningsAsParticipant: {
type: Object,
default: null,
},
},
mounted() {
Expand Down
145 changes: 145 additions & 0 deletions resources/js/Pages/Dashboard/Me/Partials/JobOpeningParticipant.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
<style lang="scss" scoped>
.entry-item:first-child {
border-top-width: 1px;
border-top-style: solid;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
}
.entry-item:last-child {
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
}
.illustration {
top: 43px;
}
</style>

<template>
<div class="mb5">
<div class="cf mw7 center mb2 fw5 relative">
<span class="mr1">
💺
</span> {{ $t('dashboard.participant_dashboard_job_opening_title') }}

<help :url="$page.props.help_links.one_on_ones" />
</div>

<div class="cf mw7 center br3 mb3 bg-white box relative pa3">
<p class="mt0 mb2 f6 gray">{{ $t('dashboard.participant_dashboard_job_opening_desc') }}</p>

<img loading="lazy" src="/img/streamline-icon-user-rating-star-4@100x100.png" width="90" alt="meeting" class="illustration absolute-ns di-ns dn top-1 left-1" />

<ul class="pl6-ns pl3 pb3 pt3 pr3 ma0 list">
<li v-for="jobOpening in localJobOpenings" :key="jobOpening.id" class="flex justify-between items-center br bl bb bb-gray bb-gray-hover pa3 entry-item">
<div v-if="idToEdit != jobOpening.id">
<span class="db mb0">{{ jobOpening.candidate.name }}</span>
<span class="f7 gray">{{ jobOpening.title }}</span>
</div>

<!-- call to action -->
<div v-if="idToEdit != jobOpening.id && !jobOpening.participated" class="tr">
<a class="btn dib-l db" @click="showEditor(jobOpening.id)">{{ $t('dashboard.one_on_ones_cta') }}</a>
</div>

<div v-if="jobOpening.participated">
<span class="mr1">🙏</span> {{ $t('dashboard.participant_dashboard_job_opening_thanks') }}
</div>

<!-- add comment about participant -->
<div v-if="idToEdit == jobOpening.id">
<form @submit.prevent="store(jobOpening)">
<errors :errors="form.errors" :class="'mb2'" />

<text-area
:ref="'note' + jobOpening.id"
v-model="form.note"
:rows="10"
@esc-key-pressed="idToEdit = 0"
/>
<p class="db lh-copy f6">
<span class="mr1">👋</span> {{ $t('dashboard.participant_dashboard_job_opening_note') }}
</p>
<p class="ma0">
<loading-button :class="'btn add w-auto-ns w-100 pv2 ph3 mr2'" :state="loadingState" :text="$t('app.submit')" />
<a class="pointer" @click.prevent="idToEdit = 0">
{{ $t('app.cancel') }}
</a>
</p>
</form>
</div>
</li>
</ul>
</div>
</div>
</template>

<script>
import Help from '@/Shared/Help';
import LoadingButton from '@/Shared/LoadingButton';
import TextArea from '@/Shared/TextArea';
import Errors from '@/Shared/Errors';
export default {
components: {
Help,
LoadingButton,
TextArea,
Errors,
},
props: {
employee: {
type: Object,
default: null,
},
jobOpenings: {
type: Array,
default: null,
},
},
data() {
return {
idToEdit: 0,
localJobOpenings: [],
form: {
note: null,
errors: [],
},
loadingState: '',
};
},
created: function() {
this.localJobOpenings = this.jobOpenings;
},
methods: {
showEditor(id) {
this.idToEdit = id;
this.$nextTick(() => {
this.$refs[`note${id}`].focus();
});
},
store(jobOpening) {
this.loadingState = 'loading';
axios.post(`${this.$page.props.auth.company.id}/dashboard/job-openings/${jobOpening.id}/candidates/${jobOpening.candidate.id}/stages/${jobOpening.candidate_stage_id}/notes`, this.form)
.then(response => {
this.flash(this.$t('dashboard.participant_dashboard_job_opening_success'), 'success');
this.idToEdit = 0;
this.loadingState = null;
this.localJobOpenings[this.localJobOpenings.findIndex(x => x.id === jobOpening.id)].participated = true;
})
.catch(error => {
this.loadingState = null;
this.form.errors = error.response.data;
});
},
}
};
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@

<!-- add a new participant cta -->
<li v-if="!modal" class="ph2 pv3 list bb bb-gray bb-gray-hover tc">
<a class="bb b--dotted bt-0 bl-0 br-0 pointer f6" @click="showSearch()">{{ trans('dashboard.job_opening_stage_participants_cta') }}</a>
<a class="bb b--dotted bt-0 bl-0 br-0 pointer f6" @click="showSearch()">{{ $t('dashboard.job_opening_stage_participants_cta') }}</a>
</li>

<!-- modal to add -->
Expand Down
5 changes: 5 additions & 0 deletions resources/lang/en/dashboard.php
Original file line number Diff line number Diff line change
Expand Up @@ -314,4 +314,9 @@
'job_opening_stage_notes_success' => 'The note has been added.',
'job_opening_edit_title' => 'Edit job opening',
'job_opening_edit_success' => 'The job opening has been edited.',
'participant_dashboard_job_opening_title' => 'Recruiting',
'participant_dashboard_job_opening_desc' => 'You have been asked to help in the recruiting process of the candidates below.',
'participant_dashboard_job_opening_thanks' => 'Thanks!',
'participant_dashboard_job_opening_note' => 'Your feedback will be read by everyone involved in the recruiting process, except the candidate.',
'participant_dashboard_job_opening_success' => 'The note has been saved.',
];
3 changes: 3 additions & 0 deletions routes/web.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@
]);
Route::post('expense', 'Company\\Dashboard\\Me\\DashboardMeExpenseController@store')->name('dashboard.expense.store');

// add note as participant of a job opening recruitment process
Route::post('job-openings/{jobOpening}/candidates/{candidate}/stages/{stage}/notes', 'Company\\Dashboard\\Me\\DashboardMeRecruitingController@store');

// details of one on ones
Route::get('oneonones/{entry}', 'Company\\Dashboard\\Me\\DashboardMeOneOnOneController@show')->name('dashboard.oneonones.show');
Route::post('oneonones/{entry}/happened', 'Company\\Dashboard\\Me\\DashboardMeOneOnOneController@markHappened');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ public function it_fails_if_job_opening_doesnt_belong_to_company(): void
$this->executeService($michael, $opening, $candidate, $candidateStage);
}

private function executeService(Employee $author, JobOpening $opening, Candidate $candidate, CandidateStage $candidateStage): void
private function executeService(Employee $author, JobOpening $opening, Candidate $candidate, CandidateStage $candidateStage, bool $isParticipant = false): void
{
Queue::fake();

Expand All @@ -173,6 +173,14 @@ private function executeService(Employee $author, JobOpening $opening, Candidate
'author_name' => $author->name,
]);

if ($isParticipant) {
$this->assertDatabaseHas('candidate_stage_participants', [
'candidate_stage_id' => $candidateStage->id,
'participant_id' => $author->id,
'participated' => true,
]);
}

$this->assertInstanceOf(
CandidateStageNote::class,
$candidateStageNote
Expand Down

0 comments on commit 89da2f4

Please sign in to comment.