Skip to content

Commit

Permalink
feat: ability to delete a work log (#1074)
Browse files Browse the repository at this point in the history
  • Loading branch information
djaiss committed Jun 21, 2021
1 parent 9ab7101 commit f5409f9
Show file tree
Hide file tree
Showing 14 changed files with 365 additions and 28 deletions.
16 changes: 14 additions & 2 deletions app/Helpers/LogHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -1314,6 +1314,12 @@ public static function processAuditLog(AuditLog $log): string
]);
break;

case 'worklog_destroyed':
$sentence = trans('account.log_worklog_destroyed', [
'date' => $log->object->{'date'},
]);
break;

default:
$sentence = '';
break;
Expand Down Expand Up @@ -1871,21 +1877,27 @@ public static function processEmployeeLog(EmployeeLog $log): string
break;

case 'meeting_decision_updated':
$sentence = trans('account.employee_log_log_meeting_decision_updated', [
$sentence = trans('account.employee_log_meeting_decision_updated', [
'group_id' => $log->object->{'group_id'},
'group_name' => $log->object->{'group_name'},
'meeting_id' => $log->object->{'meeting_id'},
]);
break;

case 'add_guest_to_meeting':
$sentence = trans('account.employee_log_log_add_guest_to_meeting', [
$sentence = trans('account.employee_log_add_guest_to_meeting', [
'group_id' => $log->object->{'group_id'},
'group_name' => $log->object->{'group_name'},
'meeting_id' => $log->object->{'meeting_id'},
]);
break;

case 'worklog_destroyed':
$sentence = trans('account.employee_log_worklog_destroyed', [
'date' => $log->object->{'date'},
]);
break;

case 'expense_destroyed':
$sentence = trans('account.employee_log_expense_destroyed', [
'expense_title' => $log->object->{'expense_title'},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use App\Jobs\UpdateDashboardPreference;
use App\Http\ViewHelpers\Dashboard\DashboardViewHelper;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use App\Services\Company\Employee\Worklog\DestroyWorklog;
use App\Http\ViewHelpers\Dashboard\DashboardTeamViewHelper;

class DashboardTeamController extends Controller
Expand Down Expand Up @@ -159,4 +160,32 @@ public function worklogDetails(Request $request, int $companyId, int $teamId, $r
'currentDate' => $requestedDate->format('Y-m-d'),
]);
}

/**
* Delete the worklog.
*
* @param Request $request
* @param int $companyId
* @param int $teamId
* @param int $worklogId
* @param int $employeeId
* @return JsonResponse
*/
public function destroyWorkLog(Request $request, int $companyId, int $teamId, int $worklogId, int $employeeId): JsonResponse
{
$loggedEmployee = InstanceHelper::getLoggedEmployee();

$data = [
'company_id' => $companyId,
'author_id' => $loggedEmployee->id,
'employee_id' => $employeeId,
'worklog_id' => $worklogId,
];

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

return response()->json([
'data' => true,
], 200);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@
use App\Helpers\InstanceHelper;
use App\Models\Company\Employee;
use App\Helpers\PermissionHelper;
use Illuminate\Http\JsonResponse;
use App\Helpers\NotificationHelper;
use App\Http\Controllers\Controller;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use App\Http\ViewHelpers\Employee\EmployeeShowViewHelper;
use App\Http\ViewHelpers\Employee\EmployeeWorkViewHelper;
use App\Services\Company\Employee\Worklog\DestroyWorklog;

class EmployeeWorkController extends Controller
{
Expand Down Expand Up @@ -46,7 +48,7 @@ public function show(Request $request, int $companyId, int $employeeId)
// worklogs
$startOfWeek = Carbon::now()->setTimezone($loggedEmployee->timezone)->startOfWeek();
$currentDay = Carbon::now()->setTimezone($loggedEmployee->timezone);
$worklogsCollection = EmployeeWorkViewHelper::worklog($employee, $loggedEmployee, $startOfWeek, $currentDay);
$worklogs = EmployeeWorkViewHelper::worklog($employee, $loggedEmployee, $startOfWeek, $currentDay);
$weeks = EmployeeWorkViewHelper::weeks($loggedEmployee);

// work from home
Expand All @@ -69,7 +71,7 @@ public function show(Request $request, int $companyId, int $employeeId)
'employee' => $employee,
'permissions' => $permissions,
'notifications' => NotificationHelper::getNotifications(InstanceHelper::getLoggedEmployee()),
'worklog' => $worklogsCollection,
'worklog' => $worklogs,
'weeks' => $weeks,
'workFromHomes' => $workFromHomeStats,
'ships' => $ships,
Expand Down Expand Up @@ -117,4 +119,31 @@ public function worklogDay(Request $request, int $companyId, int $employeeId, st
'data' => $worklog,
], 200);
}

/**
* Delete the worklog.
*
* @param Request $request
* @param int $companyId
* @param int $employeeId
* @param int $worklogId
* @return JsonResponse
*/
public function destroyWorkLog(Request $request, int $companyId, int $employeeId, int $worklogId): JsonResponse
{
$loggedEmployee = InstanceHelper::getLoggedEmployee();

$data = [
'company_id' => $companyId,
'author_id' => $loggedEmployee->id,
'employee_id' => $employeeId,
'worklog_id' => $worklogId,
];

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

return response()->json([
'data' => true,
], 200);
}
}
1 change: 1 addition & 0 deletions app/Http/ViewHelpers/Employee/EmployeeWorkViewHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public static function worklog(Employee $employee, Employee $loggedEmployee, Car
$array = [
'days' => $daysCollection,
'current_week' => $startOfWeek->copy()->format('Y-m-d'),
'id' => $worklog ? $worklog->id : null,
'worklog_parsed_content' => $worklog ? StringHelper::parse($worklog->content) : null,
'morale' => $morale && $loggedEmployee->id == $employee->id ? $morale->emoji : null,
];
Expand Down
5 changes: 3 additions & 2 deletions app/Models/Company/Team.php
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public function worklogsForDate(Carbon $date, Employee $loggedEmployee): Collect
['employee_team.team_id', '=', $this->id],
['employees.locked', '=', false],
])
->select('worklogs.content', 'employees.id', 'employees.first_name', 'employees.email', 'employees.last_name', 'employees.avatar_file_id')
->select('worklogs.content', 'worklogs.id as worklog_id', 'employees.id', 'employees.first_name', 'employees.email', 'employees.last_name', 'employees.avatar_file_id')
->get();

$worklogCollection = collect();
Expand All @@ -156,7 +156,8 @@ public function worklogsForDate(Carbon $date, Employee $loggedEmployee): Collect

$worklogCollection->push([
'content' => $worklog->content,
'id' => $worklog->id,
'id' => $worklog->worklog_id,
'employee_id' => $employee->id,
'first_name' => $employee->first_name,
'email' => $employee->email,
'last_name' => $employee->last_name,
Expand Down
23 changes: 23 additions & 0 deletions app/Services/BaseService.php
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,29 @@ public function canBypassPermissionLevelIfEmployee(int $employeeId): self
return $this;
}

/**
* Sets the permission to bypass the minimum level requirement necessary to
* execute the service if the author who calls it is actually the employee
* or the manager.
*
* @param int $employeeId
* @return self
*/
public function canBypassPermissionLevelIfEmployeeOrManager(int $managerId, int $employeeId): self
{
$manager = Employee::where('company_id', $this->companyId)
->findOrFail($managerId);

$isManager = $manager->isManagerOf($employeeId);
$this->bypassRequiredPermissionLevel = $isManager;

if ($this->bypassRequiredPermissionLevel === false) {
$this->bypassRequiredPermissionLevel = ($this->authorId == $employeeId);
}

return $this;
}

/**
* Get the validation rules that apply to the service.
*
Expand Down
75 changes: 75 additions & 0 deletions app/Services/Company/Employee/Worklog/DestroyWorklog.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php

namespace App\Services\Company\Employee\Worklog;

use Carbon\Carbon;
use App\Jobs\LogAccountAudit;
use App\Services\BaseService;
use App\Jobs\LogEmployeeAudit;
use App\Models\Company\Worklog;

class DestroyWorklog extends BaseService
{
/**
* Get the validation rules that apply to the service.
*
* @return array
*/
public function rules(): array
{
return [
'company_id' => 'required|integer|exists:companies,id',
'author_id' => 'required|integer|exists:employees,id',
'employee_id' => 'required|integer|exists:employees,id',
'worklog_id' => 'required|integer|exists:worklogs,id',
];
}

/**
* Destroy a work log.
*
* @param array $data
* @return bool
*/
public function execute(array $data): bool
{
$this->validateRules($data);

$this->author($data['author_id'])
->inCompany($data['company_id'])
->asAtLeastHR()
->canBypassPermissionLevelIfEmployeeOrManager($data['author_id'], $data['employee_id'])
->canExecuteService();

$this->validateEmployeeBelongsToCompany($data);

$worklog = Worklog::where('employee_id', $data['employee_id'])
->findOrFail($data['worklog_id']);

$worklog->delete();

LogAccountAudit::dispatch([
'company_id' => $data['company_id'],
'action' => 'worklog_destroyed',
'author_id' => $this->author->id,
'author_name' => $this->author->name,
'audited_at' => Carbon::now(),
'objects' => json_encode([
'date' => $worklog->created_at->format('Y-m-d'),
]),
])->onQueue('low');

LogEmployeeAudit::dispatch([
'employee_id' => $data['employee_id'],
'action' => 'worklog_destroyed',
'author_id' => $this->author->id,
'author_name' => $this->author->name,
'audited_at' => Carbon::now(),
'objects' => json_encode([
'date' => $worklog->created_at->format('Y-m-d'),
]),
])->onQueue('low');

return true;
}
}
71 changes: 58 additions & 13 deletions resources/js/Pages/Dashboard/Team/Partials/Worklogs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -95,16 +95,36 @@
</p>

<!-- no worklogs yet -->
<div v-show="updatedWorklogEntries.length == 0" class="tc mt2">
😢 {{ $t('dashboard.team_worklog_blank') }}
<div v-if="localWorklogEntries.length === 0" class="tc mt2">
<span class="mr1">
😢
</span> {{ $t('dashboard.team_worklog_blank') }}
</div>

<!-- list of worklogs -->
<div v-for="worklogEntry in updatedWorklogEntries" :key="worklogEntry.id" class="worklog-entry bb-gray">
<small-name-and-avatar
:name="worklogEntry.name"
:avatar="worklogEntry.avatar"
/>
<div v-for="worklogEntry in localWorklogEntries" :key="worklogEntry.id" class="worklog-entry bb-gray">
<!-- name + delete action (if allowed to) -->
<div class="flex justify-between">
<small-name-and-avatar
:name="worklogEntry.name"
:avatar="worklogEntry.avatar"
/>

<span v-if="worklogEntry.can_delete_worklog && idToDelete !== worklogEntry.id" class="f6 gray bb b--dotted bt-0 bl-0 br-0 pointer di c-delete" @click="showDeleteMode(worklogEntry.id)">
{{ $t('app.delete') }}
</span>
<span v-if="idToDelete === worklogEntry.id" class="f6">
{{ $t('app.sure') }}
<a class="c-delete mr1 pointer" @click.prevent="destroy(worklogEntry.id, worklogEntry.employee_id)">
{{ $t('app.yes') }}
</a>
<a class="pointer" @click.prevent="hideDeleteMode()">
{{ $t('app.no') }}
</a>
</span>
</div>

<!-- content -->
<div class="lh-copy content mt2 br3" v-html="worklogEntry.content">
</div>
</div>
Expand Down Expand Up @@ -152,17 +172,19 @@ export default {
data() {
return {
updatedWorklogEntries: null,
updatedCurrentDate: null,
localWorklogEntries: null,
localCurrentDate: null,
currentWorklogDate: {},
deleteMode: false,
idToDelete: 0,
form: {
errors: [],
},
};
},
created() {
this.updatedWorklogEntries = this.worklogEntries;
this.localWorklogEntries = this.worklogEntries;
this.currentWorklogDate = this.worklogDates.filter(function (item) {
return (item.status == 'current');
})[0];
Expand All @@ -177,17 +199,40 @@ export default {
},
methods: {
showDeleteMode(id) {
this.deleteMode = true;
this.idToDelete = id;
},
hideDeleteMode() {
this.deleteMode = false;
this.idToDelete = 0;
},
load(worklogDate) {
axios.get('/' + this.company.id + '/dashboard/team/' + this.currentTeam + '/' + worklogDate.friendlyDate)
axios.get(`/${this.company.id}/dashboard/team/${this.currentTeam}/${worklogDate.friendlyDate}`)
.then(response => {
this.updatedWorklogEntries= response.data.worklogEntries;
this.updatedCurrentDate = response.data.currentDate;
this.localWorklogEntries= response.data.worklogEntries;
this.localCurrentDate = response.data.currentDate;
this.currentWorklogDate = worklogDate;
})
.catch(error => {
this.form.errors = error.response.data;
});
},
destroy(worklogId, employeeId) {
axios.delete(`/${this.company.id}/dashboard/team/${this.currentTeam}/${worklogId}/${employeeId}`)
.then(response => {
this.hideDeleteMode();
var id = this.localWorklogEntries.findIndex(x => x.id === worklogId);
this.localWorklogEntries.splice(id, 1);
})
.catch(error => {
this.form.errors = error.response.data;
});
}
}
};
</script>

0 comments on commit f5409f9

Please sign in to comment.