Browse Source
Merge pull request #13 from nafiesl/job-layout
Merge pull request #13 from nafiesl/job-layout
Add Job Comment and Update Job View Layoutpull/15/head
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 497 additions and 104 deletions
-
1app/Http/Controllers/Api/ProjectsController.php
-
102app/Http/Controllers/Jobs/CommentsController.php
-
9app/Http/Controllers/JobsController.php
-
27app/Policies/Projects/JobPolicy.php
-
6resources/lang/id/comment.php
-
54resources/views/jobs/comments.blade.php
-
32resources/views/jobs/partials/comment-section.blade.php
-
42resources/views/jobs/partials/job-tasks-operation.blade.php
-
25resources/views/jobs/partials/job-tasks.blade.php
-
12resources/views/jobs/partials/nav-tabs.blade.php
-
35resources/views/jobs/show.blade.php
-
2resources/views/jobs/unfinished.blade.php
-
22resources/views/layouts/job.blade.php
-
18resources/views/projects/jobs/add-from-other-project.blade.php
-
15resources/views/projects/jobs/create.blade.php
-
52resources/views/projects/jobs/index.blade.php
-
11routes/web/projects.php
-
104tests/Feature/Projects/JobCommentsTest.php
-
30tests/Unit/Policies/JobPolicyTest.php
@ -0,0 +1,102 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace App\Http\Controllers\Jobs; |
||||
|
|
||||
|
use Illuminate\Http\Request; |
||||
|
use App\Entities\Projects\Job; |
||||
|
use App\Entities\Projects\Comment; |
||||
|
use App\Http\Controllers\Controller; |
||||
|
|
||||
|
class CommentsController extends Controller |
||||
|
{ |
||||
|
/** |
||||
|
* Display a listing of the job comments. |
||||
|
* |
||||
|
* @param \App\Entities\Projects\Job $job |
||||
|
* @return \Illuminate\View\View |
||||
|
*/ |
||||
|
public function index(Job $job) |
||||
|
{ |
||||
|
$this->authorize('view-comments', $job); |
||||
|
|
||||
|
$editableComment = null; |
||||
|
$comments = $job->comments()->with('creator')->latest()->paginate(); |
||||
|
|
||||
|
if (request('action') == 'comment-edit' && request('comment_id') != null) { |
||||
|
$editableComment = Comment::find(request('comment_id')); |
||||
|
} |
||||
|
|
||||
|
return view('jobs.comments', compact('job', 'comments', 'editableComment')); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Store a new comment in storage. |
||||
|
* |
||||
|
* @param \Illuminate\Http\Request $request |
||||
|
* @param \App\Entities\Projects\Job $job |
||||
|
* @return \Illuminate\Http\RedirectResponse |
||||
|
*/ |
||||
|
public function store(Request $request, Job $job) |
||||
|
{ |
||||
|
$this->authorize('comment-on', $job); |
||||
|
|
||||
|
$newComment = $request->validate([ |
||||
|
'body' => 'required|string|max:255', |
||||
|
]); |
||||
|
|
||||
|
$job->comments()->create([ |
||||
|
'body' => $newComment['body'], |
||||
|
'creator_id' => auth()->id(), |
||||
|
]); |
||||
|
|
||||
|
flash(__('comment.created'), 'success'); |
||||
|
|
||||
|
return back(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Update the specified comment. |
||||
|
* |
||||
|
* @param \Illuminate\Http\Request $request |
||||
|
* @param \App\Entities\Projects\Job $job |
||||
|
* @param \App\Entities\Jobs\Comment $comment |
||||
|
* @return \Illuminate\Http\Response |
||||
|
*/ |
||||
|
public function update(Request $request, Job $job, Comment $comment) |
||||
|
{ |
||||
|
$this->authorize('update', $comment); |
||||
|
|
||||
|
$commentData = $request->validate([ |
||||
|
'body' => 'required|string|max:255', |
||||
|
]); |
||||
|
$comment->update($commentData); |
||||
|
flash(__('comment.updated'), 'success'); |
||||
|
|
||||
|
return redirect()->route('jobs.comments.index', [$job] + request(['page'])); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Remove the specified comment. |
||||
|
* |
||||
|
* @param \App\Entities\Jobs\Comment $comment |
||||
|
* @return \Illuminate\Routing\Redirector |
||||
|
*/ |
||||
|
public function destroy(Job $job, Comment $comment) |
||||
|
{ |
||||
|
$this->authorize('delete', $comment); |
||||
|
|
||||
|
request()->validate([ |
||||
|
'comment_id' => 'required|exists:comments,id', |
||||
|
]); |
||||
|
|
||||
|
if (request('comment_id') == $comment->id && $comment->delete()) { |
||||
|
$routeParam = [$job] + request(['page']); |
||||
|
flash(__('comment.deleted'), 'warning'); |
||||
|
|
||||
|
return redirect()->route('jobs.comments.index', $routeParam); |
||||
|
} |
||||
|
flash(__('comment.undeleted'), 'error'); |
||||
|
|
||||
|
return back(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,54 @@ |
|||||
|
@extends('layouts.job') |
||||
|
|
||||
|
@section('subtitle', __('comment.list')) |
||||
|
|
||||
|
@section('content-job') |
||||
|
<div class="row"> |
||||
|
<div class="col-md-8 col-md-offset-1"> |
||||
|
{{ $comments->links() }} |
||||
|
@include('jobs.partials.comment-section') |
||||
|
{{ $comments->links() }} |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
@if (Request::get('action') == 'comment-edit' && $editableComment) |
||||
|
<div id="commentModal" class="modal" role="dialog"> |
||||
|
<div class="modal-dialog"> |
||||
|
<!-- Modal content--> |
||||
|
<div class="modal-content"> |
||||
|
<div class="modal-header"> |
||||
|
{{ link_to_route('jobs.comments.index', '×', [$job] + request(['page']), ['class' => 'close']) }} |
||||
|
<h4 class="modal-title">{{ __('comment.edit') }}</h4> |
||||
|
</div> |
||||
|
{!! Form::model($editableComment, ['route' => ['jobs.comments.update', $job, $editableComment->id],'method' => 'patch']) !!} |
||||
|
<div class="modal-body"> |
||||
|
{!! FormField::textarea('body', ['label' => __('comment.body')]) !!} |
||||
|
{{ Form::hidden('page', request('page')) }} |
||||
|
</div> |
||||
|
<div class="modal-footer"> |
||||
|
{!! Form::submit(__('comment.update'), ['class' => 'btn btn-success']) !!} |
||||
|
{{ link_to_route('jobs.comments.index', __('app.cancel'), [$job] + request(['page']), ['class' => 'btn btn-default']) }} |
||||
|
</div> |
||||
|
{!! Form::close() !!} |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
@endif |
||||
|
@endsection |
||||
|
|
||||
|
@section('ext_css') |
||||
|
<style> |
||||
|
ul.pagination { margin-top: 0px } |
||||
|
</style> |
||||
|
@endsection |
||||
|
|
||||
|
@section('script') |
||||
|
<script> |
||||
|
(function () { |
||||
|
$('#commentModal').modal({ |
||||
|
show: true, |
||||
|
backdrop: 'static', |
||||
|
}); |
||||
|
})(); |
||||
|
</script> |
||||
|
@endsection |
||||
@ -0,0 +1,32 @@ |
|||||
|
@can('comment-on', $job) |
||||
|
{{ Form::open(['route' => ['jobs.comments.store', $job]]) }} |
||||
|
<div class="row"> |
||||
|
<div class="col-md-9">{!! FormField::textarea('body', ['required' => true, 'label' => false, 'placeholder' => __('comment.create_text')]) !!}</div> |
||||
|
<div class="col-md-3"> |
||||
|
{{ Form::submit(__('comment.create'), ['class' => 'btn btn-success btn-block']) }}<br> |
||||
|
</div> |
||||
|
</div> |
||||
|
{{ Form::close() }} |
||||
|
@endcan |
||||
|
@foreach($comments as $comment) |
||||
|
<div class="alert alert-warning"> |
||||
|
<legend style="font-size: 14px;margin-bottom: 10px;"> |
||||
|
<span class="label label-default pull-right">{{ $comment->time_display }}</span> |
||||
|
<strong>{{ $comment->creator->name }}</strong> |
||||
|
</legend> |
||||
|
<div class="pull-right"> |
||||
|
@can('update', $comment) |
||||
|
{{ link_to_route('jobs.comments.index', __('app.edit'), [$job, 'action' => 'comment-edit', 'comment_id' => $comment->id], ['id' => 'edit-comment-'.$comment->id, 'class' => 'small', 'title' => __('comment.edit')]) }} |
||||
|
@endcan |
||||
|
@can('delete', $comment) |
||||
|
{!! FormField::delete( |
||||
|
['route' => ['jobs.comments.destroy', $job, $comment], 'class' => ''], |
||||
|
'×', |
||||
|
['class' => 'btn-link', 'id' => 'delete-comment-'.$comment->id], |
||||
|
['comment_id' => $comment->id, 'page' => request('page')] |
||||
|
) !!} |
||||
|
@endcan |
||||
|
</div> |
||||
|
{!! nl2br($comment->body) !!} |
||||
|
</div> |
||||
|
@endforeach |
||||
@ -0,0 +1,12 @@ |
|||||
|
<!-- Nav tabs --> |
||||
|
<ul class="nav nav-tabs"> |
||||
|
<li class="{{ Request::segment(3) == null ? 'active' : '' }}"> |
||||
|
{!! link_to_route('jobs.show', __('job.detail'), $job) !!} |
||||
|
</li> |
||||
|
@can('view-comments', $job) |
||||
|
<li class="{{ Request::segment(3) == 'comments' ? 'active' : '' }}"> |
||||
|
{!! link_to_route('jobs.comments.index', __('comment.list').' ('.$job->comments->count().')', $job) !!} |
||||
|
</li> |
||||
|
@endcan |
||||
|
</ul> |
||||
|
<br> |
||||
@ -0,0 +1,22 @@ |
|||||
|
@extends('layouts.app') |
||||
|
|
||||
|
@section('title') |
||||
|
@yield('subtitle', __('job.detail')) - {{ $job->name }} |
||||
|
@endsection |
||||
|
|
||||
|
@section('content') |
||||
|
@include('jobs.partials.breadcrumb') |
||||
|
|
||||
|
<h1 class="page-header"> |
||||
|
<div class="pull-right"> |
||||
|
@yield('action-buttons') |
||||
|
{{ link_to_route('projects.jobs.index', __('job.back_to_index'), [$job->project_id, '#' . $job->id], ['class' => 'btn btn-default']) }} |
||||
|
</div> |
||||
|
{{ $job->name }} <small>@yield('subtitle', __('job.detail'))</small> |
||||
|
</h1> |
||||
|
|
||||
|
@include('jobs.partials.nav-tabs') |
||||
|
|
||||
|
@yield('content-job') |
||||
|
|
||||
|
@endsection |
||||
@ -0,0 +1,104 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace Tests\Feature\Projects; |
||||
|
|
||||
|
use Tests\TestCase; |
||||
|
use App\Entities\Projects\Job; |
||||
|
use App\Entities\Projects\Comment; |
||||
|
|
||||
|
class JobCommentsTest extends TestCase |
||||
|
{ |
||||
|
/** @test */ |
||||
|
public function user_can_view_job_comments() |
||||
|
{ |
||||
|
$this->adminUserSigningIn(); |
||||
|
$job = factory(Job::class)->create(); |
||||
|
$comment = factory(Comment::class)->create([ |
||||
|
'commentable_type' => 'jobs', |
||||
|
'commentable_id' => $job->id, |
||||
|
'body' => 'This is job comment.', |
||||
|
]); |
||||
|
|
||||
|
$this->visitRoute('jobs.comments.index', $job); |
||||
|
$this->seeRouteIs('jobs.comments.index', $job); |
||||
|
|
||||
|
$this->seeText('This is job comment.'); |
||||
|
} |
||||
|
|
||||
|
/** @test */ |
||||
|
public function admin_can_add_comment_to_a_job() |
||||
|
{ |
||||
|
$admin = $this->adminUserSigningIn(); |
||||
|
$job = factory(Job::class)->create(); |
||||
|
|
||||
|
$this->visitRoute('jobs.comments.index', $job); |
||||
|
|
||||
|
$this->submitForm(__('comment.create'), [ |
||||
|
'body' => 'Komentar pertama.', |
||||
|
]); |
||||
|
|
||||
|
$this->seePageIs(route('jobs.comments.index', $job)); |
||||
|
$this->see(__('comment.created')); |
||||
|
|
||||
|
$this->seeInDatabase('comments', [ |
||||
|
'commentable_type' => 'jobs', |
||||
|
'commentable_id' => $job->id, |
||||
|
'body' => 'Komentar pertama.', |
||||
|
'creator_id' => $admin->id, |
||||
|
]); |
||||
|
} |
||||
|
|
||||
|
/** @test */ |
||||
|
public function user_can_edit_comment() |
||||
|
{ |
||||
|
$this->adminUserSigningIn(); |
||||
|
$job = factory(Job::class)->create(); |
||||
|
$comment = factory(Comment::class)->create([ |
||||
|
'commentable_type' => 'jobs', |
||||
|
'commentable_id' => $job->id, |
||||
|
'body' => 'This is job comment.', |
||||
|
]); |
||||
|
|
||||
|
$this->visitRoute('jobs.comments.index', $job); |
||||
|
$this->seeElement('a', ['id' => 'edit-comment-'.$comment->id]); |
||||
|
$this->click('edit-comment-'.$comment->id); |
||||
|
$this->seeRouteIs('jobs.comments.index', [$job, 'action' => 'comment-edit', 'comment_id' => $comment->id]); |
||||
|
|
||||
|
$this->submitForm(__('comment.update'), [ |
||||
|
'body' => 'Komentar pertama.', |
||||
|
]); |
||||
|
|
||||
|
$this->seePageIs(route('jobs.comments.index', $job)); |
||||
|
$this->see(__('comment.updated')); |
||||
|
|
||||
|
$this->seeInDatabase('comments', [ |
||||
|
'id' => $comment->id, |
||||
|
'commentable_type' => 'jobs', |
||||
|
'commentable_id' => $job->id, |
||||
|
'body' => 'Komentar pertama.', |
||||
|
]); |
||||
|
} |
||||
|
|
||||
|
/** @test */ |
||||
|
public function user_can_delete_comment() |
||||
|
{ |
||||
|
$this->adminUserSigningIn(); |
||||
|
$job = factory(Job::class)->create(); |
||||
|
$comment = factory(Comment::class)->create([ |
||||
|
'commentable_type' => 'jobs', |
||||
|
'commentable_id' => $job->id, |
||||
|
'body' => 'This is job comment.', |
||||
|
]); |
||||
|
|
||||
|
$this->visitRoute('jobs.comments.index', $job); |
||||
|
$this->seeElement('button', ['id' => 'delete-comment-'.$comment->id]); |
||||
|
$this->press('delete-comment-'.$comment->id); |
||||
|
|
||||
|
$this->seePageIs(route('jobs.comments.index', $job)); |
||||
|
$this->see(__('comment.deleted')); |
||||
|
|
||||
|
$this->dontSeeInDatabase('comments', [ |
||||
|
'id' => $comment->id, |
||||
|
]); |
||||
|
} |
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue