feat: ✨ add order on tickets
This commit is contained in:
parent
9b0f1e0241
commit
64b95f6f28
14 changed files with 504 additions and 405 deletions
|
|
@ -29,9 +29,12 @@ use Illuminate\Support\Facades\DB;
|
|||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Traits\Controllers\ChangesModelOrder;
|
||||
|
||||
class TicketController extends Controller
|
||||
{
|
||||
use ChangesModelOrder;
|
||||
|
||||
/**
|
||||
* TicketController
|
||||
*/
|
||||
|
|
@ -74,7 +77,6 @@ class TicketController extends Controller
|
|||
}));
|
||||
} //end if
|
||||
|
||||
|
||||
/** @var \App\Models\User */
|
||||
$user = auth()->user();
|
||||
$tickets = Ticket::with(['site', 'labels']);
|
||||
|
|
@ -97,6 +99,10 @@ class TicketController extends Controller
|
|||
|
||||
$tickets = $this->filterTickets($tickets, $request);
|
||||
$tickets = $this->searchTicket($tickets, $request);
|
||||
|
||||
/** Sort columns with a query */
|
||||
$this->sortQuery($tickets);
|
||||
|
||||
/** Custom pagination */
|
||||
$tickets = $this->customPaginate($tickets, $request->pagination);
|
||||
|
||||
|
|
@ -502,8 +508,6 @@ class TicketController extends Controller
|
|||
Session::remove('tickets.st');
|
||||
Session::remove('tickets.pr');
|
||||
Session::remove('tickets.ty');
|
||||
Session::remove('tickets.sort_col');
|
||||
Session::remove('tickets.sort_way');
|
||||
Session::remove('tickets.search');
|
||||
}
|
||||
if ($request->assr) {
|
||||
|
|
@ -518,12 +522,6 @@ class TicketController extends Controller
|
|||
if ($request->tys) {
|
||||
Session::remove('tickets.ty');
|
||||
}
|
||||
if ($request->sort_col) {
|
||||
Session::put('tickets.sort_col', $request->sort_col);
|
||||
}
|
||||
if ($request->sort_way) {
|
||||
Session::put('tickets.sort_way', $request->sort_way);
|
||||
}
|
||||
if ($request->pr) {
|
||||
Session::put('tickets.pr', $request->pr);
|
||||
}
|
||||
|
|
@ -555,28 +553,6 @@ class TicketController extends Controller
|
|||
if (Session::has('tickets.ty')) {
|
||||
$tickets->where('type', Session::get('tickets.ty'));
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
Session::has('tickets.sort_col') and
|
||||
Session::has('tickets.sort_way') and
|
||||
in_array(Session::get('tickets.sort_col'), [
|
||||
'id',
|
||||
'site_id',
|
||||
'created_at',
|
||||
'created_by',
|
||||
'type',
|
||||
'status',
|
||||
'assigned_to'
|
||||
])
|
||||
) {
|
||||
$tickets->orderBy(
|
||||
Session::get('tickets.sort_col'),
|
||||
Session::get('tickets.sort_way')
|
||||
);
|
||||
} else {
|
||||
$tickets->orderBy('last_activity', 'DESC');
|
||||
}
|
||||
return $tickets;
|
||||
}
|
||||
|
||||
|
|
|
|||
43
app/Http/Requests/Bo/UpdateChangeOrderRequest.php
Normal file
43
app/Http/Requests/Bo/UpdateChangeOrderRequest.php
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Bo;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class UpdateChangeOrderRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return auth()->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the data for validation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareForValidation(): void
|
||||
{
|
||||
$this->merge([
|
||||
'direction' => $this->route('direction') === 'up' ? true : false
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'direction' => 'required|boolean',
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -32,6 +32,7 @@ class Ticket extends Model
|
|||
'site_id',
|
||||
'type',
|
||||
'status',
|
||||
'order',
|
||||
'text',
|
||||
'title',
|
||||
'is_internal',
|
||||
|
|
@ -59,6 +60,7 @@ class Ticket extends Model
|
|||
{
|
||||
static::creating(function (Ticket $ticket) {
|
||||
// If bug force the ticket status on new. All the others are estimateTodo.
|
||||
self::setOrder($ticket);
|
||||
if ($ticket->type->equals(TicketTypeEnum::bug)) {
|
||||
$ticket->status = TicketStatusEnum::new;
|
||||
} else {
|
||||
|
|
@ -66,7 +68,7 @@ class Ticket extends Model
|
|||
}
|
||||
});
|
||||
static::updating(function (Ticket $ticket) {
|
||||
if (!$ticket->original['status'] !== $ticket->status->value) {
|
||||
if (!$ticket->original['status'] !== $ticket->status->value && $ticket->original['order'] === $ticket->order) {
|
||||
event(new TicketStatusChanged(
|
||||
$ticket,
|
||||
TicketStatusEnum::make($ticket->original['status']),
|
||||
|
|
@ -85,9 +87,25 @@ class Ticket extends Model
|
|||
$ticket->status->label()
|
||||
)));
|
||||
}
|
||||
if ($ticket->status->equals(TicketStatusEnum::archived)) {
|
||||
self::setOrder($ticket, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set order after the last element of the list.
|
||||
*
|
||||
* @param self $model
|
||||
* @param boolean $isArchived
|
||||
* @return void
|
||||
*/
|
||||
private static function setOrder(self $model, bool $isArchived = false): void
|
||||
{
|
||||
$model->order = \intval(self::query()->where('status', $isArchived ? '=' : '!=', TicketStatusEnum::archived)->max('order')) + 1;
|
||||
}
|
||||
|
||||
|
||||
// * RELATIONSHIPS
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -67,6 +67,17 @@ class TicketPolicy
|
|||
return $user->isAdmin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the user can change the order of a given ticket.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return boolean
|
||||
*/
|
||||
public function changeOrder(User $user)
|
||||
{
|
||||
return $user->isAdmin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the user can change the internal status of a given ticket.
|
||||
*
|
||||
|
|
|
|||
64
app/Traits/Controllers/ChangesModelOrder.php
Normal file
64
app/Traits/Controllers/ChangesModelOrder.php
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
namespace App\Traits\Controllers;
|
||||
|
||||
use App\Http\Requests\Bo\UpdateChangeOrderRequest;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
trait ChangesModelOrder
|
||||
{
|
||||
/**
|
||||
* Change order.
|
||||
*
|
||||
* @param \App\Http\Requests\Bo\UpdateChangeOrderRequest $request
|
||||
* @param mixed ...$params
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \RuntimeException Si le nom du parametre de la route ne correspond pas au params utilisé.
|
||||
*/
|
||||
public function changeOrder(UpdateChangeOrderRequest $request, mixed ...$params): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
$paramNames = collect(request()->route()->parameterNames);
|
||||
$className = Str::of($paramNames->get($paramNames->count() - 2))->lower()->studly();
|
||||
$className = "\\App\\Models\\{$className}";
|
||||
$model = Arr::get($params, $paramNames->count() - 2);
|
||||
|
||||
if (!class_exists($className)) {
|
||||
throw new \RuntimeException("The {$className} class doesn't exist.");
|
||||
}
|
||||
|
||||
if (!\is_object($model)) {
|
||||
throw new \RuntimeException("The second last param isn't an object.");
|
||||
}
|
||||
|
||||
if (get_class($model) !== (string)Str::of($className)->replaceStart('\\', '')) {
|
||||
throw new \RuntimeException("The {$className} doesn't match second last binded param.");
|
||||
}
|
||||
|
||||
/** @var \Illuminate\Database\Eloquent\Model|null */
|
||||
$model = $className::query()->where($model->getRouteKeyName(), $model->getRouteKey())->first();
|
||||
|
||||
if (!$model) {
|
||||
return back()->with('error', trans('crud.messages.order_not_changed'));
|
||||
}
|
||||
|
||||
return DB::transaction(function () use ($request, $className, $model) {
|
||||
/** @var \Illuminate\Database\Eloquent\Model|null */
|
||||
$tmp = $className::query()
|
||||
->where('order', $request->direction ? '<' : '>', $model->getOriginal('order'))
|
||||
->orderBy('order', $request->direction ? 'DESC' : 'ASC')
|
||||
->first();
|
||||
|
||||
if (!$tmp) {
|
||||
return back()->with('error', trans('crud.messages.order_not_changed'));
|
||||
}
|
||||
|
||||
$newOrder = $tmp->getOriginal('order');
|
||||
$tmp->update(['order' => $model->getOriginal('order')]);
|
||||
$model->update(['order' => $newOrder]);
|
||||
|
||||
return redirect()->back()->with('success', trans('crud.messages.order_changed'));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Ticket;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use App\Enums\Tickets\TicketStatusEnum;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('tickets', function (Blueprint $table) {
|
||||
$table->integer('order')->after('status')->comment('Ordre du ticket');
|
||||
});
|
||||
|
||||
Ticket::query()->where('status', '!=', TicketStatusEnum::archived)->get()->map(function ($ticket, $ticketIndex) {
|
||||
$ticket->order = $ticketIndex + 1;
|
||||
$ticket->saveQuietly();
|
||||
});
|
||||
Ticket::query()->where('status', '=', TicketStatusEnum::archived)->get()->map(function ($ticket, $ticketIndex) {
|
||||
$ticket->order = $ticketIndex + 1;
|
||||
$ticket->saveQuietly();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('tickets', function (Blueprint $table) {
|
||||
$table->dropColumn('order');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -1,131 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Validation Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following language lines contain the default error messages used by
|
||||
| the validator class. Some of these rules have multiple versions such
|
||||
| as the size rules. Feel free to tweak each of these messages here.
|
||||
|
|
||||
*/
|
||||
|
||||
return [
|
||||
'accepted' => 'Ce champ doit être accepté.',
|
||||
'active_url' => 'Ce n\'est pas une URL valide',
|
||||
'after' => 'La date doit être postérieure au :date.',
|
||||
'after_or_equal' => 'La date doit être postérieure ou égale au :date.',
|
||||
'alpha' => 'Ce champ doit contenir uniquement des lettres',
|
||||
'alpha_dash' => 'Ce champ doit contenir uniquement des lettres, des chiffres et des tirets.',
|
||||
'alpha_num' => 'Ce champ doit contenir uniquement des chiffres et des lettres.',
|
||||
'array' => 'Ce champ doit être un tableau.',
|
||||
'attached' => 'Ce champ est déjà attaché.',
|
||||
'before' => 'Ce champ doit être une date antérieure au :date.',
|
||||
'before_or_equal' => 'Ce champ doit être une date antérieure ou égale au :date.',
|
||||
'between' => [
|
||||
'array' => 'Le tableau doit contenir entre :min et :max éléments.',
|
||||
'file' => 'La taille du fichier doit être comprise entre :min et :max kilo-octets.',
|
||||
'numeric' => 'La valeur doit être comprise entre :min et :max.',
|
||||
'string' => 'Le texte doit contenir entre :min et :max caractères.',
|
||||
],
|
||||
'boolean' => 'Ce champ doit être vrai ou faux.',
|
||||
'confirmed' => 'Le champ de confirmation ne correspond pas.',
|
||||
'date' => 'Ce n\'est pas une date valide.',
|
||||
'date_equals' => 'La date doit être égale à :date.',
|
||||
'date_format' => 'Ce champ ne correspond pas au format :format.',
|
||||
'different' => 'Cette valeur doit être différente de :other.',
|
||||
'digits' => 'Ce champ doit contenir :digits chiffres.',
|
||||
'digits_between' => 'Ce champ doit contenir entre :min et :max chiffres.',
|
||||
'dimensions' => 'La taille de l\'image n\'est pas conforme.',
|
||||
'distinct' => 'Ce champ a une valeur en double.',
|
||||
'email' => 'Ce champ doit être une adresse email valide.',
|
||||
'ends_with' => 'Ce champ doit se terminer par une des valeurs suivantes : :values',
|
||||
'exists' => 'Ce champ sélectionné est invalide.',
|
||||
'file' => 'Ce champ doit être un fichier.',
|
||||
'filled' => 'Ce champ doit avoir une valeur.',
|
||||
'gt' => [
|
||||
'array' => 'Le tableau doit contenir plus de :value éléments.',
|
||||
'file' => 'La taille du fichier doit être supérieure à :value kilo-octets.',
|
||||
'numeric' => 'La valeur doit être supérieure à :value.',
|
||||
'string' => 'Le texte doit contenir plus de :value caractères.',
|
||||
],
|
||||
'gte' => [
|
||||
'array' => 'Le tableau doit contenir au moins :value éléments.',
|
||||
'file' => 'La taille du fichier doit être supérieure ou égale à :value kilo-octets.',
|
||||
'numeric' => 'La valeur doit être supérieure ou égale à :value.',
|
||||
'string' => 'Le texte doit contenir au moins :value caractères.',
|
||||
],
|
||||
'image' => 'Ce champ doit être une image.',
|
||||
'in' => 'Ce champ est invalide.',
|
||||
'in_array' => 'Ce champ n\'existe pas dans :other.',
|
||||
'integer' => 'Ce champ doit être un entier.',
|
||||
'ip' => 'Ce champ doit être une adresse IP valide.',
|
||||
'ipv4' => 'Ce champ doit être une adresse IPv4 valide.',
|
||||
'ipv6' => 'Ce champ doit être une adresse IPv6 valide.',
|
||||
'json' => 'Ce champ doit être un document JSON valide.',
|
||||
'lt' => [
|
||||
'array' => 'Le tableau doit contenir moins de :value éléments.',
|
||||
'file' => 'La taille du fichier doit être inférieure à :value kilo-octets.',
|
||||
'numeric' => 'La valeur doit être inférieure à :value.',
|
||||
'string' => 'Le texte doit contenir moins de :value caractères.',
|
||||
],
|
||||
'lte' => [
|
||||
'array' => 'Le tableau doit contenir au plus :value éléments.',
|
||||
'file' => 'La taille du fichier doit être inférieure ou égale à :value kilo-octets.',
|
||||
'numeric' => 'La valeur doit être inférieure ou égale à :value.',
|
||||
'string' => 'Le texte doit contenir au plus :value caractères.',
|
||||
],
|
||||
'max' => [
|
||||
'array' => 'Le tableau ne peut contenir plus de :max éléments.',
|
||||
'file' => 'La taille du fichier ne peut pas dépasser :max kilo-octets.',
|
||||
'numeric' => 'La valeur ne peut être supérieure à :max.',
|
||||
'string' => 'Le texte ne peut contenir plus de :max caractères.',
|
||||
],
|
||||
'mimes' => 'Le fichier doit être de type : :values.',
|
||||
'mimetypes' => 'Le fichier doit être de type : :values.',
|
||||
'min' => [
|
||||
'array' => 'Le tableau doit contenir au moins :min éléments.',
|
||||
'file' => 'La taille du fichier doit être supérieure à :min kilo-octets.',
|
||||
'numeric' => 'La valeur doit être supérieure ou égale à :min.',
|
||||
'string' => 'Le texte doit contenir au moins :min caractères.',
|
||||
],
|
||||
'multiple_of' => 'La valeur doit être un multiple de :value',
|
||||
'not_in' => 'Le champ sélectionné n\'est pas valide.',
|
||||
'not_regex' => 'Le format du champ n\'est pas valide.',
|
||||
'numeric' => 'Ce champ doit contenir un nombre.',
|
||||
'password' => 'Le mot de passe est incorrect',
|
||||
'present' => 'Ce champ doit être présent.',
|
||||
'prohibited' => 'Ce champ est interdit',
|
||||
'prohibited_if' => 'Ce champ est interdit quand :other a la valeur :value.',
|
||||
'prohibited_unless' => 'Ce champ est interdit à moins que :other ait l\'une des valeurs :values.',
|
||||
'regex' => 'Le format du champ est invalide.',
|
||||
'relatable' => 'Ce champ n\'est sans doute pas associé avec cette donnée.',
|
||||
'required' => 'Ce champ est obligatoire.',
|
||||
'required_if' => 'Ce champ est obligatoire quand la valeur de :other est :value.',
|
||||
'required_unless' => 'Ce champ est obligatoire sauf si :other est :values.',
|
||||
'required_with' => 'Ce champ est obligatoire quand :values est présent.',
|
||||
'required_with_all' => 'Ce champ est obligatoire quand :values sont présents.',
|
||||
'required_without' => 'Ce champ est obligatoire quand :values n\'est pas présent.',
|
||||
'required_without_all' => 'Ce champ est requis quand aucun de :values n\'est présent.',
|
||||
'same' => 'Ce champ doit être identique à :other.',
|
||||
'size' => [
|
||||
'array' => 'Le tableau doit contenir :size éléments.',
|
||||
'file' => 'La taille du fichier doit être de :size kilo-octets.',
|
||||
'numeric' => 'La valeur doit être :size.',
|
||||
'string' => 'Le texte doit contenir :size caractères.',
|
||||
],
|
||||
'starts_with' => 'Ce champ doit commencer avec une des valeurs suivantes : :values',
|
||||
'string' => 'Ce champ doit être une chaîne de caractères.',
|
||||
'timezone' => 'Ce champ doit être un fuseau horaire valide.',
|
||||
'unique' => 'La valeur est déjà utilisée.',
|
||||
'uploaded' => 'Le fichier n\'a pu être téléversé.',
|
||||
'url' => 'Le format de l\'URL n\'est pas valide.',
|
||||
'uuid' => 'Ce champ doit être un UUID valide',
|
||||
'custom' => [
|
||||
'attribute-name' => [
|
||||
'rule-name' => 'custom-message',
|
||||
],
|
||||
],
|
||||
'attributes' => [],
|
||||
];
|
||||
|
|
@ -248,5 +248,12 @@ return [
|
|||
'url_re7' => 'Url de RECETTE',
|
||||
'username' => 'nom d\'utilisateur',
|
||||
'year' => 'année',
|
||||
'id' => 'identifiant'
|
||||
],
|
||||
'custom' => [
|
||||
'type' => 'type',
|
||||
'tickets' => 'étiquettes',
|
||||
'assigned_to' => 'assigné à',
|
||||
'order' => 'ordre',
|
||||
]
|
||||
];
|
||||
|
|
|
|||
39
resources/views/bo/modules/change-model-order.blade.php
Normal file
39
resources/views/bo/modules/change-model-order.blade.php
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<td class="text-center align-middle">
|
||||
@can('changeOrder', $model)
|
||||
<div class="d-flex justify-content-center align-items-center">
|
||||
<form @class(['invisible' => $loop->first and $models->onFirstPage()])
|
||||
action="{{ route('bo.' . $routeName . '.change-order', [str($routeName)->singular()->value => $model, 'direction' => 'up']) }}"
|
||||
method="POST">
|
||||
@csrf
|
||||
@method('PATCH')
|
||||
<button data-bs-toggle="tooltip" type="submit" title="{{ __('crud.other.up') }}" @class([
|
||||
'btn btn-sm btn-outline-secondary',
|
||||
'disabled' => $loop->first and $models->onFirstPage(),
|
||||
])>
|
||||
<i class="fas fa-arrow-up"></i>
|
||||
</button>
|
||||
</form>
|
||||
<form @class([
|
||||
'invisible' =>
|
||||
$loop->last and $models->currentPage() === $models->lastPage(),
|
||||
])
|
||||
action="{{ route('bo.' . $routeName . '.change-order', [str($routeName)->singular()->value => $model, 'direction' => 'down']) }}"
|
||||
method="POST">
|
||||
@csrf
|
||||
@method('PATCH')
|
||||
<button data-bs-toggle="tooltip" type="submit" title="{{ __('crud.other.down') }}" @class([
|
||||
'btn btn-sm btn-outline-secondary ms-1',
|
||||
'disabled' =>
|
||||
$loop->last and $models->currentPage() === $models->lastPage(),
|
||||
])>
|
||||
<i class="fas fa-arrow-down"></i>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
@else
|
||||
<span class="text-danger" data-bs-toggle="tooltip" title="{{ __('crud.other.right') }}">
|
||||
<i class="fa-solid fa-ban"></i>
|
||||
</span>
|
||||
@endcan
|
||||
</td>
|
||||
|
||||
54
resources/views/bo/modules/table-col-sorter-cell.blade.php
Normal file
54
resources/views/bo/modules/table-col-sorter-cell.blade.php
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
@php
|
||||
$iArgs = ['sort_col' => $col];
|
||||
if (request()->search) {
|
||||
$iArgs['search'] = request()->search;
|
||||
}
|
||||
@endphp
|
||||
{{-- NO Sort for order column --}}
|
||||
@if ($col === 'order' or in_array($col, $ignore))
|
||||
<th @class([
|
||||
'h-100 text-center',
|
||||
'd-none d-md-table-cell' =>
|
||||
isset($mobileHide) and
|
||||
is_array($mobileHide) and
|
||||
in_array($col, $mobileHide),
|
||||
]) scope="col">
|
||||
<div class="d-flex justify-content-center align-items-center h-100">
|
||||
<span class="text-nowrap">{{ $colname }}</span>
|
||||
</div>
|
||||
</th>
|
||||
@else
|
||||
<th @class([
|
||||
'h-100 text-center',
|
||||
'd-none d-md-table-cell' =>
|
||||
isset($mobileHide) and
|
||||
is_array($mobileHide) and
|
||||
in_array($col, $mobileHide),
|
||||
]) scope="col">
|
||||
<div class="d-flex justify-content-center align-items-center h-100">
|
||||
<span class="text-nowrap">
|
||||
{{ $colname }}
|
||||
</span>
|
||||
@if (
|
||||
!session("$routeName.sort_way") or
|
||||
session("$routeName.sort_col") !== $col or
|
||||
session("$routeName.sort_way") === 'desc' and session("$routeName.sort_col") === $col)
|
||||
<a class="btn btn-sm btn-outline-secondary text-decoration-none ms-1" data-bs-toggle="tooltip"
|
||||
href="{{ request()->fullUrlWithQuery(array_merge($iArgs, ['sort_way' => 'asc', 'rst' => null])) }}"
|
||||
title="{{ __('crud.other.sort_descending', ['name' => str($colname)->lower()]) }}">
|
||||
<i class="fas fa-arrow-down 2xs"></i>
|
||||
</a>
|
||||
@endif
|
||||
@if (
|
||||
!session("$routeName.sort_way") or
|
||||
session("$routeName.sort_col") !== $col or
|
||||
session("$routeName.sort_way") === 'asc' and session("$routeName.sort_col") === $col)
|
||||
<a class="btn btn-sm btn-outline-secondary text-decoration-none ms-1"
|
||||
href="{{ request()->fullUrlWithQuery(array_merge($iArgs, ['sort_way' => 'desc', 'rst' => null])) }}"data-bs-toggle="tooltip"
|
||||
title="{{ __('crud.other.sort_ascending', ['name' => str($colname)->lower()]) }}">
|
||||
<i class="fas fa-arrow-up 2xs"></i>
|
||||
</a>
|
||||
@endif
|
||||
</div>
|
||||
</th>
|
||||
@endif
|
||||
|
|
@ -1,73 +1,45 @@
|
|||
@php
|
||||
$route = request()->route();
|
||||
$routeName = $route->getName();
|
||||
$rst = !is_null(request()->rst) || !Session::has("$routeName.sorted");
|
||||
$noOrder = !empty($noOrder);
|
||||
$noOrder = $noOrder || (Session::get("$routeName.sort_col") !== 'order' and (Session::has("$routeName.sort_col") or Session::has("$routeName.sort_way")));
|
||||
$noOrder = $noOrder || !empty(request()->search);
|
||||
$ignore = (isset($ignore) and is_array($ignore)) ? $ignore : [];
|
||||
$route = request()->route();
|
||||
$routeName = $route->getName();
|
||||
$rst = !is_null(request()->rst) || !session()->has("$routeName.sorted");
|
||||
$noOrder = !empty($noOrder);
|
||||
$noOrder =
|
||||
$noOrder ||
|
||||
(session()->get("$routeName.sort_col") !== 'order' and
|
||||
(session()->has("$routeName.sort_col") or session()->has("$routeName.sort_way")));
|
||||
$noOrder = $noOrder || !empty(request()->search);
|
||||
$ignore = (isset($ignore) and is_array($ignore)) ? $ignore : [];
|
||||
@endphp
|
||||
<tr class="table-col-sorter">
|
||||
@foreach($cols as $col => $colname)
|
||||
@php
|
||||
$iArgs = ['sort_col' => $col];
|
||||
if(request()->search) {
|
||||
$iArgs['search'] = request()->search;
|
||||
}
|
||||
@endphp
|
||||
{{-- NO Sort for order column --}}
|
||||
@if($col === 'order' or in_array($col, $ignore))
|
||||
@if($noOrder and !in_array($col, $ignore)) @continue @endif
|
||||
<th scope="col" class="text-center h-100 @if(isset($mobileHide) and is_array($mobileHide) and in_array($col, $mobileHide)) d-none d-md-table-cell @endif">
|
||||
<div class="d-flex justify-content-center align-items-center h-100">
|
||||
<span class="text-nowrap">{{ $colname }}</span>
|
||||
</div>
|
||||
</th>
|
||||
@continue
|
||||
@endif
|
||||
<th scope="col" class="text-center h-100 @if(isset($mobileHide) and is_array($mobileHide) and in_array($col, $mobileHide)) d-none d-md-table-cell @endif">
|
||||
<div class="d-flex justify-content-center align-items-center h-100">
|
||||
<span class="text-nowrap">
|
||||
{{ $colname }}
|
||||
</span>
|
||||
@if(!session("$routeName.sort_way") or session("$routeName.sort_col") !== $col or (session("$routeName.sort_way") === 'desc' and session("$routeName.sort_col") === $col))
|
||||
<a class="text-decoration-none ms-1"
|
||||
href="{{ request()->fullUrlWithQuery(array_merge($iArgs, ['sort_way' => 'asc', 'rst' => null])) }}">
|
||||
<button
|
||||
class="btn btn-sm btn-outline-dark"
|
||||
title="{{ __('crud.other.sort_descending', ['name' => Str::lower($colname)]) }}"
|
||||
data-bs-toggle="tooltip">
|
||||
<i class="fas fa-arrow-down 2xs"></i>
|
||||
</button>
|
||||
</a>
|
||||
<tr class="table-col-sorter border-start-0 border-end-0 border-top-0 border-secondary border border-2">
|
||||
@foreach ($cols as $col => $colname)
|
||||
@if($col === 'order')
|
||||
@if(
|
||||
!request()->sort_col
|
||||
&& !request()->sort_way
|
||||
&& !request()->ass
|
||||
&& !request()->st
|
||||
&& !request()->pr
|
||||
&& !request()->ty
|
||||
&& !request()->search
|
||||
)
|
||||
@include('bo.modules.table-col-sorter-cell')
|
||||
@endif
|
||||
@if(!session("$routeName.sort_way") or session("$routeName.sort_col") !== $col or (session("$routeName.sort_way") === 'asc' and session("$routeName.sort_col") === $col))
|
||||
<a class="text-decoration-none ms-1"
|
||||
href="{{ request()->fullUrlWithQuery(array_merge($iArgs, ['sort_way' => 'desc', 'rst' => null])) }}">
|
||||
<button
|
||||
class="btn btn-sm btn-outline-dark"
|
||||
title="{{ __('crud.other.sort_ascending', ['name' => Str::lower($colname)]) }}"
|
||||
data-bs-toggle="tooltip">
|
||||
<i class="fas fa-arrow-up 2xs"></i>
|
||||
</button>
|
||||
</a>
|
||||
@endif
|
||||
</div>
|
||||
</th>
|
||||
@else
|
||||
@include('bo.modules.table-col-sorter-cell')
|
||||
@endif
|
||||
@endforeach
|
||||
{{-- Buttons Col --}}
|
||||
<th scope="col" class="text-end">
|
||||
@if(!$rst)
|
||||
<a class="btn btn-sm btn-danger"
|
||||
href="{{ request()->fullUrlWithQuery(['sort_col' => null, 'sort_way' => null, 'rst' => true, 'search' => null]) }}"
|
||||
data-bs-toggle="tooltip"
|
||||
title="{{ __('crud.other.sort_delete') }}">
|
||||
<i class="fa fa-eraser"></i>
|
||||
</a>
|
||||
<th class="text-end" scope="col">
|
||||
@if (!$rst)
|
||||
<a class="btn btn-sm btn-danger" data-bs-toggle="tooltip"
|
||||
href="{{ request()->fullUrlWithQuery(['sort_col' => null, 'sort_way' => null, 'rst' => true, 'search' => null]) }}"
|
||||
title="{{ __('crud.other.sort_delete') }}">
|
||||
<i class="fa fa-eraser"></i>
|
||||
</a>
|
||||
@else
|
||||
<span data-bs-toggle="tooltip" data-bs-placement="top" title="{{ __('crud.other.sort_arrow') }}">
|
||||
<i class="fas fa-question-circle"></i>
|
||||
</span>
|
||||
<span data-bs-toggle="tooltip" title="{{ __('crud.other.sort_arrow') }}">
|
||||
<i class="fas fa-question-circle"></i>
|
||||
</span>
|
||||
@endif
|
||||
</th>
|
||||
</tr>
|
||||
</tr>
|
||||
|
|
@ -162,184 +162,189 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table-hover table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">
|
||||
<span># </span>
|
||||
<span>@include('modules.sorter', ['colname' => 'id'])</span>
|
||||
</th>
|
||||
<th scope="col">
|
||||
<span>{{ __('Titre') }} </span>
|
||||
<span>@include('modules.sorter', ['colname' => 'title'])</span>
|
||||
</th>
|
||||
<th scope="col">
|
||||
<span>{{ __('Type') }} </span>
|
||||
<span>@include('modules.sorter', ['colname' => 'type'])</span>
|
||||
</th>
|
||||
@can('assignLabels', App\Models\Ticket::class)
|
||||
<th scope="col">{{ __('Étiquettes') }}</th>
|
||||
@endcan
|
||||
@if (Auth::user()->isAdmin())
|
||||
<th scope="col">
|
||||
<span>{{ __('Assigné à') }} </span>
|
||||
<span>@include('modules.sorter', ['colname' => 'assigned_to'])</span>
|
||||
</th>
|
||||
@endif
|
||||
<th scope="col">
|
||||
<span>{{ __('Le') }} </span>
|
||||
<span>@include('modules.sorter', ['colname' => 'created_at'])</span>
|
||||
</th>
|
||||
<th scope="col"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@if (!count($tickets))
|
||||
<tr>
|
||||
<td class="text-center" colspan="@if (Auth::user()->isAdmin()) 6 @else 5 @endif">
|
||||
<h2>{{ __('Aucun ticket') }}</h2>
|
||||
</td>
|
||||
</tr>
|
||||
@endif
|
||||
@foreach ($tickets as $ticket)
|
||||
<tr class="position-relative">
|
||||
<td scope="row">
|
||||
<div class="d-flex justify-content-between">
|
||||
<span class="me-1">{{ $ticket->id }} @if ($ticket->is_internal)
|
||||
<i class="fa-solid fa-lock"></i>
|
||||
@endif
|
||||
</span>
|
||||
<span class="d-flex flex-column text-end">
|
||||
@if (Auth::user()->isAdmin())
|
||||
<a href="{{ route('bo.sites.show', $ticket->site) }}"
|
||||
title="{{ __('Voir le site :sitename', [
|
||||
'sitename' => $ticket->site->name,
|
||||
]) }}">{{ $ticket->site->name }}</a>
|
||||
@else
|
||||
<span class="text-decoration-underline">{{ $ticket->site->name }}</span>
|
||||
@endif
|
||||
<span
|
||||
class="{{ $ticket->status->class() }} rounded text-center">{{ $ticket->status->label() }}</span>
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<span class="me-1">{{ $ticket->title }}</span>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<span class="badge {{ $ticket->type->class() }}">{{ $ticket->type->label() }}</span>
|
||||
</td>
|
||||
@can('assignLabels', App\Models\Ticket::class)
|
||||
<td>
|
||||
<span class="ticket-index-labels">
|
||||
@foreach ($ticket->labels as $label)
|
||||
<span class="badge label colorize"
|
||||
data-color="{{ $label->color }}">{{ $label->name }}</span>
|
||||
@endforeach
|
||||
</span>
|
||||
<div class="overflow-scroll w-100">
|
||||
<table class="table-hover table">
|
||||
<thead>
|
||||
@include('bo.modules.table-col-sorter', [
|
||||
'cols' => [
|
||||
'id' => Str::ucfirst(__('validation.attributes.id')),
|
||||
'title' => Str::ucfirst(__('validation.attributes.name')),
|
||||
'type' => Str::ucfirst(__('validation.custom.type')),
|
||||
'tickets' => Str::ucfirst(__('validation.custom.tickets')),
|
||||
'assigned_to' => Str::ucfirst(__('validation.custom.assigned_to')),
|
||||
'order' => Str::ucfirst(__('validation.custom.order')),
|
||||
'created_at' => Str::ucfirst(__('validation.attributes.created_at')),
|
||||
],
|
||||
'ignore' => ['id', 'tickets']
|
||||
])
|
||||
</thead>
|
||||
<tbody>
|
||||
@if (!count($tickets))
|
||||
<tr>
|
||||
<td class="text-center" colspan="@if (Auth::user()->isAdmin()) 6 @else 5 @endif">
|
||||
<h2>{{ __('Aucun ticket') }}</h2>
|
||||
</td>
|
||||
@endcan
|
||||
@if (Auth::user()->isAdmin())
|
||||
<td>{{ $ticket->assignedUser ? $ticket->assignedUser->name : __('Personne') }}</td>
|
||||
@endif
|
||||
<td>{{ Carbon\Carbon::parse($ticket->created_at)->format('d/m/Y à H:i') }}</td>
|
||||
<td>
|
||||
<div class="d-flex flex-column">
|
||||
<div>
|
||||
<div class="btn-group" role="group">
|
||||
@php
|
||||
$ticket_files = $ticket->getFiles();
|
||||
@endphp
|
||||
@foreach ($ticket_files as $key => $file)
|
||||
@if ($file !== null && (\App\Lib\Helpers\ToolboxHelper::isImageFile($file) || \App\Lib\Helpers\ToolboxHelper::isPdfFile($file)))
|
||||
<a class="glightbox btn btn-outline-dark"
|
||||
data-gallery="gallery{{ $ticket->id }}" href="{{ asset($file) }}"
|
||||
target="_blank"><i class="fa-solid fa-file-image"></i>
|
||||
</a>
|
||||
@break
|
||||
</tr>
|
||||
@endif
|
||||
@foreach ($tickets as $ticket)
|
||||
<tr class="position-relative">
|
||||
<td scope="row">
|
||||
<div class="d-flex justify-content-between">
|
||||
<span class="me-1">{{ $ticket->id }} @if ($ticket->is_internal)
|
||||
<i class="fa-solid fa-lock"></i>
|
||||
@endif
|
||||
@endforeach
|
||||
{{-- Modal du ticket --}}
|
||||
<!-- Button trigger modal -->
|
||||
<button class="btn btn-outline-info" data-bs-toggle="modal"
|
||||
data-bs-target="#ticket{{ $ticket->id }}Modal" type="button"><i
|
||||
class="fa-solid fa-eye"></i></button>
|
||||
<a class="btn btn-outline-success"
|
||||
href="{{ route('bo.ticket.show', $ticket->id) }}"><i
|
||||
class="fa-solid fa-comment"></i></a>
|
||||
@if (auth()->user()->isAdmin())
|
||||
<a class="btn btn-outline-primary"
|
||||
href="{{ route('bo.ticket.edit', $ticket) }}"><i
|
||||
class="fa-solid fa-pen"></i></a>
|
||||
@endif
|
||||
@can('changeStatus', $ticket)
|
||||
@if (!$ticket->status->equals(\App\Enums\Tickets\TicketStatusEnum::archived))
|
||||
<form class="confirmJS" method="POST"
|
||||
action="{{ route('bo.ticket.archive', $ticket) }}">
|
||||
@method('PUT')
|
||||
@csrf
|
||||
<button class="btn btn-outline-danger rounded-0 rounded-end" type="submit"><i
|
||||
class="fa-solid fa-box-archive"></i></button>
|
||||
</form>
|
||||
</span>
|
||||
<span class="d-flex flex-column text-end">
|
||||
@if (Auth::user()->isAdmin())
|
||||
<a href="{{ route('bo.sites.show', $ticket->site) }}"
|
||||
title="{{ __('Voir le site :sitename', [
|
||||
'sitename' => $ticket->site->name,
|
||||
]) }}">{{ $ticket->site->name }}</a>
|
||||
@else
|
||||
<span class="text-decoration-underline">{{ $ticket->site->name }}</span>
|
||||
@endif
|
||||
@endcan
|
||||
<span class="{{ $ticket->status->class() }} rounded text-center">
|
||||
{{ $ticket->status->label() }}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="ticket{{ $ticket->id }}Modal"
|
||||
aria-labelledby="ticket{{ $ticket->id }}ModalLabel" aria-hidden="true" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="ticket{{ $ticket->id }}ModalLabel">
|
||||
@can('isAdmin')
|
||||
<a href="{{ route('bo.sites.show', $ticket->site) }}"
|
||||
title="{{ __('Voir le site :sitename', [
|
||||
'sitename' => $ticket->site->name,
|
||||
]) }}"><b>{{ $ticket->site->name }}</b></a>
|
||||
@else
|
||||
<b>{{ $ticket->site->name }}</b>
|
||||
@endcan -
|
||||
<u>
|
||||
{{ __('Ticket n°') }} {{ $ticket->id }}
|
||||
@if ($ticket->is_internal)
|
||||
<i class="fa-solid fa-lock"></i>
|
||||
@endif
|
||||
</u> -
|
||||
<span class="badge {{ $ticket->type->class() }}">
|
||||
{{ $ticket->type->label() }}
|
||||
</span>
|
||||
</h5>
|
||||
<button class="btn btn-sm btn-primary bg-primary" data-bs-dismiss="modal"
|
||||
type="button" aria-label="Close">
|
||||
<i class="fa-solid fa-xmark text-white"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
@can('assignLabels', App\Models\Ticket::class)
|
||||
<div class="mb-3 mt-1">
|
||||
@foreach ($ticket->labels as $label)
|
||||
<span class="badge label colorize"
|
||||
data-color="{{ $label->color }}">{{ $label->name }}</span>
|
||||
@endforeach
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<span class="me-1">{{ $ticket->title }}</span>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<span class="badge {{ $ticket->type->class() }}">{{ $ticket->type->label() }}</span>
|
||||
</td>
|
||||
@php
|
||||
$routeName = request()->route()->getName();
|
||||
@endphp
|
||||
@can('assignLabels', App\Models\Ticket::class)
|
||||
<td>
|
||||
<span class="ticket-index-labels">
|
||||
@foreach ($ticket->labels as $label)
|
||||
<span class="badge label colorize"
|
||||
data-color="{{ $label->color }}">{{ $label->name }}</span>
|
||||
@endforeach
|
||||
</span>
|
||||
</td>
|
||||
@endcan
|
||||
@if (Auth::user()->isAdmin())
|
||||
<td>{{ $ticket->assignedUser ? $ticket->assignedUser->name : __('Personne') }}</td>
|
||||
@endif
|
||||
@if (
|
||||
!request()->sort_col
|
||||
&& !request()->sort_way
|
||||
&& !request()->ass
|
||||
&& !request()->st
|
||||
&& !request()->pr
|
||||
&& !request()->ty
|
||||
&& !request()->search
|
||||
)
|
||||
@include('bo.modules.change-model-order', [
|
||||
'routeName' => 'ticket',
|
||||
'model' => $ticket,
|
||||
'models' => $tickets,
|
||||
])
|
||||
@endif
|
||||
<td>{{ Carbon\Carbon::parse($ticket->created_at)->format('d/m/Y à H:i') }}</td>
|
||||
<td>
|
||||
<div class="d-flex flex-column">
|
||||
<div>
|
||||
<div class="btn-group" role="group">
|
||||
@php
|
||||
$ticket_files = $ticket->getFiles();
|
||||
@endphp
|
||||
@foreach ($ticket_files as $key => $file)
|
||||
@if ($file !== null && (\App\Lib\Helpers\ToolboxHelper::isImageFile($file) || \App\Lib\Helpers\ToolboxHelper::isPdfFile($file)))
|
||||
<a class="glightbox btn btn-outline-dark"
|
||||
data-gallery="gallery{{ $ticket->id }}" href="{{ asset($file) }}"
|
||||
target="_blank"><i class="fa-solid fa-file-image"></i>
|
||||
</a>
|
||||
@break
|
||||
@endif
|
||||
@endforeach
|
||||
{{-- Modal du ticket --}}
|
||||
<!-- Button trigger modal -->
|
||||
<button class="btn btn-outline-info" data-bs-toggle="modal"
|
||||
data-bs-target="#ticket{{ $ticket->id }}Modal" type="button"><i
|
||||
class="fa-solid fa-eye"></i></button>
|
||||
<a class="btn btn-outline-success"
|
||||
href="{{ route('bo.ticket.show', $ticket->id) }}"><i
|
||||
class="fa-solid fa-comment"></i></a>
|
||||
@if (auth()->user()->isAdmin())
|
||||
<a class="btn btn-outline-primary"
|
||||
href="{{ route('bo.ticket.edit', $ticket) }}"><i
|
||||
class="fa-solid fa-pen"></i></a>
|
||||
@endif
|
||||
@can('changeStatus', $ticket)
|
||||
@if (!$ticket->status->equals(\App\Enums\Tickets\TicketStatusEnum::archived))
|
||||
<form class="confirmJS" method="POST"
|
||||
action="{{ route('bo.ticket.archive', $ticket) }}">
|
||||
@method('PUT')
|
||||
@csrf
|
||||
<button class="btn btn-outline-danger rounded-0 rounded-end" type="submit"><i
|
||||
class="fa-solid fa-box-archive"></i></button>
|
||||
</form>
|
||||
@endif
|
||||
@endcan
|
||||
<p>{!! clean(nl2br($ticket->text)) !!}</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-sm btn-primary" data-bs-dismiss="modal"
|
||||
type="button">{{ __('Fermer') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
{{ $tickets->withQueryString()->links() }}
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="ticket{{ $ticket->id }}Modal"
|
||||
aria-labelledby="ticket{{ $ticket->id }}ModalLabel" aria-hidden="true" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="ticket{{ $ticket->id }}ModalLabel">
|
||||
@can('isAdmin')
|
||||
<a href="{{ route('bo.sites.show', $ticket->site) }}"
|
||||
title="{{ __('Voir le site :sitename', [
|
||||
'sitename' => $ticket->site->name,
|
||||
]) }}"><b>{{ $ticket->site->name }}</b></a>
|
||||
@else
|
||||
<b>{{ $ticket->site->name }}</b>
|
||||
@endcan -
|
||||
<u>
|
||||
{{ __('Ticket n°') }} {{ $ticket->id }}
|
||||
@if ($ticket->is_internal)
|
||||
<i class="fa-solid fa-lock"></i>
|
||||
@endif
|
||||
</u> -
|
||||
<span class="badge {{ $ticket->type->class() }}">
|
||||
{{ $ticket->type->label() }}
|
||||
</span>
|
||||
</h5>
|
||||
<button class="btn btn-sm btn-primary bg-primary" data-bs-dismiss="modal"
|
||||
type="button" aria-label="Close">
|
||||
<i class="fa-solid fa-xmark text-white"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
@can('assignLabels', App\Models\Ticket::class)
|
||||
<div class="mb-3 mt-1">
|
||||
@foreach ($ticket->labels as $label)
|
||||
<span class="badge label colorize"
|
||||
data-color="{{ $label->color }}">{{ $label->name }}</span>
|
||||
@endforeach
|
||||
</div>
|
||||
@endcan
|
||||
<p>{!! clean(nl2br($ticket->text)) !!}</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-sm btn-primary" data-bs-dismiss="modal"
|
||||
type="button">{{ __('Fermer') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{ $tickets->withQueryString()->links() }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
@if(!session('tickets.sort_way') or session('tickets.sort_col') !== $colname or (session('tickets.sort_way') === 'desc' and session('tickets.sort_col') === $colname))
|
||||
<a class="col_sort text-secondary lead asc" href="{{ request()->fullUrlWithQuery(['sort_col' => $colname, 'sort_way' => 'asc']) }}"> ↓ </a>
|
||||
@endif
|
||||
@if(!session('tickets.sort_way') or session('tickets.sort_col') !== $colname or (session('tickets.sort_way') === 'asc' and session('tickets.sort_col') === $colname))
|
||||
<a class="col_sort text-secondary lead desc" href="{{ request()->fullUrlWithQuery(['sort_col' => $colname, 'sort_way' => 'desc']) }}"> ↑ </a>
|
||||
@endif
|
||||
|
|
@ -147,6 +147,10 @@ Route::middleware('admin-secure')
|
|||
Route::post('/{ticket}/status', [TicketController::class, 'changeStatus'])
|
||||
->middleware('can:changeStatus,ticket')
|
||||
->name('changeStatus');
|
||||
Route::patch('/{ticket}/change-order/{direction}', [
|
||||
TicketController::class,
|
||||
'changeOrder'
|
||||
])->where('direction', 'up|down')->name('change-order');
|
||||
Route::post('/{ticket}/subscribe', [TicketController::class, 'subscribe'])
|
||||
->middleware('can:suscribeToTicket,ticket')
|
||||
->name('subscribe');
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue