use common\logic\Ticket\Ticket\Model\TicketSearch; | use common\logic\Ticket\Ticket\Model\TicketSearch; | ||||
use yii\filters\AccessControl; | use yii\filters\AccessControl; | ||||
use yii\filters\VerbFilter; | use yii\filters\VerbFilter; | ||||
use yii\helpers\Html; | |||||
use yii\web\NotFoundHttpException; | use yii\web\NotFoundHttpException; | ||||
class SupportController extends BackendController | class SupportController extends BackendController | ||||
public function actionCreate() | public function actionCreate() | ||||
{ | { | ||||
$userCurrent = $this->getUserCurrent(); | |||||
$ticketManager = $this->getTicketManager(); | $ticketManager = $this->getTicketManager(); | ||||
$ticket = $ticketManager->instanciateTicket($this->getProducerCurrent(), $this->getUserCurrent()); | |||||
$ticketMessageManager = $this->getTicketMessageManager(); | |||||
$ticket = $ticketManager->instanciateTicket($this->getProducerCurrent(), $userCurrent); | |||||
if ($ticket->load(\Yii::$app->request->post()) && $ticketManager->saveCreate($ticket)) { | if ($ticket->load(\Yii::$app->request->post()) && $ticketManager->saveCreate($ticket)) { | ||||
$ticketMessageManager->createTicketMessage($ticket, $userCurrent, $ticket->message); | |||||
$this->setFlash('success', 'Le ticket a bien été créé.'); | $this->setFlash('success', 'Le ticket a bien été créé.'); | ||||
return $this->redirect(['index']); | |||||
return $this->redirect(['view', 'id' => $ticket->id]); | |||||
} else { | } else { | ||||
return $this->render('create', [ | return $this->render('create', [ | ||||
'ticket' => $ticket, | 'ticket' => $ticket, | ||||
public function actionView(int $id) | public function actionView(int $id) | ||||
{ | { | ||||
$ticketManager = $this->getTicketManager(); | |||||
$ticketMessageManager = $this->getTicketMessageManager(); | |||||
$ticket = $this->findTicket($id); | $ticket = $this->findTicket($id); | ||||
$ticketMessage = $ticketMessageManager->instanciateTicketMessage($ticket, $this->getUserCurrent()); | |||||
if ($ticketMessage->load(\Yii::$app->request->post()) && $ticketMessageManager->saveCreate($ticketMessage)) { | |||||
return $this->redirect(['view', 'id' => $ticket->id, '#' => 'bottom']); | |||||
} | |||||
return $this->render('view', [ | return $this->render('view', [ | ||||
'ticket' => $ticket | |||||
'ticket' => $ticket, | |||||
'ticketMessageResponse' => $ticketMessage | |||||
]); | ]); | ||||
} | } | ||||
$ticketManager = $this->getTicketManager(); | $ticketManager = $this->getTicketManager(); | ||||
$ticket = $this->findTicket($id); | $ticket = $this->findTicket($id); | ||||
$ticketManager->closeTicket($ticket); | $ticketManager->closeTicket($ticket); | ||||
$this->addFlash('success', "Le ticket a bien été fermé."); | |||||
$this->addFlash('success', "Le ticket <strong>".Html::encode($ticket->subject)."</strong> a bien été fermé."); | |||||
return $this->redirect(['index']); | return $this->redirect(['index']); | ||||
} | } | ||||
$ticketManager = $this->getTicketManager(); | $ticketManager = $this->getTicketManager(); | ||||
$ticket = $ticketManager->findOneTicketById($id); | $ticket = $ticketManager->findOneTicketById($id); | ||||
if($ticket && $ticketManager->hasTicketAccess($ticket, $this->getUserCurrent())) { | |||||
if ($ticket && $ticketManager->hasTicketAccess($ticket, $this->getUserCurrent())) { | |||||
return $ticket; | return $ticket; | ||||
} | |||||
else { | |||||
} else { | |||||
throw new NotFoundHttpException("Le ticket est introuvable."); | throw new NotFoundHttpException("Le ticket est introuvable."); | ||||
} | } | ||||
} | } |
?> | ?> | ||||
<div class="support-index"> | <div class="support-index"> | ||||
<div> | <div> | ||||
<div class="col-md-4"> | <div class="col-md-4"> | ||||
<div class="info-box"> | <div class="info-box"> | ||||
<div class="clr"></div> | <div class="clr"></div> | ||||
<div class="box"> | |||||
<div class="box box-table-tickets"> | |||||
<div class="box-header with-border"> | <div class="box-header with-border"> | ||||
<h3 class="box-title">Tickets</h3> | <h3 class="box-title">Tickets</h3> | ||||
</div> | </div> | ||||
<div class="box-body"> | <div class="box-body"> | ||||
<?= GridView::widget([ | <?= GridView::widget([ | ||||
'summary' => '', | |||||
'filterModel' => $searchTicket, | 'filterModel' => $searchTicket, | ||||
'dataProvider' => $dataProviderTicket, | 'dataProvider' => $dataProviderTicket, | ||||
'columns' => [ | 'columns' => [ | ||||
[ | |||||
'attribute' => 'created_at', | |||||
'value' => function ($ticket) { | |||||
return date('d/m/Y', strtotime($ticket->created_at)); | |||||
} | |||||
], | |||||
[ | [ | ||||
'attribute' => 'subject', | 'attribute' => 'subject', | ||||
'format' => 'raw', | 'format' => 'raw', | ||||
'value' => function($ticket) { | |||||
'value' => function ($ticket) { | |||||
return Html::a($ticket->subject, ['support/view', 'id' => $ticket->id]); | return Html::a($ticket->subject, ['support/view', 'id' => $ticket->id]); | ||||
} | } | ||||
], | ], | ||||
[ | [ | ||||
'attribute' => 'status', | 'attribute' => 'status', | ||||
'filter' => [Ticket::STATUS_OPEN => 'Ouvert', Ticket::STATUS_CLOSED => 'Fermé'], | 'filter' => [Ticket::STATUS_OPEN => 'Ouvert', Ticket::STATUS_CLOSED => 'Fermé'], | ||||
'value' => function($ticket) { | |||||
'value' => function ($ticket) { | |||||
$label = $ticket->status == Ticket::STATUS_OPEN ? 'Ouvert' : 'Fermé'; | $label = $ticket->status == Ticket::STATUS_OPEN ? 'Ouvert' : 'Fermé'; | ||||
return $label; | return $label; | ||||
} | } | ||||
'contentOptions' => ['class' => 'column-actions'], | 'contentOptions' => ['class' => 'column-actions'], | ||||
'buttons' => [ | 'buttons' => [ | ||||
'close-open' => function ($url, $ticket) use ($ticketManager) { | 'close-open' => function ($url, $ticket) use ($ticketManager) { | ||||
if($ticketManager->isTicketOpen($ticket)) { | |||||
if ($ticketManager->isTicketOpen($ticket)) { | |||||
$title = 'Fermer'; | $title = 'Fermer'; | ||||
$url = ['support/close', 'id' => $ticket->id]; | $url = ['support/close', 'id' => $ticket->id]; | ||||
$glyphicon = 'glyphicon-folder-close'; | $glyphicon = 'glyphicon-folder-close'; | ||||
} | |||||
else { | |||||
} else { | |||||
$title = 'Ré-ouvrir'; | $title = 'Ré-ouvrir'; | ||||
$url = ['support/open', 'id' => $ticket->id]; | $url = ['support/open', 'id' => $ticket->id]; | ||||
$glyphicon = 'glyphicon-folder-open'; | $glyphicon = 'glyphicon-folder-open'; | ||||
} | } | ||||
return Html::a('<span class="glyphicon '.$glyphicon.'"></span>', $url, [ | |||||
return Html::a('<span class="glyphicon ' . $glyphicon . '"></span>', $url, [ | |||||
'title' => $title, 'class' => 'btn btn-default' | 'title' => $title, 'class' => 'btn btn-default' | ||||
]); | ]); | ||||
} | } |
<?php | <?php | ||||
use common\logic\Ticket\Ticket\Wrapper\TicketManager; | use common\logic\Ticket\Ticket\Wrapper\TicketManager; | ||||
use common\logic\User\User\Wrapper\UserManager; | |||||
use yii\helpers\Html; | |||||
use yii\widgets\ActiveForm; | |||||
$ticketManager = TicketManager::getInstance(); | $ticketManager = TicketManager::getInstance(); | ||||
$this->setTitle('Support'); | |||||
$this->addBreadcrumb($this->getTitle()); | |||||
$userManager = UserManager::getInstance(); | |||||
$this->setTitle('Voir un ticket'); | |||||
$this->addBreadcrumb(['label' => 'Support', 'url' => ['support/index']]); | |||||
$this->addBreadcrumb('Voir un ticket'); | $this->addBreadcrumb('Voir un ticket'); | ||||
?> | |||||
<div class="ticket-view"> | |||||
<div class="box box-solid"> | |||||
<div class="box-body"> | |||||
<table class="table"> | |||||
<tbody> | |||||
<tr> | |||||
<td><strong>Sujet</strong></td> | |||||
<td><?= Html::encode($ticket->subject); ?></td> | |||||
</tr> | |||||
<tr> | |||||
<td><strong>Ouverture</strong></td> | |||||
<td><?= $ticketManager->getTicketDateCreatedAtFormat($ticket); ?></td> | |||||
</tr> | |||||
<tr> | |||||
<td><strong>Statut</strong></td> | |||||
<td><?= $ticketManager->getTicketStatusLabelAsHtml($ticket); ?></td> | |||||
</tr> | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
</div> | |||||
<ul class="timeline"> | |||||
<?php foreach($ticket->ticketMessages as $key => $ticketMessage): ?> | |||||
<li> | |||||
<?php if ($key === array_key_last($ticket->ticketMessages)): ?> | |||||
<a name="bottom"></a> | |||||
<?php endif; ?> | |||||
<a name="<?= $ticketMessage->id ?>"></a> | |||||
<i class="fa fa-user <?= $userManager->isAdmin($ticketMessage->user) ? 'bg-orange' : 'bg-aqua'; ?>"></i> | |||||
<div class="timeline-item"> | |||||
<span class="time"><i class="fa fa-clock-o"></i> <?= date('d/m/Y à H:i', strtotime($ticketMessage->created_at)) ?></span> | |||||
<h3 class="timeline-header">Guillaume Bourgeois</h3> | |||||
<div class="timeline-body"> | |||||
<?= nl2br($ticketMessage->message); ?> | |||||
</div> | |||||
</div> | |||||
</li> | |||||
<?php endforeach; ?> | |||||
</ul> | |||||
<div class="box box-success"> | |||||
<div class="box-header"> | |||||
<h3 class="box-title"><i class="fa fa-comments"></i> Répondre</h3> | |||||
</div> | |||||
<div class="box-body"> | |||||
<?php $form = ActiveForm::begin(); ?> | |||||
<?= $form->field($ticketMessageResponse, 'message')->textarea(['rows' => 6]); ?> | |||||
<div class="form-group"> | |||||
<?= Html::submitButton('Répondre', ['class' => 'btn btn-success btn-sm']) ?> | |||||
</div> | |||||
<?php ActiveForm::end(); ?> | |||||
</div> | |||||
</div> | |||||
<div class="box box-danger"> | |||||
<div class="box-header"> | |||||
<h3 class="box-title"><i class="fa fa-folder"></i> Cliquez ici si vous souhaitez fermer le ticket</h3> | |||||
</div> | |||||
<div class="box-body"> | |||||
<?= Html::a('Fermer le ticket', ['support/close', 'id' => $ticket->id], ['class' => 'btn btn-danger btn-sm']) ?> | |||||
</div> | |||||
</div> | |||||
</div> |
} | } | ||||
} | } | ||||
a { | a { | ||||
color: $color1 ; | |||||
color: darken($color1, 5) ; | |||||
} | } | ||||
.btn { | .btn { |
} | } | ||||
} | } | ||||
.float-right { | |||||
float: right; | |||||
} | |||||
.float-left { | |||||
float: left; | |||||
} | |||||
#block-demo { | #block-demo { | ||||
padding: 10px 0px ; | padding: 10px 0px ; | ||||
background-color: $color2 ; | background-color: $color2 ; | ||||
@import "document/_form.scss" ; | @import "document/_form.scss" ; | ||||
@import "document/_index.scss" ; | @import "document/_index.scss" ; | ||||
@import "development/_index.scss" ; | @import "development/_index.scss" ; | ||||
@import "support/_index.scss"; | |||||
@import "support/_view.scss"; | |||||
@import "_responsive.scss" ; | @import "_responsive.scss" ; |
.support-index { | |||||
} |
.ticket-view { | |||||
.table { | |||||
tr:first-child td { | |||||
border-top: 0px none; | |||||
} | |||||
} | |||||
.timeline { | |||||
&::before { | |||||
background: transparent none; | |||||
} | |||||
li, .timeline-item { | |||||
margin-right: 0px; | |||||
} | |||||
} | |||||
} |
'id_user' => 'Utilisateur', | 'id_user' => 'Utilisateur', | ||||
'subject' => 'Sujet', | 'subject' => 'Sujet', | ||||
'status' => 'Statut', | 'status' => 'Statut', | ||||
'created_at' => 'Date de création', | |||||
'created_at' => 'Ouverture', | |||||
'updated_at' => 'Modification', | |||||
]; | ]; | ||||
} | } | ||||
{ | { | ||||
return $ticket->status == Ticket::STATUS_CLOSED; | return $ticket->status == Ticket::STATUS_CLOSED; | ||||
} | } | ||||
public function getTicketDateCreatedAtFormat(Ticket $ticket) | |||||
{ | |||||
return date('d/m/Y', strtotime($ticket->created_at)); | |||||
} | |||||
public function getTicketStatusLabelAsHtml(Ticket $ticket) | |||||
{ | |||||
$classLabel = 'label-success'; | |||||
$statusLabel = 'Ouvert'; | |||||
if($this->isTicketClosed($ticket)) { | |||||
$classLabel = 'label-danger'; | |||||
$statusLabel = 'Fermé'; | |||||
} | |||||
return '<span class="label '.$classLabel.'">'.$statusLabel.'</span>'; | |||||
} | |||||
} | } |
namespace common\logic\Ticket\TicketMessage\Service; | namespace common\logic\Ticket\TicketMessage\Service; | ||||
use common\logic\AbstractBuilder; | use common\logic\AbstractBuilder; | ||||
use common\logic\Ticket\Ticket\Model\Ticket; | |||||
use common\logic\Ticket\TicketMessage\Model\TicketMessage; | use common\logic\Ticket\TicketMessage\Model\TicketMessage; | ||||
use common\logic\User\User\Model\User; | |||||
class TicketMessageBuilder extends AbstractBuilder | class TicketMessageBuilder extends AbstractBuilder | ||||
{ | { | ||||
public function instanciateTicketMessage(): TicketMessage | |||||
public function instanciateTicketMessage(Ticket $ticket, User $user, string $message = ''): TicketMessage | |||||
{ | { | ||||
$ticket = new TicketMessage(); | |||||
$ticketMessage = new TicketMessage(); | |||||
return $ticket; | |||||
$ticketMessage->populateTicket($ticket); | |||||
$ticketMessage->populateUser($user); | |||||
$ticketMessage->message = $message; | |||||
return $ticketMessage; | |||||
} | } | ||||
public function createTicketMessage(): TicketMessage | |||||
public function createTicketMessage(Ticket $ticket, User $user, string $message): TicketMessage | |||||
{ | { | ||||
$ticketMessage = $this->instanciateTicketMessage(); | |||||
$ticketMessage = $this->instanciateTicketMessage($ticket, $user, $message); | |||||
$this->saveCreate($ticketMessage); | $this->saveCreate($ticketMessage); | ||||
return $ticketMessage; | return $ticketMessage; |