Browse Source

Add user activities tab on the project detail page

pull/72/head
Nafies Luthfi 5 years ago
parent
commit
aed240710d
  1. 11
      app/Entities/Users/Activity.php
  2. 24
      app/Http/Controllers/Projects/ActivityController.php
  3. 1
      app/Providers/AppServiceProvider.php
  4. 9
      resources/lang/de/activity.php
  5. 2
      resources/lang/de/project.php
  6. 9
      resources/lang/en/activity.php
  7. 2
      resources/lang/en/project.php
  8. 9
      resources/lang/id/activity.php
  9. 2
      resources/lang/id/project.php
  10. 22
      resources/views/projects/activities/index.blade.php
  11. 3
      resources/views/projects/partials/nav-tabs.blade.php
  12. 4
      resources/views/users/activities/activity_list_item.blade.php
  13. 15
      resources/views/users/activities/projects/job_deleted.blade.php
  14. 11
      resources/views/users/activities/projects/project_created.blade.php
  15. 22
      resources/views/users/activities/projects/project_updated.blade.php
  16. 5
      routes/web/projects.php
  17. 34
      tests/Unit/Models/ActivityTest.php

11
app/Entities/Users/Activity.php

@ -2,6 +2,7 @@
namespace App\Entities\Users;
use App\Entities\Users\User;
use Illuminate\Database\Eloquent\Model;
class Activity extends Model
@ -11,4 +12,14 @@ class Activity extends Model
protected $fillable = ['type', 'parent_id', 'user_id', 'object_id', 'object_type', 'data'];
protected $casts = ['data' => 'array'];
public function user()
{
return $this->belongsTo(User::class)->withDefault(['name' => 'n/a']);
}
public function object()
{
return $this->morphTo();
}
}

24
app/Http/Controllers/Projects/ActivityController.php

@ -0,0 +1,24 @@
<?php
namespace App\Http\Controllers\Projects;
use App\Entities\Projects\Project;
use App\Entities\Users\Activity;
use App\Http\Controllers\Controller;
class ActivityController extends Controller
{
public function index(Project $project)
{
$activityQuery = Activity::query();
$activityQuery->where(function ($query) use ($project) {
$query->where('object_id', $project->id);
$query->where('object_type', 'projects');
});
$activities = $activityQuery->latest()->paginate();
return view('projects.activities.index', compact('project', 'activities'));
}
}

1
app/Providers/AppServiceProvider.php

@ -25,6 +25,7 @@ class AppServiceProvider extends ServiceProvider
'projects' => 'App\Entities\Projects\Project',
'issues' => 'App\Entities\Projects\Issue',
'jobs' => 'App\Entities\Projects\Job',
'tasks' => 'App\Entities\Projects\Task',
]);
Paginator::useBootstrap();
}

9
resources/lang/de/activity.php

@ -0,0 +1,9 @@
<?php
return [
'projects' => [
'project_created' => 'Project created: <strong>:name</strong> new <strong>:user</strong>.',
'project_updated' => 'Project data <strong>:name</strong> updated by <strong>:user</strong>.',
'job_deleted' => 'Job deleted by <strong>:user</strong>.',
],
];

2
resources/lang/de/project.php

@ -59,6 +59,7 @@ return [
'proposal_date' => 'Datum des Angebotes',
'project_value' => 'Projektwert',
'proposal_value' => 'Angebotswert',
'updated_at' => 'Last Update',
// Relations
'files' => 'Dokumentenliste',
@ -72,6 +73,7 @@ return [
'status' => 'Projektstatus',
'payments' => 'Zahlungen',
'issues' => 'Issues',
'activities' => 'Activities',
// Statuses
'planned' => 'geplant',

9
resources/lang/en/activity.php

@ -0,0 +1,9 @@
<?php
return [
'projects' => [
'project_created' => 'Project created: <strong>:name</strong> new <strong>:user</strong>.',
'project_updated' => 'Project data <strong>:name</strong> updated by <strong>:user</strong>.',
'job_deleted' => 'Job deleted by <strong>:user</strong>.',
],
];

2
resources/lang/en/project.php

@ -59,6 +59,7 @@ return [
'proposal_date' => 'Proposal Date',
'project_value' => 'Project Value',
'proposal_value' => 'Proposal Value',
'updated_at' => 'Last Update',
// Relations
'files' => 'Document List',
@ -72,6 +73,7 @@ return [
'status' => 'Project Status',
'payments' => 'Payments',
'issues' => 'Issues',
'activities' => 'Activities',
// Statuses
'planned' => 'Planned',

9
resources/lang/id/activity.php

@ -0,0 +1,9 @@
<?php
return [
'projects' => [
'project_created' => 'Input project baru: <strong>:name</strong> oleh <strong>:user</strong>.',
'project_updated' => 'Data project <strong>:name</strong> diubah oleh <strong>:user</strong>.',
'job_deleted' => 'Job dihapus oleh <strong>:user</strong>.',
],
];

2
resources/lang/id/project.php

@ -59,6 +59,7 @@ return [
'proposal_date' => 'Tanggal Proposal',
'project_value' => 'Nilai Project',
'proposal_value' => 'Nilai Proposal',
'updated_at' => 'Waktu Update',
// Relations
'files' => 'List Dokumen',
@ -72,6 +73,7 @@ return [
'status' => 'Status Project',
'payments' => 'Pembayaran',
'issues' => 'Issue',
'activities' => 'Aktifitas',
// Statuses
'planned' => 'Rencana',

22
resources/views/projects/activities/index.blade.php

@ -0,0 +1,22 @@
@extends('layouts.project')
@section('subtitle', __('project.activities'))
@section('content-project')
<div class="row">
<div class="col-md-8 col-md-offset-2">
{{ $activities->links() }}
<ul class="list-group">
@foreach($activities as $activity)
@includeWhen(
view()->exists('users.activities.'.$activity->object_type.'.'.$activity->type),
'users.activities.'.$activity->object_type.'.'.$activity->type
)
@endforeach
</ul>
{{ $activities->links() }}
</div>
</div>
@endsection

3
resources/views/projects/partials/nav-tabs.blade.php

@ -3,6 +3,9 @@
<li class="{{ Request::segment(3) == null ? 'active' : '' }}">
{!! link_to_route('projects.show', __('project.detail'), $project) !!}
</li>
<li class="{{ Request::segment(3) == 'activities' ? 'active' : '' }}">
{!! link_to_route('projects.activities.index', __('project.activities'), $project) !!}
</li>
@can('view-jobs', $project)
<li class="{{ Request::segment(3) == 'jobs' ? 'active' : '' }}">
{!! link_to_route('projects.jobs.index', __('project.jobs').' ('.$project->jobs->count().')', $project) !!}

4
resources/views/users/activities/activity_list_item.blade.php

@ -0,0 +1,4 @@
<li class="list-group-item">
<span class="label label-info pull-right">{{ $time }}</span>
{{ $body }}
</li>

15
resources/views/users/activities/projects/job_deleted.blade.php

@ -0,0 +1,15 @@
@component('users.activities.activity_list_item')
@slot('time')
{{ $activity->created_at }}
@endslot
@slot('body')
<p>
{!! __('activity.'.$activity->object_type.'.'.$activity->type, [
'user' => $activity->user->name,
]) !!}
</p>
<div>{{ __('job.name') }}: {{ $activity->data['name'] }}</div>
<div>{{ __('job.description') }}: {{ $activity->data['description'] }}</div>
<div>{{ __('job.price') }}: {{ format_money($activity->data['price']) }}</div>
@endslot
@endcomponent

11
resources/views/users/activities/projects/project_created.blade.php

@ -0,0 +1,11 @@
@component('users.activities.activity_list_item')
@slot('time')
{{ $activity->created_at }}
@endslot
@slot('body')
{!! __('activity.'.$activity->object_type.'.'.$activity->type, [
'user' => $activity->user->name,
'name' => $activity->object->name,
]) !!}
@endslot
@endcomponent

22
resources/views/users/activities/projects/project_updated.blade.php

@ -0,0 +1,22 @@
@component('users.activities.activity_list_item')
@slot('time')
{{ $activity->created_at }}
@endslot
@slot('body')
<p>
{!! __('activity.'.$activity->object_type.'.'.$activity->type, [
'user' => $activity->user->name,
'name' => $activity->object->name,
]) !!}
</p>
@php
$data = $activity->data;
@endphp
@foreach ($data['before'] as $key => $value)
@php
$afterValue = $data['after'][$key] ?? null;
@endphp
<div>{{ __('project.'.$key) }}: {{ $value }} => {{ $afterValue }}</div>
@endforeach
@endslot
@endcomponent

5
routes/web/projects.php

@ -26,6 +26,11 @@ Route::group(['middleware' => ['auth'], 'namespace' => 'Projects'], function ()
Route::get('projects/{project}/invoices', ['as' => 'projects.invoices', 'uses' => 'InvoicesController@index']);
/*
* Project Activities Routes
*/
Route::get('projects/{project}/activities', ['as' => 'projects.activities.index', 'uses' => 'ActivityController@index']);
/*
* Project Jobs Routes
*/
Route::get('projects/{project}/jobs-export/{type?}', ['as' => 'projects.jobs-export', 'uses' => 'JobsController@jobsExport']);

34
tests/Unit/Models/ActivityTest.php

@ -5,6 +5,8 @@ namespace Tests\Unit\Models;
use App\Entities\Projects\Job;
use App\Entities\Projects\Project;
use App\Entities\Projects\Task;
use App\Entities\Users\Activity;
use App\Entities\Users\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
@ -213,4 +215,36 @@ class ActivityTest extends TestCase
]),
]);
}
/** @test */
public function an_activity_has_belongs_to_user_relation()
{
$project = factory(Project::class)->create();
$activity = Activity::where('object_type', 'projects')
->where('object_id', $project->id)
->first();
$this->assertInstanceOf(User::class, $activity->user);
$this->assertEquals($activity->user_id, $activity->user->id);
}
/** @test */
public function an_activity_has_belongs_to_object_relation()
{
$project = factory(Project::class)->create();
$job = factory(Job::class)->create(['project_id' => $project->id]);
$task = factory(Task::class)->create(['job_id' => $job->id]);
$projectActivity = Activity::where('object_type', 'projects')->first();
$this->assertInstanceOf(Project::class, $projectActivity->object);
$this->assertEquals($projectActivity->object_id, $projectActivity->object->id);
$jobActivity = Activity::where('object_type', 'jobs')->first();
$this->assertInstanceOf(Job::class, $jobActivity->object);
$this->assertEquals($jobActivity->object_id, $jobActivity->object->id);
$taskActivity = Activity::where('object_type', 'tasks')->first();
$this->assertInstanceOf(Task::class, $taskActivity->object);
$this->assertEquals($taskActivity->object_id, $taskActivity->object->id);
}
}
Loading…
Cancel
Save