Ticket System
This commit is contained in:
parent
812126e120
commit
94bbea2690
27 changed files with 1391 additions and 2 deletions
62
app/Http/Controllers/Mod/TicketsController.php
Normal file
62
app/Http/Controllers/Mod/TicketsController.php
Normal file
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Mod;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Ticket;
|
||||
use App\Models\Server;
|
||||
use App\Models\TicketCategory;
|
||||
use App\Models\TicketComment;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use App\Notifications\Ticket\User\ReplyNotification;
|
||||
|
||||
class TicketsController extends Controller
|
||||
{
|
||||
public function index() {
|
||||
$tickets = Ticket::paginate(10);
|
||||
$ticketcategories = TicketCategory::all();
|
||||
return view("admin.ticket.index", compact("tickets", "ticketcategories"));
|
||||
}
|
||||
public function show($ticket_id) {
|
||||
$ticket = Ticket::where("ticket_id", $ticket_id)->firstOrFail();
|
||||
$ticketcomments = $ticket->ticketcomments;
|
||||
$ticketcategory = $ticket->ticketcategory;
|
||||
$server = Server::where('id', $ticket->server)->first();
|
||||
return view("admin.ticket.show", compact("ticket", "ticketcategory", "ticketcomments", "server"));
|
||||
}
|
||||
|
||||
public function close($ticket_id) {
|
||||
$ticket = Ticket::where("ticket_id", $ticket_id)->firstOrFail();
|
||||
$ticket->status = "Closed";
|
||||
$ticket->save();
|
||||
$ticketOwner = $ticket->user;
|
||||
return redirect()->back()->with('success', __('A ticket has been closed, ID: #') . $ticket->ticket_id);
|
||||
}
|
||||
|
||||
public function delete($ticket_id){
|
||||
$ticket = Ticket::where("ticket_id", $ticket_id)->firstOrFail();
|
||||
TicketComment::where("ticket_id", $ticket->id)->delete();
|
||||
$ticket->delete();
|
||||
return redirect()->back()->with('success', __('A ticket has been deleted, ID: #') . $ticket_id);
|
||||
|
||||
}
|
||||
public function reply(Request $request) {
|
||||
$this->validate($request, array("ticketcomment" => "required"));
|
||||
$ticket = Ticket::where('id', $request->input("ticket_id"))->firstOrFail();
|
||||
$ticket->status = "Answered";
|
||||
$ticket->update();
|
||||
$ticketcomment = TicketComment::create(array(
|
||||
"ticket_id" => $request->input("ticket_id"),
|
||||
"user_id" => Auth::user()->id,
|
||||
"ticketcomment" => $request->input("ticketcomment"),
|
||||
));
|
||||
$user = User::where('id', $ticket->user_id)->firstOrFail();
|
||||
$newmessage = $request->input("ticketcomment");
|
||||
$user->notify(new ReplyNotification($ticket, $user, $newmessage));
|
||||
return redirect()->back()->with('success', __('Your comment has been submitted'));
|
||||
}
|
||||
}
|
84
app/Http/Controllers/TicketsController.php
Normal file
84
app/Http/Controllers/TicketsController.php
Normal file
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
use App\Models\Ticket;
|
||||
use App\Models\Server;
|
||||
use App\Models\TicketComment;
|
||||
use App\Models\TicketCategory;
|
||||
use App\Notifications\Ticket\User\CreateNotification;
|
||||
use App\Notifications\Ticket\Admin\AdminCreateNotification;
|
||||
use App\Notifications\Ticket\Admin\AdminReplyNotification;
|
||||
|
||||
|
||||
class TicketsController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$tickets = Ticket::where("user_id", Auth::user()->id)->paginate(10);
|
||||
$ticketcategories = TicketCategory::all();
|
||||
|
||||
return view("ticket.index", compact("tickets", "ticketcategories"));
|
||||
}
|
||||
public function create() {
|
||||
$ticketcategories = TicketCategory::all();
|
||||
$servers = Auth::user()->servers;
|
||||
return view("ticket.create", compact("ticketcategories", "servers"));
|
||||
}
|
||||
public function store(Request $request) {
|
||||
$this->validate($request, array(
|
||||
"title" => "required",
|
||||
"ticketcategory" => "required",
|
||||
"priority" => "required",
|
||||
"message" => "required")
|
||||
);
|
||||
$ticket = new Ticket(array(
|
||||
"title" => $request->input("title"),
|
||||
"user_id" => Auth::user()->id,
|
||||
"ticket_id" => strtoupper(Str::random(5)),
|
||||
"ticketcategory_id" => $request->input("ticketcategory"),
|
||||
"priority" => $request->input("priority"),
|
||||
"message" => $request->input("message"),
|
||||
"status" => "Open",
|
||||
"server" => $request->input("server"))
|
||||
);
|
||||
$ticket->save();
|
||||
$user = Auth::user();
|
||||
$admin = User::where('role', 'admin')->orWhere('role', 'mod')->get();
|
||||
$user->notify(new CreateNotification($ticket));
|
||||
Notification::send($admin, new AdminCreateNotification($ticket, $user));
|
||||
|
||||
return redirect()->route('ticket.index')->with('success', __('A ticket has been opened, ID: #') . $ticket->ticket_id);
|
||||
}
|
||||
public function show($ticket_id) {
|
||||
$ticket = Ticket::where("ticket_id", $ticket_id)->firstOrFail();
|
||||
$ticketcomments = $ticket->ticketcomments;
|
||||
$ticketcategory = $ticket->ticketcategory;
|
||||
$server = Server::where('id', $ticket->server)->first();
|
||||
return view("ticket.show", compact("ticket", "ticketcategory", "ticketcomments", "server"));
|
||||
}
|
||||
public function reply(Request $request) {
|
||||
$this->validate($request, array("ticketcomment" => "required"));
|
||||
$ticket = Ticket::where('id', $request->input("ticket_id"))->firstOrFail();
|
||||
$ticket->status = "Client Reply";
|
||||
$ticket->update();
|
||||
$ticketcomment = TicketComment::create(array(
|
||||
"ticket_id" => $request->input("ticket_id"),
|
||||
"user_id" => Auth::user()->id,
|
||||
"ticketcomment" => $request->input("ticketcomment"),
|
||||
"message" => $request->input("message")
|
||||
));
|
||||
$user = Auth::user();
|
||||
$admin = User::where('role', 'admin')->orWhere('role', 'mod')->get();
|
||||
$newmessage = $request->input("ticketcomment");
|
||||
Notification::send($admin, new AdminReplyNotification($ticket, $user, $newmessage));
|
||||
return redirect()->back()->with('success', __('Your comment has been submitted'));
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ use App\Http\Middleware\ApiAuthToken;
|
|||
use App\Http\Middleware\CheckSuspended;
|
||||
use App\Http\Middleware\GlobalNames;
|
||||
use App\Http\Middleware\isAdmin;
|
||||
use App\Http\Middleware\isMod;
|
||||
use App\Http\Middleware\LastSeen;
|
||||
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
||||
|
||||
|
@ -72,6 +73,7 @@ class Kernel extends HttpKernel
|
|||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
||||
'admin' => isAdmin::class,
|
||||
'mod' => isMod::class,
|
||||
'api.token' => ApiAuthToken::class,
|
||||
'checkSuspended' => CheckSuspended::class
|
||||
];
|
||||
|
|
27
app/Http/Middleware/isMod.php
Normal file
27
app/Http/Middleware/isMod.php
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Providers\RouteServiceProvider;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class isMod
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if (Auth::user() && Auth::user()->role == 'mod' || Auth::user() && Auth::user()->role == 'admin') {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
return redirect(RouteServiceProvider::HOME);
|
||||
}
|
||||
}
|
21
app/Models/Ticket.php
Normal file
21
app/Models/Ticket.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Ticket extends Model {
|
||||
protected $fillable = [
|
||||
'user_id', 'ticketcategory_id', 'ticket_id', 'title', 'priority', 'message', 'status', 'server'
|
||||
];
|
||||
|
||||
public function ticketcategory(){
|
||||
return $this->belongsTo(TicketCategory::class);}
|
||||
|
||||
public function ticketcomments(){
|
||||
return $this->hasMany(TicketComment::class);}
|
||||
|
||||
public function user(){
|
||||
return $this->belongsTo(User::class);}
|
||||
}
|
||||
|
13
app/Models/TicketCategory.php
Normal file
13
app/Models/TicketCategory.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class TicketCategory extends Model {
|
||||
protected $fillable = ['name'];
|
||||
|
||||
public function tickets(){
|
||||
return $this->hasMany(Ticket::class);}
|
||||
}
|
||||
|
21
app/Models/TicketComment.php
Normal file
21
app/Models/TicketComment.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class TicketComment extends Model {
|
||||
protected $fillable = [
|
||||
'ticket_id', 'user_id', 'ticketcomment'
|
||||
];
|
||||
|
||||
public function ticketcategory(){
|
||||
return $this->belongsTo(TicketCategory::class);}
|
||||
|
||||
public function ticket(){
|
||||
return $this->belongsTo(Ticket::class);}
|
||||
|
||||
public function user(){
|
||||
return $this->belongsTo(User::class);}
|
||||
}
|
||||
|
71
app/Notifications/Ticket/Admin/AdminCreateNotification.php
Normal file
71
app/Notifications/Ticket/Admin/AdminCreateNotification.php
Normal file
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
namespace App\Notifications\Ticket\Admin;
|
||||
|
||||
use App\Models\Ticket;
|
||||
use App\Models\User;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
class AdminCreateNotification extends Notification implements ShouldQueue
|
||||
{
|
||||
|
||||
//THIS IS BASICALLY NOT USED ANYMORE WITH INVOICENOTIFICATION IN PLACE
|
||||
|
||||
use Queueable;
|
||||
|
||||
private Ticket $ticket;
|
||||
private User $user;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Ticket $ticket, User $user)
|
||||
{
|
||||
$this->ticket = $ticket;
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
$via = ['mail','database'];
|
||||
return $via;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return MailMessage
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
return (new MailMessage)
|
||||
->subject('[Ticket ID: ' . $this->ticket->ticket_id . '] ' . $this->ticket->title)
|
||||
->markdown('mail.ticket.admin.create' , ['ticket' => $this->ticket, 'user' => $this->user]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($notifiable)
|
||||
{
|
||||
return [
|
||||
'title' => '[Ticket ID: ' . $this->ticket->ticket_id . '] ' . $this->ticket->title,
|
||||
'content' => "Ticket With ID : {$this->ticket->ticket_id} has been opened by <strong>{$this->user->name}</strong>",
|
||||
];
|
||||
}
|
||||
}
|
78
app/Notifications/Ticket/Admin/AdminReplyNotification.php
Normal file
78
app/Notifications/Ticket/Admin/AdminReplyNotification.php
Normal file
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
|
||||
namespace App\Notifications\Ticket\Admin;
|
||||
|
||||
use App\Models\Ticket;
|
||||
use App\Models\User;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
class AdminReplyNotification extends Notification implements ShouldQueue
|
||||
{
|
||||
|
||||
//THIS IS BASICALLY NOT USED ANYMORE WITH INVOICENOTIFICATION IN PLACE
|
||||
|
||||
use Queueable;
|
||||
|
||||
private Ticket $ticket;
|
||||
private User $user;
|
||||
private $newmessage;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Ticket $ticket, User $user, $newmessage)
|
||||
{
|
||||
$this->ticket = $ticket;
|
||||
$this->user = $user;
|
||||
$this->newmessage = $newmessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
$via = ['mail','database'];
|
||||
return $via;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return MailMessage
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
return (new MailMessage)
|
||||
->subject('[Ticket ID: ' . $this->ticket->ticket_id . '] ' . $this->ticket->title)
|
||||
->markdown('mail.ticket.admin.reply' , ['ticket' => $this->ticket, 'user' => $this->user, 'newmessage' => $this->newmessage]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($notifiable)
|
||||
{
|
||||
return [
|
||||
'title' => '[Ticket ID: ' . $this->ticket->ticket_id . '] ' . $this->ticket->title,
|
||||
'content' => "
|
||||
<p>Ticket With ID : {$this->ticket->ticket_id} has had a new reply posted by <strong>{$this->user->name}</strong></p>
|
||||
<br>
|
||||
<p><strong>Message:</strong></p>
|
||||
<p>{$this->newmessage}</p>
|
||||
",
|
||||
];
|
||||
}
|
||||
}
|
68
app/Notifications/Ticket/User/CreateNotification.php
Normal file
68
app/Notifications/Ticket/User/CreateNotification.php
Normal file
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
namespace App\Notifications\Ticket\User;
|
||||
|
||||
use App\Models\Ticket;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
class CreateNotification extends Notification implements ShouldQueue
|
||||
{
|
||||
|
||||
//THIS IS BASICALLY NOT USED ANYMORE WITH INVOICENOTIFICATION IN PLACE
|
||||
|
||||
use Queueable;
|
||||
|
||||
private Ticket $ticket;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Ticket $ticket)
|
||||
{
|
||||
$this->ticket = $ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
$via = ['mail','database'];
|
||||
return $via;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return MailMessage
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
return (new MailMessage)
|
||||
->subject('[Ticket ID: ' . $this->ticket->ticket_id . '] ' . $this->ticket->title)
|
||||
->markdown('mail.ticket.user.create' , ['ticket' => $this->ticket]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($notifiable)
|
||||
{
|
||||
return [
|
||||
'title' => '[Ticket ID: ' . $this->ticket->ticket_id . '] ' . $this->ticket->title,
|
||||
'content' => "Your Ticket has been Created With ID : {$this->ticket->ticket_id}",
|
||||
];
|
||||
}
|
||||
}
|
78
app/Notifications/Ticket/User/ReplyNotification.php
Normal file
78
app/Notifications/Ticket/User/ReplyNotification.php
Normal file
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
|
||||
namespace App\Notifications\Ticket\User;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Ticket;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
class ReplyNotification extends Notification implements ShouldQueue
|
||||
{
|
||||
|
||||
//THIS IS BASICALLY NOT USED ANYMORE WITH INVOICENOTIFICATION IN PLACE
|
||||
|
||||
use Queueable;
|
||||
|
||||
private Ticket $ticket;
|
||||
private User $user;
|
||||
private $newmessage;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Ticket $ticket, User $user, $newmessage)
|
||||
{
|
||||
$this->ticket = $ticket;
|
||||
$this->user = $user;
|
||||
$this->newmessage = $newmessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
$via = ['mail','database'];
|
||||
return $via;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return MailMessage
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
return (new MailMessage)
|
||||
->subject('[Ticket ID: ' . $this->ticket->ticket_id . '] ' . $this->ticket->title)
|
||||
->markdown('mail.ticket.user.reply' , ['ticket' => $this->ticket, 'user' => $this->user, 'newmessage' => $this->newmessage]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($notifiable)
|
||||
{
|
||||
return [
|
||||
'title' => '[Ticket ID: ' . $this->ticket->ticket_id . '] ' . $this->ticket->title,
|
||||
'content' => "
|
||||
<p>Ticket With ID : {$this->ticket->ticket_id} A response has been added to your ticket. Please see below for our response!</p>
|
||||
<br>
|
||||
<p><strong>Message:</strong></p>
|
||||
<p>{$this->newmessage}</p>
|
||||
",
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateTicketsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('tickets', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->integer('user_id')->unsigned();
|
||||
$table->integer('ticketcategory_id')->unsigned();
|
||||
$table->string('ticket_id')->unique();
|
||||
$table->string('title');
|
||||
$table->string('priority');
|
||||
$table->text('message');
|
||||
$table->string('status');
|
||||
$table->string('server')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('tickets');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateTicketCategoriesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('ticket_categories', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('name');
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
DB::table('ticket_categories')->insert(
|
||||
array(
|
||||
'name' => 'Technical',
|
||||
)
|
||||
);
|
||||
DB::table('ticket_categories')->insert(
|
||||
array(
|
||||
'name' => 'Billing',
|
||||
)
|
||||
);
|
||||
DB::table('ticket_categories')->insert(
|
||||
array(
|
||||
'name' => 'Issue',
|
||||
)
|
||||
);
|
||||
DB::table('ticket_categories')->insert(
|
||||
array(
|
||||
'name' => 'Request',
|
||||
)
|
||||
);
|
||||
DB::table('ticket_categories')->insert(
|
||||
array(
|
||||
'name' => 'Other',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('ticket_categories');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateTicketCommentsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('ticket_comments', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->integer('ticket_id')->unsigned();
|
||||
$table->integer('user_id')->unsigned();
|
||||
$table->text('ticketcomment');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('ticket_comments');
|
||||
}
|
||||
}
|
|
@ -104,6 +104,9 @@
|
|||
value="admin">
|
||||
{{__(' Administrator')}}
|
||||
</option>
|
||||
<option @if($user->role == 'mod') selected @endif class="text-info" value="mod">
|
||||
{{__(' Moderator')}}
|
||||
</option>
|
||||
<option @if($user->role == 'client') selected @endif class="text-success"
|
||||
value="client">
|
||||
{{__('Client')}}
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
</div>
|
||||
<div class="col-lg-8">
|
||||
<span style="max-width: 250px;"
|
||||
class="d-inline-block text-truncate badge {{$user->role == 'admin' ? 'badge-info' : 'badge-secondary'}}">
|
||||
class="d-inline-block text-truncate badge {{$user->role == 'admin' || $user->role == 'mod' ? 'badge-info' : 'badge-secondary'}}">
|
||||
{{$user->role}}
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
@ -225,7 +225,24 @@
|
|||
</a>
|
||||
</li>
|
||||
@endif
|
||||
<li class="nav-item">
|
||||
<a href="{{ route('ticket.index') }}" class="nav-link @if (Request::routeIs('ticket.*')) active @endif">
|
||||
<i class="nav-icon fas fas fa-ticket-alt"></i>
|
||||
<p>{{ __('Support Ticket') }}</p>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@if (Auth::user()->role == 'admin' || Auth::user()->role == 'mod')
|
||||
<li class="nav-header">{{ __('Moderation') }}</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a href="{{ route('mod.ticket.index') }}" class="nav-link @if (Request::routeIs('mod.ticket.*')) active @endif">
|
||||
<i class="nav-icon fas fa-ticket-alt"></i>
|
||||
<p>{{ __('Ticket List') }}</p>
|
||||
</a>
|
||||
</li>
|
||||
@endif
|
||||
|
||||
@if (Auth::user()->role == 'admin')
|
||||
|
||||
<li class="nav-header">{{ __('Administration') }}</li>
|
||||
|
|
25
resources/views/mail/ticket/admin/create.blade.php
Normal file
25
resources/views/mail/ticket/admin/create.blade.php
Normal file
|
@ -0,0 +1,25 @@
|
|||
@component('mail::message')
|
||||
Ticket #{{$ticket->ticket_id}} has been opened by **{{$user->name}}**
|
||||
|
||||
### Details:
|
||||
Client: {{$user->name}} <br>
|
||||
Subject: {{$ticket->title}} <br>
|
||||
Category: {{ $ticket->ticketcategory->name }} <br>
|
||||
Priority: {{ $ticket->priority }} <br>
|
||||
Status: {{ $ticket->status }} <br>
|
||||
|
||||
___
|
||||
```
|
||||
{{ $ticket->message }}
|
||||
```
|
||||
___
|
||||
<br>
|
||||
You can respond to this ticket by simply replying to this email or through the admin area at the url below.
|
||||
<br>
|
||||
|
||||
{{ route('mod.ticket.show', ['ticket_id' => $ticket->ticket_id]) }}
|
||||
|
||||
<br>
|
||||
{{__('Thanks')}},<br>
|
||||
{{ config('app.name') }}
|
||||
@endcomponent
|
25
resources/views/mail/ticket/admin/reply.blade.php
Normal file
25
resources/views/mail/ticket/admin/reply.blade.php
Normal file
|
@ -0,0 +1,25 @@
|
|||
@component('mail::message')
|
||||
Ticket #{{$ticket->ticket_id}} has had a new reply posted by **{{$user->name}}**
|
||||
|
||||
### Details
|
||||
Client: {{$user->name}} <br>
|
||||
Subject: {{$ticket->title}} <br>
|
||||
Category: {{ $ticket->ticketcategory->name }} <br>
|
||||
Priority: {{ $ticket->priority }} <br>
|
||||
Status: {{ $ticket->status }} <br>
|
||||
|
||||
___
|
||||
```
|
||||
{{ $newmessage }}
|
||||
```
|
||||
___
|
||||
<br>
|
||||
You can respond to this ticket by simply replying to this email or through the admin area at the url below.
|
||||
<br>
|
||||
|
||||
{{ route('mod.ticket.show', ['ticket_id' => $ticket->ticket_id]) }}
|
||||
|
||||
<br>
|
||||
{{__('Thanks')}},<br>
|
||||
{{ config('app.name') }}
|
||||
@endcomponent
|
13
resources/views/mail/ticket/user/create.blade.php
Normal file
13
resources/views/mail/ticket/user/create.blade.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
@component('mail::message')
|
||||
Hello {{$ticket->user->name}},
|
||||
|
||||
This is a notification that we have received your support request, and your ticket number is **#{{$ticket->ticket_id}}**.
|
||||
|
||||
We will be responding to this ticket as soon as possible. If this is a Setup request, please understand that these requests take longer than regular support timeframes. Please be aware that Setups may take up to 48 hours to be completed.
|
||||
|
||||
Thank you so much for being so understanding.
|
||||
|
||||
<br>
|
||||
{{__('Thanks')}},<br>
|
||||
{{ config('app.name') }}
|
||||
@endcomponent
|
18
resources/views/mail/ticket/user/reply.blade.php
Normal file
18
resources/views/mail/ticket/user/reply.blade.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
@component('mail::message')
|
||||
A response has been added to your ticket. Please see below for our response!
|
||||
|
||||
### Details
|
||||
Ticket ID : {{ $ticket->ticket_id }} <br>
|
||||
Subject: {{ $ticket->title }} <br>
|
||||
Status: {{ $ticket->status }} <br>
|
||||
|
||||
___
|
||||
```
|
||||
{{ $newmessage }}
|
||||
```
|
||||
___
|
||||
<br>
|
||||
<br>
|
||||
{{__('Thanks')}},<br>
|
||||
{{ config('app.name') }}
|
||||
@endcomponent
|
104
resources/views/mod/ticket/index.blade.php
Normal file
104
resources/views/mod/ticket/index.blade.php
Normal file
|
@ -0,0 +1,104 @@
|
|||
@extends('layouts.main')
|
||||
|
||||
@section('content')
|
||||
<!-- CONTENT HEADER -->
|
||||
<section class="content-header">
|
||||
<div class="container-fluid">
|
||||
<div class="row mb-2">
|
||||
<div class="col-sm-6">
|
||||
<h1>{{__('Ticket')}}</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 class="text-muted"
|
||||
href="{{route('mod.ticket.index')}}">{{__('Ticket List')}}</a></li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- END CONTENT HEADER -->
|
||||
|
||||
<!-- MAIN CONTENT -->
|
||||
<section class="content">
|
||||
<div class="container-fluid">
|
||||
|
||||
<div class="card">
|
||||
|
||||
<div class="card-header">
|
||||
<div class="d-flex justify-content-between">
|
||||
<h5 class="card-title"><i class="fas fa-ticket-alt mr-2"></i>{{__('Ticket List')}}</h5>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body table-responsive">
|
||||
|
||||
<table id="datatable" class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Category</th>
|
||||
<th>Title</th>
|
||||
<th>User</th>
|
||||
<th>Status</th>
|
||||
<th>Last Updated</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($tickets as $ticket)
|
||||
<tr>
|
||||
<td>
|
||||
{{ $ticket->ticketcategory->name }}
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ route('mod.ticket.show', ['ticket_id' => $ticket->ticket_id]) }}">
|
||||
#{{ $ticket->ticket_id }} - {{ $ticket->title }}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="/admin/users/{{$ticket->user->id}}">
|
||||
{{ $ticket->user->name }}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
@if ($ticket->status === 'Open')
|
||||
<span class="badge badge-success">Open</span>
|
||||
@elseif ($ticket->status === 'Closed')
|
||||
<span class="badge badge-danger">Closed</span>
|
||||
@elseif ($ticket->status === 'Answered')
|
||||
<span class="badge badge-info">Answered</span>
|
||||
@elseif ($ticket->status === 'Client Reply')
|
||||
<span class="badge badge-warning">Client Reply</span>
|
||||
@endif
|
||||
</td>
|
||||
<td>{{ $ticket->updated_at }}</td>
|
||||
<td>
|
||||
<a data-content="View" data-toggle="popover" data-trigger="hover" data-placement="top" href="{{ route('mod.ticket.show', ['ticket_id' => $ticket->ticket_id]) }}" class="btn btn-sm text-white btn-info mr-1"><i class="fas fa-eye"></i></a>
|
||||
<form class="d-inline" action="{{ route('mod.ticket.close', ['ticket_id' => $ticket->ticket_id ]) }}" method="POST">
|
||||
@csrf
|
||||
<button data-content="Close" data-toggle="popover" data-trigger="hover" data-placement="top" type="submit" class="btn btn-sm text-white btn-warning mr-1"><i class="fas fa-times"></i></button>
|
||||
</form>
|
||||
<form class="d-inline" action="{{ route('mod.ticket.delete', ['ticket_id' => $ticket->ticket_id ]) }}" method="POST">
|
||||
@csrf
|
||||
<button data-content="Delete" data-toggle="popover" data-trigger="hover" data-placement="top" type="submit" class="btn btn-sm text-white btn-danger mr-1"><i class="fas fa-trash"></i></button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<!-- END CUSTOM CONTENT -->
|
||||
|
||||
</section>
|
||||
<!-- END CONTENT -->
|
||||
|
||||
|
||||
|
||||
@endsection
|
141
resources/views/mod/ticket/show.blade.php
Normal file
141
resources/views/mod/ticket/show.blade.php
Normal file
|
@ -0,0 +1,141 @@
|
|||
@extends('layouts.main')
|
||||
|
||||
@section('content')
|
||||
<!-- CONTENT HEADER -->
|
||||
<section class="content-header">
|
||||
<div class="container-fluid">
|
||||
<div class="row mb-2">
|
||||
<div class="col-sm-6">
|
||||
<h1>{{ __('Ticket') }}</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 class="text-muted"
|
||||
href="{{ route('mod.ticket.index') }}">{{ __('Ticket') }}</a>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- END CONTENT HEADER -->
|
||||
|
||||
<!-- MAIN CONTENT -->
|
||||
<section class="content">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="d-flex justify-content-between">
|
||||
<h5 class="card-title"><i class="fas fa-users mr-2"></i>#{{ $ticket->ticket_id }}</h5>
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
@endif
|
||||
</p>
|
||||
<p><b>Created on:</b> {{ $ticket->created_at->diffForHumans() }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="d-flex justify-content-between">
|
||||
<h5 class="card-title"><i class="fas fa-cloud mr-2"></i>{{__('Comment')}}</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="d-flex justify-content-between">
|
||||
<h5 class="card-title"><img
|
||||
src="https://www.gravatar.com/avatar/{{ md5(strtolower($ticket->user->email)) }}?s=25"
|
||||
class="user-image" alt="User Image">
|
||||
<a href="/admin/users/{{$ticket->user->id}}">{{ $ticket->user->name }}</a>
|
||||
@if($ticket->user->role === "member")
|
||||
<span class="badge badge-secondary"> Member </span>
|
||||
@elseif ($ticket->user->role === "client")
|
||||
<span class="badge badge-success"> Client </span>
|
||||
@elseif ($ticket->user->role === "mod")
|
||||
<span class="badge badge-info"> Moderator </span>
|
||||
@elseif ($ticket->user->role === "admin")
|
||||
<span class="badge badge-danger"> Admin </span>
|
||||
@endif
|
||||
</h5>
|
||||
<span class="badge badge-primary">{{ $ticket->created_at->diffForHumans() }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{{ $ticket->message }}
|
||||
</div>
|
||||
</div>
|
||||
@foreach ($ticketcomments as $ticketcomment)
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="d-flex justify-content-between">
|
||||
<h5 class="card-title"><img
|
||||
src="https://www.gravatar.com/avatar/{{ md5(strtolower($ticketcomment->user->email)) }}?s=25"
|
||||
class="user-image" alt="User Image">
|
||||
<a href="/admin/users/{{$ticketcomment->user->id}}">{{ $ticketcomment->user->name }}</a>
|
||||
@if($ticketcomment->user->role === "member")
|
||||
<span class="badge badge-secondary"> Member </span>
|
||||
@elseif ($ticketcomment->user->role === "client")
|
||||
<span class="badge badge-success"> Client </span>
|
||||
@elseif ($ticketcomment->user->role === "mod")
|
||||
<span class="badge badge-info"> Moderator </span>
|
||||
@elseif ($ticketcomment->user->role === "admin")
|
||||
<span class="badge badge-danger"> Admin </span>
|
||||
@endif
|
||||
</h5>
|
||||
<span class="badge badge-primary">{{ $ticketcomment->created_at->diffForHumans() }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{{ $ticketcomment->ticketcomment }}
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
<div class="comment-form">
|
||||
<form action="{{ route('mod.ticket.reply')}}" method="POST" class="form">
|
||||
{!! csrf_field() !!}
|
||||
<input type="hidden" name="ticket_id" value="{{ $ticket->id }}">
|
||||
<div class="form-group{{ $errors->has('ticketcomment') ? ' has-error' : '' }}">
|
||||
<textarea rows="10" id="ticketcomment" class="form-control" name="ticketcomment"></textarea>
|
||||
@if ($errors->has('ticketcomment'))
|
||||
<span class="help-block">
|
||||
<strong>{{ $errors->first('ticketcomment') }}</strong>
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- END CONTENT -->
|
||||
@endsection
|
||||
|
127
resources/views/ticket/create.blade.php
Normal file
127
resources/views/ticket/create.blade.php
Normal file
|
@ -0,0 +1,127 @@
|
|||
@extends('layouts.main')
|
||||
|
||||
@section('content')
|
||||
<!-- CONTENT HEADER -->
|
||||
<section class="content-header">
|
||||
<div class="container-fluid">
|
||||
<div class="row mb-2">
|
||||
<div class="col-sm-6">
|
||||
<h1>{{ __('Ticket') }}</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 class="text-muted"
|
||||
href="{{ route('ticket.index') }}">{{ __('Ticket') }}</a>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- END CONTENT HEADER -->
|
||||
|
||||
<!-- MAIN CONTENT -->
|
||||
<section class="content">
|
||||
<div class="container-fluid">
|
||||
<form action="{{route('ticket.new.store')}}" method="POST">
|
||||
@csrf
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title">
|
||||
<i class="fas fa-money-check-alt mr-2"></i>{{__('Open a new ticket')}}
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group col-sm-12 {{ $errors->has('title') ? ' has-error' : '' }}">
|
||||
<label for="title" class="control-label">Title</label>
|
||||
<input id="title" type="text" class="form-control" name="title" value="{{ old('title') }}">
|
||||
@if ($errors->has('title'))
|
||||
<span class="help-block">
|
||||
<strong>{{ $errors->first('title') }}</strong>
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
@if ($servers->count() >= 1)
|
||||
<div class="form-group col-sm-12 {{ $errors->has('server') ? ' has-error' : '' }}">
|
||||
<label for="server" class="control-label">Servers</label>
|
||||
<select id="server" type="server" class="form-control" name="server">
|
||||
<option value="">Select Servers</option>
|
||||
@foreach ($servers as $server)
|
||||
<option value="{{ $server->id }}">{{ $server->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
|
||||
@if ($errors->has('category'))
|
||||
<span class="help-block">
|
||||
<strong>{{ $errors->first('ticketcategory') }}</strong>
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
<div class="form-group col-sm-12 {{ $errors->has('ticketcategory') ? ' has-error' : '' }}">
|
||||
<label for="ticketcategory" class="control-label">Category</label>
|
||||
<select id="ticketcategory" type="ticketcategory" class="form-control" name="ticketcategory">
|
||||
<option value="">Select Category</option>
|
||||
@foreach ($ticketcategories as $ticketcategory)
|
||||
<option value="{{ $ticketcategory->id }}">{{ $ticketcategory->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
|
||||
@if ($errors->has('category'))
|
||||
<span class="help-block">
|
||||
<strong>{{ $errors->first('ticketcategory') }}</strong>
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
<div class="form-group col-sm-12 {{ $errors->has('priority') ? ' has-error' : '' }}">
|
||||
<label for="priority" class="control-label">Priority</label>
|
||||
<select id="priority" type="" class="form-control" name="priority">
|
||||
<option value="">Select Priority</option>
|
||||
<option value="Low">Low</option>
|
||||
<option value="Medium">Medium</option>
|
||||
<option value="High">High</option>
|
||||
</select>
|
||||
@if ($errors->has('priority'))
|
||||
<span class="help-block">
|
||||
<strong>{{ $errors->first('priority') }}</strong>
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
{{__('Open Ticket')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title">
|
||||
<i class="fas fa-money-check-alt mr-2"></i>{{__('Ticket details')}}
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group col-sm-12 {{ $errors->has('message') ? ' has-error' : '' }}">
|
||||
<label for="message" class="control-label">Message</label>
|
||||
<textarea rows="8" id="message" class="form-control" name="message"></textarea>
|
||||
@if ($errors->has('message'))
|
||||
<span class="help-block">
|
||||
<strong>{{ $errors->first('message') }}</strong>
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
<!-- END CONTENT -->
|
||||
@endsection
|
||||
|
100
resources/views/ticket/index.blade.php
Normal file
100
resources/views/ticket/index.blade.php
Normal file
|
@ -0,0 +1,100 @@
|
|||
@extends('layouts.main')
|
||||
|
||||
@section('content')
|
||||
<!-- CONTENT HEADER -->
|
||||
<section class="content-header">
|
||||
<div class="container-fluid">
|
||||
<div class="row mb-2">
|
||||
<div class="col-sm-6">
|
||||
<h1>{{ __('Ticket') }}</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 class="text-muted"
|
||||
href="{{ route('ticket.index') }}">{{ __('Ticket') }}</a>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- END CONTENT HEADER -->
|
||||
|
||||
<!-- MAIN CONTENT -->
|
||||
<section class="content">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-lg-8">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="d-flex justify-content-between">
|
||||
<h5 class="card-title"><i class="fas fa-ticket-alt mr-2"></i>{{__('My Ticket')}}</h5>
|
||||
<a href="{{route('ticket.new')}}" class="btn btn-sm btn-primary"><i
|
||||
class="fas fa-plus mr-1"></i>{{__('New Ticket')}}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body table-responsive">
|
||||
|
||||
<table id="datatable" class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Category</th>
|
||||
<th>Title</th>
|
||||
<th>Status</th>
|
||||
<th>Last Updated</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($tickets as $ticket)
|
||||
<tr>
|
||||
<td>
|
||||
{{ $ticket->ticketcategory->name }}
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ route('ticket.show', ['ticket_id' => $ticket->ticket_id]) }}">
|
||||
#{{ $ticket->ticket_id }} - {{ $ticket->title }}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
@if ($ticket->status === 'Open')
|
||||
<span class="badge badge-success">Open</span>
|
||||
@elseif ($ticket->status === 'Closed')
|
||||
<span class="badge badge-danger">Closed</span>
|
||||
@elseif ($ticket->status === 'Answered')
|
||||
<span class="badge badge-info">Answered</span>
|
||||
@elseif ($ticket->status === 'Client Reply')
|
||||
<span class="badge badge-warning">Client Reply</span>
|
||||
@endif
|
||||
</td>
|
||||
<td>{{ $ticket->updated_at }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title">{{__('Ticket Information')}}
|
||||
<i data-toggle="popover"
|
||||
data-trigger="hover"
|
||||
data-content="{{__('please make the best of it')}}"
|
||||
class="fas fa-info-circle"></i></h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>Can't start your server? Need an additional port? Do you have any other questions? Let us know by
|
||||
opening a ticket.</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- END CONTENT -->
|
||||
@endsection
|
||||
|
141
resources/views/ticket/show.blade.php
Normal file
141
resources/views/ticket/show.blade.php
Normal file
|
@ -0,0 +1,141 @@
|
|||
@extends('layouts.main')
|
||||
|
||||
@section('content')
|
||||
<!-- CONTENT HEADER -->
|
||||
<section class="content-header">
|
||||
<div class="container-fluid">
|
||||
<div class="row mb-2">
|
||||
<div class="col-sm-6">
|
||||
<h1>{{ __('Ticket') }}</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 class="text-muted"
|
||||
href="{{ route('ticket.index') }}">{{ __('Ticket') }}</a>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- END CONTENT HEADER -->
|
||||
|
||||
<!-- MAIN CONTENT -->
|
||||
<section class="content">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="d-flex justify-content-between">
|
||||
<h5 class="card-title"><i class="fas fa-users mr-2"></i>#{{ $ticket->ticket_id }}</h5>
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
@endif
|
||||
</p>
|
||||
<p><b>Created on:</b> {{ $ticket->created_at->diffForHumans() }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="d-flex justify-content-between">
|
||||
<h5 class="card-title"><i class="fas fa-cloud mr-2"></i>{{__('Comment')}}</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="d-flex justify-content-between">
|
||||
<h5 class="card-title"><img
|
||||
src="https://www.gravatar.com/avatar/{{ md5(strtolower($ticket->user->email)) }}?s=25"
|
||||
class="user-image" alt="User Image">
|
||||
<a href="/admin/users/{{$ticket->user->id}}">{{ $ticket->user->name }} </a>
|
||||
@if($ticket->user->role === "member")
|
||||
<span class="badge badge-secondary"> Member </span>
|
||||
@elseif ($ticket->user->role === "client")
|
||||
<span class="badge badge-success"> Client </span>
|
||||
@elseif ($ticket->user->role === "mod")
|
||||
<span class="badge badge-info"> Moderator </span>
|
||||
@elseif ($ticket->user->role === "admin")
|
||||
<span class="badge badge-danger"> Admin </span>
|
||||
@endif
|
||||
</h5>
|
||||
<span class="badge badge-primary">{{ $ticket->created_at->diffForHumans() }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{{ $ticket->message }}
|
||||
</div>
|
||||
</div>
|
||||
@foreach ($ticketcomments as $ticketcomment)
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="d-flex justify-content-between">
|
||||
<h5 class="card-title"><img
|
||||
src="https://www.gravatar.com/avatar/{{ md5(strtolower($ticketcomment->user->email)) }}?s=25"
|
||||
class="user-image" alt="User Image">
|
||||
<a href="/admin/users/{{$ticketcomment->user->id}}">{{ $ticketcomment->user->name }}</a>
|
||||
@if($ticketcomment->user->role === "member")
|
||||
<span class="badge badge-secondary"> Member </span>
|
||||
@elseif ($ticketcomment->user->role === "client")
|
||||
<span class="badge badge-success"> Client </span>
|
||||
@elseif ($ticketcomment->user->role === "mod")
|
||||
<span class="badge badge-info"> Moderator </span>
|
||||
@elseif ($ticketcomment->user->role === "admin")
|
||||
<span class="badge badge-danger"> Admin </span>
|
||||
@endif
|
||||
</h5>
|
||||
<span class="badge badge-primary">{{ $ticketcomment->created_at->diffForHumans() }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{{ $ticketcomment->ticketcomment }}
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
<div class="comment-form">
|
||||
<form action="{{ route('ticket.reply')}}" method="POST" class="form">
|
||||
{!! csrf_field() !!}
|
||||
<input type="hidden" name="ticket_id" value="{{ $ticket->id }}">
|
||||
<div class="form-group{{ $errors->has('ticketcomment') ? ' has-error' : '' }}">
|
||||
<textarea rows="10" id="ticketcomment" class="form-control" name="ticketcomment"></textarea>
|
||||
@if ($errors->has('ticketcomment'))
|
||||
<span class="help-block">
|
||||
<strong>{{ $errors->first('ticketcomment') }}</strong>
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- END CONTENT -->
|
||||
@endsection
|
||||
|
|
@ -14,6 +14,7 @@ use App\Http\Controllers\Admin\SettingsController;
|
|||
use App\Http\Controllers\Admin\UsefulLinkController;
|
||||
use App\Http\Controllers\Admin\UserController;
|
||||
use App\Http\Controllers\Admin\VoucherController;
|
||||
use App\Http\Controllers\Mod\TicketsController as ModTicketsController;
|
||||
use App\Http\Controllers\Auth\SocialiteController;
|
||||
use App\Http\Controllers\HomeController;
|
||||
use App\Http\Controllers\NotificationController;
|
||||
|
@ -22,6 +23,7 @@ use App\Http\Controllers\ProfileController;
|
|||
use App\Http\Controllers\ServerController;
|
||||
use App\Http\Controllers\StoreController;
|
||||
use App\Http\Controllers\TranslationController;
|
||||
use App\Http\Controllers\TicketsController;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
@ -89,7 +91,13 @@ Route::middleware(['auth', 'checkSuspended'])->group(function () {
|
|||
|
||||
#switch language
|
||||
Route::post('changelocale', [TranslationController::class, 'changeLocale'])->name('changeLocale');
|
||||
|
||||
|
||||
#ticket user
|
||||
Route::get('ticket', [TicketsController::class, 'index'])->name('ticket.index');
|
||||
Route::get('ticket/new', [TicketsController::class, 'create'])->name('ticket.new');
|
||||
Route::post('ticket/new', [TicketsController::class, 'store'])->name('ticket.new.store');
|
||||
Route::get('ticket/show/{ticket_id}', [TicketsController::class, 'show'])->name('ticket.show');
|
||||
Route::post('ticket/reply', [TicketsController::class, 'reply'])->name('ticket.reply');
|
||||
|
||||
#admin
|
||||
Route::prefix('admin')->name('admin.')->middleware('admin')->group(function () {
|
||||
|
@ -164,5 +172,15 @@ Route::middleware(['auth', 'checkSuspended'])->group(function () {
|
|||
]);
|
||||
});
|
||||
|
||||
#mod
|
||||
Route::prefix('mod')->name('mod.')->middleware('mod')->group(function () {
|
||||
#ticket moderation
|
||||
Route::get('ticket', [ModTicketsController::class, 'index'])->name('ticket.index');
|
||||
Route::get('ticket/show/{ticket_id}', [ModTicketsController::class, 'show'])->name('ticket.show');
|
||||
Route::post('ticket/reply', [ModTicketsController::class, 'reply'])->name('ticket.reply');
|
||||
Route::post('ticket/close/{ticket_id}', [ModTicketsController::class, 'close'])->name('ticket.close');
|
||||
Route::post('ticket/delete/{ticket_id}', [ModTicketsController::class, 'delete'])->name('ticket.delete');
|
||||
});
|
||||
|
||||
Route::get('/home', [HomeController::class, 'index'])->name('home');
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue