[Fix] PartnerController Refactor | [Fix] Ticket improvements (#690)

This commit is contained in:
Dennis 2023-01-31 14:25:14 +01:00 committed by GitHub
commit e180704dd1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 184 additions and 232 deletions

View file

@ -1,7 +1,8 @@
<?php
namespace App\Http\Controllers;
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\PartnerDiscount;
use App\Models\User;
use Illuminate\Http\Request;
@ -40,26 +41,19 @@ class PartnerController extends Controller
'registered_user_discount' => 'required|integer|max:100|min:0',
]);
if(PartnerDiscount::where("user_id",$request->user_id)->exists()){
return redirect()->route('admin.partners.index')->with('error', __('Partner already exists'));
}
PartnerDiscount::create($request->all());
return redirect()->route('admin.partners.index')->with('success', __('partner has been created!'));
}
/**
* Display the specified resource.
*
* @param Voucher $voucher
* @return Response
*/
public function show(Voucher $voucher)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param Voucher $voucher
* @param Partner $partner
* @return Application|Factory|View
*/
public function edit(PartnerDiscount $partner)
@ -75,7 +69,7 @@ class PartnerController extends Controller
* Update the specified resource in storage.
*
* @param Request $request
* @param Voucher $voucher
* @param Partner $partner
* @return RedirectResponse
*/
public function update(Request $request, PartnerDiscount $partner)
@ -95,7 +89,7 @@ class PartnerController extends Controller
/**
* Remove the specified resource from storage.
*
* @param Voucher $voucher
* @param Partner $partner
* @return RedirectResponse
*/
public function destroy(PartnerDiscount $partner)
@ -105,81 +99,7 @@ class PartnerController extends Controller
return redirect()->back()->with('success', __('partner has been removed!'));
}
public function users(Voucher $voucher)
{
return view('admin.vouchers.users', [
'voucher' => $voucher,
]);
}
/**
* @param Request $request
* @return JsonResponse
*
* @throws ValidationException
*/
public function redeem(Request $request)
{
//general validations
$request->validate([
'code' => 'required|exists:vouchers,code',
]);
//get voucher by code
$voucher = Voucher::where('code', '=', $request->input('code'))->firstOrFail();
//extra validations
if ($voucher->getStatus() == 'USES_LIMIT_REACHED') {
throw ValidationException::withMessages([
'code' => __('This voucher has reached the maximum amount of uses'),
]);
}
if ($voucher->getStatus() == 'EXPIRED') {
throw ValidationException::withMessages([
'code' => __('This voucher has expired'),
]);
}
if (! $request->user()->vouchers()->where('id', '=', $voucher->id)->get()->isEmpty()) {
throw ValidationException::withMessages([
'code' => __('You already redeemed this voucher code'),
]);
}
if ($request->user()->credits + $voucher->credits >= 99999999) {
throw ValidationException::withMessages([
'code' => "You can't redeem this voucher because you would exceed the limit of ".CREDITS_DISPLAY_NAME,
]);
}
//redeem voucher
$voucher->redeem($request->user());
event(new UserUpdateCreditsEvent($request->user()));
return response()->json([
'success' => "{$voucher->credits} ".CREDITS_DISPLAY_NAME.' '.__('have been added to your balance!'),
]);
}
public function usersDataTable(Voucher $voucher)
{
$users = $voucher->users();
return datatables($users)
->editColumn('name', function (User $user) {
return '<a class="text-info" target="_blank" href="'.route('admin.users.show', $user->id).'">'.$user->name.'</a>';
})
->addColumn('credits', function (User $user) {
return '<i class="fas fa-coins mr-2"></i> '.$user->credits();
})
->addColumn('last_seen', function (User $user) {
return $user->last_seen ? $user->last_seen->diffForHumans() : '';
})
->rawColumns(['name', 'credits', 'last_seen'])
->make();
}
public function dataTable()
{

View file

@ -50,7 +50,7 @@ class TicketsController extends Controller
$ticket = new Ticket([
'title' => $request->input('title'),
'user_id' => Auth::user()->id,
'ticket_id' => strtoupper(Str::random(5)),
'ticket_id' => strtoupper(Str::random(8)),
'ticketcategory_id' => $request->input('ticketcategory'),
'priority' => $request->input('priority'),
'message' => $request->input('message'),

View file

@ -1,93 +1,24 @@
@import "default.css";
/******************* CUSTOM CSS ********************/
.layout-fixed .wrapper .sidebar {
height: calc(100vh - 3.5rem - 1px);
background: radial-gradient(#061b29, black);
}
body:not(.sidebar-mini-md) .content-wrapper, body:not(.sidebar-mini-md) .main-footer, body:not(.sidebar-mini-md) .main-header {
transition: margin-left .3s ease-in-out;
margin-left: 250px;
background: radial-gradient(#061b29, black);
}
[class*=sidebar-dark] .brand-link, [class*=sidebar-dark] .brand-link .pushmenu {
color: hsla(0,0%,100%,.8);
background: radial-gradient(#061b29, black);
}
.main-sidebar .brand-text, .main-sidebar .logo-xl, .main-sidebar .logo-xs, .sidebar .nav-link p, .sidebar .user-panel .info {
transition: margin-left .3s linear,opacity .3s ease,visibility .3s ease;
color: #d3d3d3;
}
.sidebar-dark-primary .nav-sidebar>.nav-item>.nav-link.active, .sidebar-light-primary .nav-sidebar>.nav-item>.nav-link.active {
color: #fff;
background: radial-gradient(#1b4b61, #fd030300);
border-radius: 50px;
}
.dark-mode .card {
background-color: #00000000;
color: #ffffff99;
border-width: 3px;
border-color: #f7f7f7;
border-style: double;
border-radius: 15px;
}
.btn-info {
color: #ffffff;
background-color: #b8171700;
border-color: #ffffff;
box-shadow: none;
}
.btn-warning {
color: #ffffff;
background-color: #ffc10700;
border-color: #ffffff;
box-shadow: none;
}
.card-title {
float: left;
font-size: 1.1rem;
font-weight: 400;
margin: 0;
color: white;
}
.dark-mode .text-muted {
color: #ffffff99!important;
}
.dark-mode .list-group-item {
background-color: #343a4000;
border-color: #ffffff99;
}
.dark-mode .info-box {
background-color: #343a4000;
color: #fff;
border: 3px;
border-style: double;
border-radius: 15px;
border-color: white;
}
label:not(.form-check-label):not(.custom-file-label) {
font-weight: 700;
color: #ffffffc2;
}
.dark-mode .custom-control-label:before, .dark-mode .custom-file-label, .dark-mode .custom-file-label:after, .dark-mode .custom-select, .dark-mode .form-control, .dark-mode .input-group-text {
background-color: #007af400;
color: #828282;
}
@import "default.css";.layout-fixed .wrapper .sidebar{ height:calc(100vh - 3.5rem - 1px);background:radial-gradient(#061b29,black);}
body:not(.sidebar-mini-md) .content-wrapper,body:not(.sidebar-mini-md) .main-footer,body:not(.sidebar-mini-md) .main-header{ transition:margin-left .3s ease-in-out;margin-left:250px;background:radial-gradient(#061b29,black);}
[class*=sidebar-dark] .brand-link,[class*=sidebar-dark] .brand-link .pushmenu{ color:hsla(0,0%,100%,.8);background:radial-gradient(#061b29,black);}
.main-sidebar .brand-text,.main-sidebar .logo-xl,.main-sidebar .logo-xs,.sidebar .nav-link p,.sidebar .user-panel .info{ transition:margin-left .3s linear,opacity .3s ease,visibility .3s ease;color:#d3d3d3;}
.sidebar-dark-primary .nav-sidebar>.nav-item>.nav-link.active,.sidebar-light-primary .nav-sidebar>.nav-item>.nav-link.active{ color:#fff;background:radial-gradient(#1b4b61,#fd030300);border-radius:50px;}
.dark-mode .card{ background-color:#00000000;color:#ffffff99;border-width:3px;border-color:#f7f7f7;border-style:double;border-radius:15px;}
.btn-info{ color:#ffffff;background-color:#b8171700;border-color:#ffffff;box-shadow:none;}
.btn-warning{ color:#ffffff;background-color:#ffc10700;border-color:#ffffff;box-shadow:none;}
.card-title{ float:left;font-size:1.1rem;font-weight:400;margin:0;color:white;}
.dark-mode .text-muted{ color:#ffffff99!important;}
.dark-mode .list-group-item{ background-color:#343a4000;border-color:#ffffff99;}
.dark-mode .info-box{ background-color:#343a4000;color:#fff;border:3px;border-style:double;border-radius:15px;border-color:white;}
label:not(.form-check-label):not(.custom-file-label){ font-weight:700;color:#ffffffc2;}
.dark-mode .custom-control-label:before,.dark-mode .custom-file-label,.dark-mode .custom-file-label:after,.dark-mode .custom-select,.dark-mode .form-control,.dark-mode .input-group-text{ background-color:#007af400;color:#828282;}
.alert-success{ color:#fff;background-color:#28a745;border-color:#ffffff;border-radius:15px;border-style:double;}
.dark-mode{ color:#fff;background:radial-gradient(#061b29,black);}
.dark-mode .invoice{ background-color:#343a4000;border:3px;border-radius:15px;border-color:white;border:double;}
.dark-mode .nav-tabs .nav-item.show .nav-link,.dark-mode .nav-tabs .nav-link.active{ background-color:#ffffff1c;color:#fff;}
.slim-crop-area img,.slim-image-editor img,.slim-popover img,.slim img{ background:black;}
.dark-mode .callout{ background-color:#00ff0333;}
.callout.callout-info{ border-left-color:#00e11d;}
.p-3{ padding:1rem!important;background:#04141e;}
.small-box>.small-box-footer{ color:hsla(0,0%,100%,.8);display:block;padding:3px 0;position:relative;text-align:center;text-decoration:none;z-index:10;background:#061b29;}
.dark-mode .dropdown-menu{ background-color:#061b29;border-color:white;}

View file

@ -10,6 +10,7 @@ use App\Http\Controllers\Admin\ApplicationApiController;
use App\Http\Controllers\Admin\InvoiceController;
use App\Http\Controllers\Admin\LegalController;
use App\Http\Controllers\Admin\OverViewController;
use App\Http\Controllers\Admin\PartnerController;
use App\Http\Controllers\Admin\PaymentController;
use App\Http\Controllers\Admin\ProductController;
use App\Http\Controllers\Admin\ServerController as AdminServerController;
@ -22,7 +23,6 @@ use App\Http\Controllers\Auth\SocialiteController;
use App\Http\Controllers\HomeController;
use App\Http\Controllers\Moderation\TicketsController as ModTicketsController;
use App\Http\Controllers\NotificationController;
use App\Http\Controllers\PartnerController;
use App\Http\Controllers\ProductController as FrontProductController;
use App\Http\Controllers\ProfileController;
use App\Http\Controllers\ServerController;

View file

@ -6,12 +6,12 @@
<div class="container-fluid">
<div class="row mb-2">
<div class="col-sm-6">
<h1>{{__('Vouchers')}}</h1>
<h1>{{__('Partner')}}</h1>
</div>
<div class="col-sm-6">
<ol class="breadcrumb float-sm-right">
<li class="breadcrumb-item"><a href="{{route('home')}}">{{__('Dashboard')}}</a></li>
<li class="breadcrumb-item"><a href="{{route('admin.partners.index')}}">{{__('Vouchers')}}</a>
<li class="breadcrumb-item"><a href="{{route('admin.partners.index')}}">{{__('Partner')}}</a>
</li>
<li class="breadcrumb-item"><a class="text-muted"
href="{{route('admin.partners.create')}}">{{__('Create')}}</a>
@ -40,19 +40,14 @@
@csrf
<div class="form-group">
<label for="user_id">{{__('User')}}</label>
<select id="user_id" style="width:100%"
class="custom-select @error('user') is-invalid @enderror" name="user_id" autocomplete="off">
@foreach($users as $user)
<option @if($partners->contains('user_id' , $user->id)) disabled @endif
value="{{$user->id}}">{{$user->name}} ({{$user->email}})</option>
@endforeach
<div class="custom-control mb-3 p-0">
<label for="user_id">{{ __('User') }}:
</label>
<select id="user_id" style="width:100%" class="custom-select" name="user_id" required
autocomplete="off" @error('user_id') is-invalid @enderror>
</select>
@error('user')
<div class="text-danger">
{{$message}}
</div>
@enderror
</div>
<div class="form-group">
@ -143,5 +138,75 @@
})
</script>
<script type="application/javascript">
function initUserIdSelect(data) {
function escapeHtml(str) {
var div = document.createElement('div');
div.appendChild(document.createTextNode(str));
return div.innerHTML;
}
$('#user_id').select2({
ajax: {
url: '/admin/users.json',
dataType: 'json',
delay: 250,
data: function (params) {
return {
filter: { name: params.term },
page: params.page,
};
},
processResults: function (data, params) {
return { results: data };
},
cache: true,
},
data: data,
escapeMarkup: function (markup) { return markup; },
minimumInputLength: 2,
templateResult: function (data) {
if (data.loading) return escapeHtml(data.text);
return '<div class="user-block"> \
<img class="img-circle img-bordered-xs" src="' + escapeHtml(data.avatarUrl) + '?s=120" alt="User Image"> \
<span class="username"> \
<a href="#">' + escapeHtml(data.name) +'</a> \
</span> \
<span class="description"><strong>' + escapeHtml(data.email) + '</strong>' + '</span> \
</div>';
},
templateSelection: function (data) {
return '<div> \
<span> \
<img class="img-rounded img-bordered-xs" src="' + escapeHtml(data.avatarUrl) + '?s=120" style="height:28px;margin-top:-4px;" alt="User Image"> \
</span> \
<span style="padding-left:5px;"> \
' + escapeHtml(data.name) + ' (<strong>' + escapeHtml(data.email) + '</strong>) \
</span> \
</div>';
}
});
}
$(document).ready(function() {
@if (old('user_id'))
$.ajax({
url: '/admin/users.json?user_id={{ old('user_id') }}',
dataType: 'json',
}).then(function (data) {
initUserIdSelect([ data ]);
});
@else
initUserIdSelect();
@endif
});
</script>
@endsection

View file

@ -35,22 +35,40 @@
<div class="card-body">
<div class="ticket-info">
@if(!empty($server))
<p><b>Server:</b> <a href="{{ config("SETTINGS::SYSTEM:PTERODACTYL:URL") . '/admin/servers/view/' . $server->pterodactyl_id }}" target="__blank">{{ $server->name }}</a></p>
@endif
<p><b>Title:</b> {{ $ticket->title }}</p>
<p><b>Category:</b> {{ $ticketcategory->name }}</p>
<p>
@if ($ticket->status === 'Open')
<b>Status:</b> <span class="badge badge-success">Open</span>
@elseif ($ticket->status === 'Closed')
<b>Status:</b> <span class="badge badge-danger">Closed</span>
@elseif ($ticket->status === 'Answered')
<b>Status:</b> <span class="badge badge-info">Answered</span>
@elseif ($ticket->status === 'Client Reply')
<b>Status:</b> <span class="badge badge-warning">Client Reply</span>
<p><b>{{__("Server")}}:</b> <a href="{{ config("SETTINGS::SYSTEM:PTERODACTYL:URL") . '/admin/servers/view/' . $server->pterodactyl_id }}" target="__blank">{{ $server->name }}</a></p>
@endif
<p><b>{{__("Title")}}:</b> {{ $ticket->title }}</p>
<p><b>{{__("Category")}}:</b> {{ $ticketcategory->name }}</p>
<p><b>{{__("Status")}}:</b>
@switch($ticket->status)
@case("Open")
<span class="badge badge-success">{{__("Open")}}</span>
@break
@case("Closed")
<span class="badge badge-danger">{{__("Closed")}}</span>
@break
@case("Answered")
<span class="badge badge-info">{{__("Answered")}}</span>
@break
@case("Client Reply")
<span class="badge badge-warning">{{__("Client Reply")}}</span>
@break
@endswitch
</p>
<p><b>Created on:</b> {{ $ticket->created_at->diffForHumans() }}</p>
<p><b>Priority:</b>
@switch($ticket->priority)
@case("Low")
<span class="badge badge-success">{{__("Low")}}</span>
@break
@case("Medium")
<span class="badge badge-warning">{{__("Closed")}}</span>
@break
@case("High")
<span class="badge badge-danger">{{__("Answered")}}</span>
@break
@endswitch
</p>
<p><b>{{__("Created on")}}:</b> {{ $ticket->created_at->diffForHumans() }}</p>
@if($ticket->status!='Closed')
<form class="d-inline" method="post" action="{{route('moderator.ticket.close', ['ticket_id' => $ticket->ticket_id ])}}">
{{csrf_field()}}

View file

@ -35,22 +35,40 @@
<div class="card-body">
<div class="ticket-info">
@if(!empty($server))
<p><b>Server:</b> <a href="{{ config('SETTINGS::SYSTEM:PTERODACTYL:URL') }}/server/{{ $server->identifier }}" target="__blank">{{ $server->name }} </a></p>
@endif
<p><b>Title:</b> {{ $ticket->title }}</p>
<p><b>Category:</b> {{ $ticketcategory->name }}</p>
<p>
@if ($ticket->status === 'Open')
<b>Status:</b> <span class="badge badge-success">Open</span>
@elseif ($ticket->status === 'Closed')
<b>Status:</b> <span class="badge badge-danger">Closed</span>
@elseif ($ticket->status === 'Answered')
<b>Status:</b> <span class="badge badge-info">Answered</span>
@elseif ($ticket->status === 'Client Reply')
<b>Status:</b> <span class="badge badge-warning">Client Reply</span>
<p><b>{{__("Server")}}:</b> <a href="{{ config('SETTINGS::SYSTEM:PTERODACTYL:URL') }}/server/{{ $server->identifier }}" target="__blank">{{ $server->name }} </a></p>
@endif
<p><b>{{__("Title")}}:</b> {{ $ticket->title }}</p>
<p><b>{{__("Category")}}:</b> {{ $ticketcategory->name }}</p>
<p><b>{{__("Status")}}:</b>
@switch($ticket->status)
@case("Open")
<span class="badge badge-success">{{__("Open")}}</span>
@break
@case("Closed")
<span class="badge badge-danger">{{__("Closed")}}</span>
@break
@case("Answered")
<span class="badge badge-info">{{__("Answered")}}</span>
@break
@case("Client Reply")
<span class="badge badge-warning">{{__("Client Reply")}}</span>
@break
@endswitch
</p>
<p><b>Created on:</b> {{ $ticket->created_at->diffForHumans() }}</p>
<p><b>Priority:</b>
@switch($ticket->priority)
@case("Low")
<span class="badge badge-success">{{__("Low")}}</span>
@break
@case("Medium")
<span class="badge badge-warning">{{__("Closed")}}</span>
@break
@case("High")
<span class="badge badge-danger">{{__("Answered")}}</span>
@break
@endswitch
</p>
<p><b>{{__("Created on")}}:</b> {{ $ticket->created_at->diffForHumans() }}</p>
@if($ticket->status!='Closed')
<form class="d-inline" method="post"
action="{{route('ticket.close', ['ticket_id' => $ticket->ticket_id ])}}">