mirror of
https://github.com/getnamingo/registry.git
synced 2025-05-29 17:00:06 +02:00
Added view ticket
This commit is contained in:
parent
2795e814c2
commit
27f912ed1c
5 changed files with 196 additions and 115 deletions
|
@ -41,6 +41,7 @@ class SupportController extends Controller
|
|||
}
|
||||
|
||||
try {
|
||||
$db->beginTransaction();
|
||||
$currentDateTime = new \DateTime();
|
||||
$crdate = $currentDateTime->format('Y-m-d H:i:s.v');
|
||||
$db->insert(
|
||||
|
@ -62,17 +63,8 @@ class SupportController extends Controller
|
|||
]
|
||||
);
|
||||
$ticket_id = $db->getLastInsertId();
|
||||
|
||||
$db->insert(
|
||||
'ticket_responses',
|
||||
[
|
||||
'ticket_id' => $ticket_id,
|
||||
'responder_id' => $_SESSION['auth_user_id'],
|
||||
'response' => $message,
|
||||
'date_created' => $crdate,
|
||||
]
|
||||
);
|
||||
|
||||
$db->commit();
|
||||
} catch (Exception $e) {
|
||||
$db->rollBack();
|
||||
return view($response, 'admin/support/newticket.twig', [
|
||||
|
@ -96,6 +88,86 @@ class SupportController extends Controller
|
|||
'categories' => $categories,
|
||||
]);
|
||||
}
|
||||
|
||||
public function viewTicket(Request $request, Response $response, $args)
|
||||
{
|
||||
$rawNumber = $args;
|
||||
$ticketNumber = filter_var($rawNumber, FILTER_VALIDATE_INT);
|
||||
|
||||
if ($ticketNumber === false) {
|
||||
$this->container->get('flash')->addMessage('error', 'Invalid ticket number');
|
||||
return $response->withHeader('Location', '/support')->withStatus(302);
|
||||
}
|
||||
|
||||
$db = $this->container->get('db');
|
||||
// Get the current URI
|
||||
$uri = $request->getUri()->getPath();
|
||||
|
||||
$ticket = $db->selectRow('SELECT st.*, u.username AS ticket_creator
|
||||
FROM support_tickets AS st
|
||||
JOIN users AS u ON st.user_id = u.id
|
||||
WHERE st.id = ?', [$ticketNumber]);
|
||||
|
||||
if ($ticket) {
|
||||
$replies = $db->select('SELECT tr.*, u.username AS responder_name
|
||||
FROM ticket_responses AS tr
|
||||
JOIN users AS u ON tr.responder_id = u.id
|
||||
WHERE tr.ticket_id = ?', [$ticketNumber]);
|
||||
$category = $db->selectValue('SELECT name FROM ticket_categories WHERE id = ?', [$ticket['category_id']]);
|
||||
|
||||
// Default view for GET requests or if POST data is not set
|
||||
return view($response,'admin/support/viewTicket.twig', [
|
||||
'ticket' => $ticket,
|
||||
'replies' => $replies,
|
||||
'category' => $category,
|
||||
'currentUri' => $uri
|
||||
]);
|
||||
} else {
|
||||
$this->container->get('flash')->addMessage('error', 'Invalid ticket number');
|
||||
return $response->withHeader('Location', '/support')->withStatus(302);
|
||||
}
|
||||
}
|
||||
|
||||
public function replyTicket(Request $request, Response $response)
|
||||
{
|
||||
if ($request->getMethod() === 'POST') {
|
||||
// Retrieve POST data
|
||||
$data = $request->getParsedBody();
|
||||
$db = $this->container->get('db');
|
||||
// Get the current URI
|
||||
$uri = $request->getUri()->getPath();
|
||||
$categories = $db->select("SELECT * FROM ticket_categories");
|
||||
|
||||
$ticket_id = $data['ticket_id'] ?? null;
|
||||
$responseText = $data['responseText'] ?? null;
|
||||
|
||||
if (!$responseText) {
|
||||
$this->container->get('flash')->addMessage('error', 'Please enter a reply');
|
||||
return $response->withHeader('Location', '/ticket/'.$ticket_id)->withStatus(302);
|
||||
}
|
||||
|
||||
try {
|
||||
$currentDateTime = new \DateTime();
|
||||
$crdate = $currentDateTime->format('Y-m-d H:i:s.v');
|
||||
|
||||
$db->insert(
|
||||
'ticket_responses',
|
||||
[
|
||||
'ticket_id' => $ticket_id,
|
||||
'responder_id' => $_SESSION['auth_user_id'],
|
||||
'response' => $responseText,
|
||||
'date_created' => $crdate,
|
||||
]
|
||||
);
|
||||
|
||||
$this->container->get('flash')->addMessage('success', 'Reply has been created successfully on ' . $crdate);
|
||||
return $response->withHeader('Location', '/ticket/'.$ticket_id)->withStatus(302);
|
||||
} catch (Exception $e) {
|
||||
$this->container->get('flash')->addMessage('error', 'Database error: '.$e->getMessage());
|
||||
return $response->withHeader('Location', '/ticket/'.$ticket_id)->withStatus(302);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function docs(Request $request, Response $response)
|
||||
{
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
<div class="page-body">
|
||||
<div class="container-xl">
|
||||
<div class="col-12">
|
||||
{% include 'partials/flash.twig' %}
|
||||
{% if subject is defined %}
|
||||
<div class="alert alert-important alert-success alert-dismissible" role="alert">
|
||||
<div class="d-flex">
|
||||
|
|
110
cp/resources/views/admin/support/viewTicket.twig
Normal file
110
cp/resources/views/admin/support/viewTicket.twig
Normal file
|
@ -0,0 +1,110 @@
|
|||
{% extends "layouts/app.twig" %}
|
||||
|
||||
{% block title %}{{ __('Ticket Overview') }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="page-wrapper">
|
||||
<!-- Page header -->
|
||||
<div class="page-header d-print-none">
|
||||
<div class="container-xl">
|
||||
<div class="row g-2 align-items-center">
|
||||
<div class="col">
|
||||
<!-- Page pre-title -->
|
||||
<div class="page-pretitle">
|
||||
{{ __('Overview') }}
|
||||
</div>
|
||||
<h2 class="page-title">
|
||||
{{ __('Ticket Overview') }}
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Page body -->
|
||||
<div class="page-body">
|
||||
<div class="container-xl">
|
||||
<div class="col-12">
|
||||
{% include 'partials/flash.twig' %}
|
||||
<form action="/support/reply" method="post">
|
||||
{{ csrf.field | raw }}
|
||||
<input type="hidden" name="ticket_id" value="{{ ticket.id }}">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title">Ticket #{{ ticket.id }} - {{ ticket.subject }}</h5>
|
||||
{% if ticket.status == 'Open' %}
|
||||
<span class="badge bg-success-lt">{{ ticket.status }}</span>
|
||||
{% elseif ticket.status == 'In Progress' %}
|
||||
<span class="badge bg-warning-lt">{{ ticket.status }}</span>
|
||||
{% elseif ticket.status == 'Resolved' %}
|
||||
<span class="badge bg-info-lt">{{ ticket.status }}</span>
|
||||
{% elseif ticket.status == 'Closed' %}
|
||||
<span class="badge bg-secondary-lt">{{ ticket.status }}</span>
|
||||
{% else %}
|
||||
<span class="badge bg-dark-lt">Unknown Status</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h6 class="card-subtitle mb-2 text-muted">Ticket Details</h6>
|
||||
<p><span>Created on:</span> <strong>{{ ticket.date_created }}</strong></p>
|
||||
<p><span>Category:</span> <strong>{{ category }}</strong></p>
|
||||
<p><span>Priority:</span> <strong>{{ ticket.priority }}</strong></p>
|
||||
|
||||
<div class="card mt-3">
|
||||
<div class="card-body">
|
||||
<h6 class="card-subtitle mb-2 text-muted">Conversation</h6>
|
||||
{% for reply in replies %}
|
||||
<div class="d-flex align-items-start mb-3">
|
||||
<div class="flex-shrink-0">
|
||||
<span class="avatar">{{ reply.responder_name|slice(0, 2) }}</span>
|
||||
</div>
|
||||
<div class="flex-grow-1 ms-3">
|
||||
<strong>{{ reply.responder_name }}</strong>
|
||||
<small class="text-muted">{{ reply.date_created|date("Y-m-d H:i") }}</small>
|
||||
<p>{{ reply.response }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div class="d-flex align-items-start mb-3">
|
||||
<div class="flex-shrink-0">
|
||||
<span class="avatar">{{ ticket.ticket_creator|slice(0, 2) }}</span>
|
||||
</div>
|
||||
<div class="flex-grow-1 ms-3">
|
||||
<strong>{{ ticket.ticket_creator }}</strong> <small class="text-muted">{{ ticket.date_created|date("Y-m-d H:i") }}</small>
|
||||
<p>{{ ticket.message }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<label for="responseText" class="form-label">Your Response</label>
|
||||
<textarea class="form-control" id="responseText" name="responseText" rows="3" required></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-auto">
|
||||
<button type="submit" class="btn btn-primary">Submit Response</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="footer footer-transparent d-print-none">
|
||||
<div class="container-xl">
|
||||
<div class="col-12 col-lg-auto mt-3 mt-lg-0">
|
||||
<ul class="list-inline list-inline-dots mb-0">
|
||||
<li class="list-inline-item">
|
||||
Copyright © 2023
|
||||
<a href="https://namingo.org" target="_blank" class="link-secondary">Namingo</a>.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -219,7 +219,7 @@
|
|||
</a>
|
||||
</div>
|
||||
</li>
|
||||
<li {{ is_current_url('ticketview') or is_current_url('newticket') or is_current_url('docs') or is_current_url('mediakit') ? 'class="nav-item dropdown active"' : 'class="nav-item dropdown"' }}>
|
||||
<li {{ is_current_url('ticketview') or is_current_url('newticket') or is_current_url('docs') or is_current_url('mediakit') or 'ticket' in currentUri ? 'class="nav-item dropdown active"' : 'class="nav-item dropdown"' }}>
|
||||
<a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown" data-bs-auto-close="outside" role="button" aria-expanded="false">
|
||||
<span class="nav-link-icon d-md-none d-lg-inline-block"><svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M12 12m-4 0a4 4 0 1 0 8 0a4 4 0 1 0 -8 0"></path><path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"></path><path d="M15 15l3.35 3.35"></path><path d="M9 15l-3.35 3.35"></path><path d="M5.65 5.65l3.35 3.35"></path><path d="M18.35 5.65l-3.35 3.35"></path></svg>
|
||||
</span>
|
||||
|
@ -250,110 +250,6 @@
|
|||
</div>
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
{% if route_is('dashboard') %}
|
||||
<div class="modal modal-blur fade" id="modal-report" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">New report</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Name</label>
|
||||
<input type="text" class="form-control" name="example-text-input" placeholder="Your report name">
|
||||
</div>
|
||||
<label class="form-label">Report type</label>
|
||||
<div class="form-selectgroup-boxes row mb-3">
|
||||
<div class="col-lg-6">
|
||||
<label class="form-selectgroup-item">
|
||||
<input type="radio" name="report-type" value="1" class="form-selectgroup-input" checked>
|
||||
<span class="form-selectgroup-label d-flex align-items-center p-3">
|
||||
<span class="me-3">
|
||||
<span class="form-selectgroup-check"></span>
|
||||
</span>
|
||||
<span class="form-selectgroup-label-content">
|
||||
<span class="form-selectgroup-title strong mb-1">Simple</span>
|
||||
<span class="d-block text-muted">Provide only basic data needed for the report</span>
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<label class="form-selectgroup-item">
|
||||
<input type="radio" name="report-type" value="1" class="form-selectgroup-input">
|
||||
<span class="form-selectgroup-label d-flex align-items-center p-3">
|
||||
<span class="me-3">
|
||||
<span class="form-selectgroup-check"></span>
|
||||
</span>
|
||||
<span class="form-selectgroup-label-content">
|
||||
<span class="form-selectgroup-title strong mb-1">Advanced</span>
|
||||
<span class="d-block text-muted">Insert charts and additional advanced analyses to be inserted in the report</span>
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-8">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Report url</label>
|
||||
<div class="input-group input-group-flat">
|
||||
<span class="input-group-text">
|
||||
https://tabler.io/reports/
|
||||
</span>
|
||||
<input type="text" class="form-control ps-0" value="report-01" autocomplete="off">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Visibility</label>
|
||||
<select class="form-select">
|
||||
<option value="1" selected>Private</option>
|
||||
<option value="2">Public</option>
|
||||
<option value="3">Hidden</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Client name</label>
|
||||
<input type="text" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Reporting period</label>
|
||||
<input type="date" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-12">
|
||||
<div>
|
||||
<label class="form-label">Additional information</label>
|
||||
<textarea class="form-control" rows="3"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#" class="btn btn-link link-secondary" data-bs-dismiss="modal">
|
||||
Cancel
|
||||
</a>
|
||||
<a href="#" class="btn btn-primary ms-auto" data-bs-dismiss="modal">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/plus -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><line x1="12" y1="5" x2="12" y2="19" /><line x1="5" y1="12" x2="19" y2="12" /></svg>
|
||||
Create new report
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<!-- Libs JS -->
|
||||
{% if route_is('dashboard') %}
|
||||
{% include 'partials/js-dash.twig' %}
|
||||
|
|
|
@ -96,6 +96,8 @@ $app->group('', function ($route) {
|
|||
|
||||
$route->get('/support', SupportController::class .':view')->setName('ticketview');
|
||||
$route->map(['GET', 'POST'], '/support/new', SupportController::class .':newticket')->setName('newticket');
|
||||
$route->get('/ticket/{ticket}', SupportController::class . ':viewTicket')->setName('viewTicket');
|
||||
$route->post('/support/reply', SupportController::class . ':replyTicket')->setName('replyTicket');
|
||||
$route->get('/support/docs', SupportController::class .':docs')->setName('docs');
|
||||
$route->get('/support/media', SupportController::class .':mediakit')->setName('mediakit');
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue