8 private function db() {
9 return dbx()->get_system_obj(
'dbxDB');
12 private function tpl() {
13 return dbx()->get_system_obj(
'dbxTPL');
16 private function h($value):
string {
17 return htmlspecialchars((
string) $value, ENT_QUOTES,
'UTF-8');
20 private function denied():
string {
21 return $this->tpl()->get_tpl(
'dbx|alert-warning', array(
22 'msg' =>
'Bitte melden Sie sich an, um Ihre Kontaktanfragen zu sehen.',
26 private function statusClass(
string $status):
string {
28 'open' =>
'text-bg-primary',
29 'in_progress' =>
'text-bg-info',
30 'waiting_customer' =>
'text-bg-warning',
31 'answered' =>
'text-bg-success',
32 'closed' =>
'text-bg-secondary',
33 )[$status] ??
'text-bg-light';
36 private function ticketForUser(
int $rid,
int $uid): array {
44 private function excerpt($value,
int $max = 120):
string {
45 $value = trim((
string) preg_replace(
'/\s+/',
' ', (
string) $value));
46 if (strlen($value) > $max) {
47 $value = substr($value, 0, $max - 3) .
'...';
49 return $this->h($value);
52 private function decorateRows(array $rows): array {
54 foreach ($rows as $row) {
56 $row[
'status_view'] =
'<span class="badge ' . $this->statusClass($status) .
'">' . $this->h(
dbxContactTicket::statusLabel($status)) .
'</span>';
57 $row[
'subject_view'] = $this->excerpt($row[
'subject'] ??
'', 90);
58 $row[
'action'] = $this->tpl()->get_tpl(
'dbxContact|contact-ticket-row-action', array(
59 'rid' => (
int) ($row[
'id'] ?? 0),
67 if (!is_array($data) || (string) ($data[
'type'] ??
'') !==
'delete') {
71 $rid = (int) ($data[
'record'][
'id'] ?? $data[
'data'][
'rid'] ?? 0);
72 $data[
'data'][
'action'] =
'?dbx_modul=dbxContact&dbx_run1=my&dbx_run2=delete&rid=' . $rid;
73 $data[
'data'][
'tooltip'] =
'Anfrage entfernen';
78 private function listTickets(
int $uid): string {
80 $report =
dbx()->get_system_obj(
'dbxReport');
81 $where =
'uid = ' . $uid .
' AND user_hidden = 0';
83 $report->init(
'contact-list',
'dbxContact|contact-list');
84 $report->add_rep(
'bar_title',
'Meine Anfragen');
85 $report->add_rep(
'bar_icon',
'bi-life-preserver');
86 $report->add_rep(
'bar_subtitle',
'Status, Antworten und Verlauf Ihrer Tickets');
87 $report->add_rep(
'bar_actions',
88 '<a class="btn btn-primary btn-sm" href="?dbx_modul=dbxContact&dbx_run1=form"><i class="bi bi-plus-circle"></i> Neue Anfrage</a>'
91 $report->_action =
'?dbx_modul=dbxContact&dbx_run1=my';
92 $report->_pages =
true;
93 $report->_create_row_select =
false;
94 $report->_create_row_edit =
false;
95 $report->_create_row_delete =
true;
96 $report->_table_buttons =
'left';
97 $report->_msg_confirm_delete =
'Anfrage entfernen?';
98 $report->set_callback_owner($this);
99 $report->set_callback(
'row_action_data',
'contactListReportRowActionData');
100 $report->set_tabel_tpl(
'tpl_row_delete',
'modul|contact-ticket-row-delete');
101 $report->_rflds = array(
103 'last_activity_date' =>
'Letzte Aktivitaet',
104 'status_view' =>
'Status',
105 'subject_view' =>
'Betreff',
106 'action' =>
' ',
108 $report->_rpt_format = array(
109 'last_activity_date' =>
'php-datetime-usr',
110 'status_view' =>
'html',
111 'subject_view' =>
'html',
114 $report->_rrows = 30;
117 $report->_rcount = $report->_count_all;
121 array(
'id',
'last_activity_date',
'create_date',
'status',
'subject'),
122 'last_activity_date,id',
129 $report->_rdata = $this->decorateRows(is_array($rows) ? $rows : array());
131 return $report->run();
134 private function timeline(array $ticket): string {
136 dbxContactTicket::ensureInitialMessage(
$db, $ticket);
139 foreach (dbxContactTicket::messages(
$db, (
int) $ticket[
'id'],
false) as $message) {
140 $authorType = (string) ($message[
'author_type'] ??
'system');
141 $statusTo = trim((
string) ($message[
'status_to'] ??
''));
142 $html .= $this->tpl()->get_tpl(
'dbxContact|contact-ticket-message', array(
143 'message_class' => $authorType ===
'admin' ?
'border-primary bg-primary-subtle' :
'bg-body-tertiary',
144 'message_icon' => $authorType ===
'admin' ?
'bi-headset' : ($authorType ===
'requester' ?
'bi-person' :
'bi-gear'),
145 'author_label' => $authorType ===
'admin' ?
'Support' : ($authorType ===
'requester' ?
'Sie' :
'System'),
146 'create_date' => $this->h($message[
'create_date'] ??
''),
147 'body' => nl2br($this->h($message[
'body'] ??
'')),
148 'status_badge' => $statusTo !==
''
149 ?
'<span class="badge ' . $this->statusClass($statusTo) .
'">Status: ' . $this->h(dbxContactTicket::statusLabel($statusTo)) .
'</span>'
154 return $html !==
'' ? $html :
'<div class="text-muted">Noch kein Verlauf vorhanden.</div>';
157 private function messageForm(array $ticket): string {
158 $rid = (int) $ticket[
'id'];
159 if ((
string) ($ticket[
'status'] ??
'') ===
'closed') {
160 return '<div class="alert alert-secondary mb-0">Dieses Ticket ist geschlossen. Fuer ein neues Anliegen legen Sie bitte eine neue Anfrage an.</div>';
163 $form =
dbx()->get_system_obj(
'dbxForm');
164 $form->init(
'contact-user-message',
'contact-user-message-form');
165 $form->_dd = dbxContactTicket::DD_MESSAGE;
166 $form->_fd =
'dbxContact|contact-user-message';
167 $form->_action =
'?dbx_modul=dbxContact&dbx_run1=my&dbx_run2=ticket&rid=' . $rid;
168 $form->_data = array(
'body' =>
'');
169 $form->add_module_bar(
'Nachricht hinzufuegen',
'bi-chat-dots',
'Ihre Nachricht wird dem Support angezeigt');
170 $form->add_rep(
'bar_title_pre',
'');
171 $form->add_rep(
'bar_title_heading_attrs',
'');
172 $form->add_rep(
'bar_middle',
'');
173 $form->add_rep(
'bar_actions',
'');
174 $form->add_rep(
'bar_extra',
'');
175 $form->add_rep(
'rid', $rid);
176 $form->_msg_info =
'Ergaenzen Sie Informationen oder beantworten Sie eine Rueckfrage des Supports.';
177 $form->add_fld(
'body');
179 if ($form->submit() && !$form->errors()) {
180 $body = trim((
string) $form->get_post_data(
'body',
'',
'*'));
181 $oldStatus = dbxContactTicket::normalizeStatus((
string) ($ticket[
'status'] ??
'open'));
182 $messageId = dbxContactTicket::addMessage($this->db(), $rid, array(
183 'author_uid' => (
int)
dbx()->user(),
184 'author_type' =>
'requester',
185 'message_type' =>
'message',
186 'visibility' =>
'public',
188 'status_from' => $oldStatus,
189 'status_to' =>
'open',
191 if ($messageId > 0) {
192 dbxContactTicket::touch($this->db(), $rid, array(
'status' =>
'open',
'closed_date' =>
''));
193 $form->_msg_success =
'Ihre Nachricht wurde dem Ticket hinzugefuegt.';
194 $form->_data[
'body'] =
'';
196 $form->_msg_error =
'Die Nachricht konnte nicht gespeichert werden.';
203 private function ticket(
int $uid): string {
204 $rid = (int)
dbx()->get_modul_var(
'rid', 0,
'int');
205 $ticket = $this->ticketForUser($rid, $uid);
207 return $this->tpl()->get_tpl(
'dbx|alert-warning', array(
'msg' =>
'Anfrage nicht gefunden.'));
210 $messageForm = $this->messageForm($ticket);
211 $ticket = $this->ticketForUser($rid, $uid);
212 $status = dbxContactTicket::normalizeStatus((
string) ($ticket[
'status'] ??
'open'));
214 return $this->tpl()->get_tpl(
'dbxContact|contact-ticket-detail', array(
215 'bar_class' =>
'dbx-module-bar',
216 'bar_title_class' =>
'dbx-module-bar-titleblock',
217 'bar_actions_class' =>
'dbx-module-bar-actions',
218 'bar_title_pre' =>
'',
219 'bar_title_heading_attrs' =>
'',
220 'bar_icon' =>
'bi-life-preserver',
221 'bar_title' =>
'Ticket #' . $rid,
222 'bar_subtitle' =>
'Kontaktanfrage und Verlauf',
224 'bar_actions' =>
'<a class="btn btn-outline-secondary btn-sm" href="?dbx_modul=dbxContact&dbx_run1=my"><i class="bi bi-arrow-left"></i> Meine Anfragen</a>',
227 'subject' => $this->h($ticket[
'subject'] ??
''),
228 'status_label' => $this->h(dbxContactTicket::statusLabel($status)),
229 'status_class' => $this->statusClass($status),
230 'create_date' => $this->h($ticket[
'create_date'] ??
''),
231 'timeline' => $this->timeline($ticket),
232 'message_form' => $messageForm,
236 private function deleteTicket(
int $uid): string {
237 $rid = (int)
dbx()->get_modul_var(
'rid', 0,
'int');
238 $ticket = $this->ticketForUser($rid, $uid);
240 return $this->tpl()->get_tpl(
'dbx|alert-warning', array(
'msg' =>
'Anfrage nicht gefunden.'));
243 $form =
dbx()->get_system_obj(
'dbxForm');
244 $form->init(
'contact-user-delete',
'contact-user-delete-form');
245 $form->_fd =
'dbxContact|contact-user-delete';
246 $form->_action =
'?dbx_modul=dbxContact&dbx_run1=my&dbx_run2=delete&rid=' . $rid;
247 $form->_data = array(
'confirm_delete' => 0);
248 $form->add_module_bar(
'Anfrage ausblenden',
'bi-trash');
249 $form->add_rep(
'bar_title_pre',
'');
250 $form->add_rep(
'bar_title_heading_attrs',
'');
251 $form->add_rep(
'bar_middle',
'');
252 $form->add_rep(
'bar_actions',
'');
253 $form->add_rep(
'bar_extra',
'');
254 $form->add_rep(
'rid', $rid);
255 $form->_msg_info =
'';
256 $form->add_fld(
'confirm_delete');
258 if ($form->submit() && !$form->errors()) {
259 $ok = $this->db()->update(dbxContactTicket::DD_TICKET, array(
261 'user_hidden_date' => date(
'Y-m-d H:i:s'),
262 ),
'id = ' . $rid .
' AND uid = ' . $uid, 0, 1, 1, 1);
264 return $this->tpl()->get_tpl(
'dbx|alert-success', array(
265 'msg' =>
'Die Anfrage wurde aus Ihrer Ansicht entfernt. Der Supportverlauf bleibt erhalten.',
266 )) .
'<div class="p-3"><a class="btn btn-primary" href="?dbx_modul=dbxContact&dbx_run1=my">Zu meinen Anfragen</a></div>';
268 $form->_msg_error =
'Die Anfrage konnte nicht ausgeblendet werden.';
275 $uid = (int)
dbx()->user();
277 return $this->denied();
280 $run2 =
dbx()->get_modul_var(
'dbx_run2',
'list',
'parameter');
281 if ($run2 ===
'ticket') {
282 return $this->ticket($uid);
284 if ($run2 ===
'delete') {
285 return $this->deleteTicket($uid);
287 return $this->listTickets($uid);