Blame | Last modification | View Log | RSS feed
<?php
declare(strict_types=1);
/**
* @author: Daniel Schmitzer (daniel@maennchen1.de)
* @date: 14.10.23
* @time: 07:56
*/
namespace wpsgTicket;
$oProduct = \wpsg_product::getInstance($this->view['data']['id']);
\wpsg_drawForm_AdminboxStart(__('Ticketprodukt', 'wpsg'));
$arTicketTemplate = [];
foreach (TicketTemplate::find([], null, true) as $oTicketTemplate) $arTicketTemplate[$oTicketTemplate->getId()] = $oTicketTemplate->getLabel();
?>
<script type="module">
import { product_addedit_content } from '<?php echo WPSG_URL; ?>mods/mod_ticket/assets/js/wpsg_ticket.js';
const wpsgSettings = {
baseUrl: '<?php echo WPSG_URL; ?>'
};
product_addedit_content(wpsgSettings, <?php echo $oProduct->getId(); ?>, '<?php echo \admin_url('admin-ajax.php'); ?>');
</script>
<?php echo wpsg_drawForm_Checkbox('meta[ticket_product]', __('Produkt ist ein Ticket Produkt', 'wpsg'), $oProduct->getMeta('ticket_product', false, '0')); ?>
<hr />
<div id="wpsg_ticket_product" style="display:none;">
<?php echo wpsg_drawForm_Select('meta[ticket_template]', __('Ticket Template', 'wpsg'), $arTicketTemplate, $oProduct->getMeta('ticket_template', false, '0')); ?>
<template v-if="mounted">
<br />
<div class="flex justify-between">
<div class="flex gap-2 items-center">
<a href="#" @click.prevent="addSerialevent" class="button"><?php echo __('Neuen Serientermin definieren', 'wpsg'); ?></a>
<a href="#" @click.prevent="addEvent" class="button"><?php echo __('Neuen Einzeltermin anlegen', 'wpsg'); ?></a>
<a href="<?php echo \add_query_arg([
'action' => 'wpsg_ticket',
'ticket_action' => 'export',
'ticket_product_id' => $oProduct->getId()
], \admin_url('admin-ajax.php')); ?>" target="_blank" class="button"><?php echo __('Terminübersicht exportieren', 'wpsg'); ?></a>
</div>
<a href="/wp-admin/admin.php?page=wpsg-Admin&action=module&modul=wpsg_mod_ticket"><?php echo __('Zur Modulkonfiguration', 'wpsg'); ?></a>
</div>
<br />
<div class="nav nav-tabs">
<li :class="{'active': tab === 2}"><a @click.prevent="tab = 2" href="#"><?php echo __('Serientermine', 'wpsg'); ?></a></li>
<li :class="{'active': tab === 1}"><a @click.prevent="tab = 1" href="#"><?php echo __('Termine', 'wpsg'); ?></a></li>
<li :class="{'active': tab === 3}"><a @click.prevent="tab = 3" href="#"><?php echo __('Belegungsansicht', 'wpsg'); ?></a></li>
</div>
<div class="tab-content">
<div v-if="tab === 1" class="ticket_list">
<div class="head">
<div class="tablenav">
<div class="flex justify-between items-center grow pr-4">
<label>
<input type="checkbox" v-model="data.filter.hideInactive" @change="reload" /><span><?php echo __('Nur buchbare Termine anzeigen', 'wpsg'); ?></span>
</label>
<select style="width:200px;" v-if="data_serial.items.length > 0" v-model.number="data.filter.autoticket_id" @change="load()">
<option :value="0"><?php echo __('Alle', 'wpsg'); ?></option>
<template v-for="(st, i) of data_serial.items">
<option :value="st.id">{{st.label}}</option>
</template>
</select>
</div>
<span class="tablenav-pages" v-if="data.pager.count > 0">
<span class="displaying-num">{{data.pager.count}} Tickets</span>
<span class="pagination-links">
<a href="#" @click.prevent="goPage(1)" class="tablenav-pages-navspan button" :class="{'disabled': data.pager.page <= 1}">«</a>
<a href="#" @click.prevent="goPage(data.pager.page - 1)" class="tablenav-pages-navspan button" :class="{'disabled': data.pager.page <= 1}">‹</a>
<span class="paging-input">
<span class="tablenav-paging-text">
<span class="total-pages">{{data.pager.page}}</span>
von
<span class="total-pages">{{data.pager.pages}}</span>
</span>
</span>
<a href="#" @click.prevent="goPage(data.pager.page + 1)" class="next-page button" :class="{'disabled': data.pager.page >= data.pager.pages}">›</a>
<a href="#" @click.prevent="goPage(data.pager.pages)" class="last-page button" :class="{'disabled': data.pager.page >= data.pager.pages}">»</a>
</span>
</span>
</div>
</div>
<div class="content" v-if="data.items.length > 0">
<table>
<thead>
<tr>
<th class="col_date"><?php echo __('Datum', 'wpsg'); ?></th>
<th class="col_order"><?php echo __('Bestellungen', 'wpsg'); ?></th>
<th class="col_slots"><?php echo __('Slots', 'wpsg'); ?></th>
<th class="col_state"><?php echo __('Status', 'wpsg'); ?></th>
</tr>
</thead>
<tbody v-for="(t, i) of data.items">
<tr>
<td class="col_date">{{t.label}}</td>
<td class="col_order"></td>
<td class="col_slots">
{{t.slots_used}} / {{t.slots}}
</td>
<td class="col_state">
<div class="inner">
<span v-if="t.state === 1" class="active"><?php echo __('aktiv', 'wpsg'); ?></span>
<span v-else-if="t.state === 2" class="inactive"><?php echo __('inaktiv', 'wpsg'); ?></span>
<span> / </span>
<span v-if="t.booking_state === 1" class="text-green"><?php echo __('buchbar', 'wpsg'); ?></span>
<span v-else-if="t.booking_state === 2" class="text-red">
<span v-if="t.slots_used >= t.slots_available">
<?php echo __('ausgebucht', 'wpsg'); ?>
</span>
<span v-else>
<?php echo __('ausgelaufen', 'wpsg'); ?>
</span>
</span>
</div>
</td>
</tr>
<tr>
<td class="col_action">
<div class="inner">
<a href="#" @click.prevent="changeTerminState(t)">
<span v-if="t.state === 1"><?php echo __('deaktivieren', 'wpsg'); ?></span>
<span v-else-if="t.state === 2"><?php echo __('aktivieren', 'wpsg'); ?></span>
</a>
<span> | </span>
<a href="#" @click.prevent="deleteTicket(t)"><?php echo __('löschen', 'wpsg'); ?></a>
</div>
</td>
<td class="col_order" colspan="2">
<template v-if="t.order.length > 10">
{{t.order.length}} Bestellungen
</template>
<span v-else class="flex flex-wrap gap-4">
<span v-for="(o, i2) of t.order"><a :href="o.order_link">{{o.order_nr}}</a> ({{o.amount}})</span>
</span>
</td>
<td>
<template v-if="t.autoticket_id > 0">
<a title="<?php echo __('Termine dieses Serientermins anzeigen', 'wpsg'); ?>" href="#" @click.prevent="display_autoTermin(t.autoticket_id)"><?php echo __('Serientermin'); ?> #{{t.autoticket_id}}</a>
</template>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div v-if="tab === 2" class="ticket_serial ticket_list">
<div class="head">
<div class="tablenav">
<div></div>
<span class="tablenav-pages" v-if="data_serial.pager.count > 0">
<span class="displaying-num">{{data_serial.pager.count}} Serientermine</span>
<span class="pagination-links">
<a href="#" @click.prevent="goSerialPage(1)" class="tablenav-pages-navspan button" :class="{'disabled': data_serial.pager.page <= 1}">«</a>
<a href="#" @click.prevent="goSerialPage(data_serial.pager.page - 1)" class="tablenav-pages-navspan button" :class="{'disabled': data_serial.pager.page <= 1}">‹</a>
<span class="paging-input">
<span class="tablenav-paging-text">
<span class="total-pages">{{data_serial.pager.page}}</span>
von
<span class="total-pages">{{data_serial.pager.pages}}</span>
</span>
</span>
<a href="#" @click.prevent="goSerialPage(data_serial.pager.page + 1)" class="next-page button" :class="{'disabled': data_serial.pager.page >= data_serial.pager.pages}">›</a>
<a href="#" @click.prevent="goSerialPage(data_serial.pager.pages)" class="last-page button" :class="{'disabled': data_serial.pager.page >= data_serial.pager.pages}">»</a>
</span>
</span>
</div>
</div>
<div class="content" v-if="data_serial.items.length > 0">
<table>
<thead>
<tr>
<th class="col_date"><?php echo __('Datum', 'wpsg'); ?></th>
<th class="col_tickets"><?php echo __('Termine', 'wpsg'); ?></th>
<th class="col_state"><?php echo __('Status', 'wpsg'); ?></th>
</tr>
</thead>
<tbody v-for="(t, i) of data_serial.items">
<tr>
<td class="col_date">
<a href="#" title="<?php echo __('Termine dieses Serientermins anzeigen', 'wpsg'); ?>" @click.prevent="display_autoTermin(t.id)">{{t.label}}</a>
</td>
<td class="col_tickets">{{t.count_tickets}}</td>
<td class="col_state">
<div class="inner">
<span v-if="t.state === 1" class="active"><?php echo __('aktiv', 'wpsg'); ?></span>
<span v-else-if="t.state === 2" class="inactive"><?php echo __('inaktiv', 'wpsg'); ?></span>
</div>
</td>
</tr>
<tr>
<td class="col_action">
<div class="inner">
<a href="#" @click.prevent="editTicket(t)">
<?php echo __('bearbeiten', 'wpsg'); ?>
</a>
<span> | </span>
<a href="#" @click.prevent="changeTerminState(t)">
<span v-if="t.state === 1"><?php echo __('deaktivieren', 'wpsg'); ?></span>
<span v-else-if="t.state === 2"><?php echo __('aktivieren', 'wpsg'); ?></span>
</a>
<span> | </span>
<a href="#" @click.prevent="deleteTicket(t)"><?php echo __('löschen', 'wpsg'); ?></a>
</div>
</td>
<td class="col_order" colspan="2">
<template v-if="t.order.length > 10">
{{t.order.length}} Bestellungen
</template>
<span v-else class="flex flex-wrap gap-4">
<span v-for="(o, i2) of t.order"><a :href="o.order_link">{{o.order_nr}}</a> ({{o.amount}})</span>
</span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div v-if="tab === 3" class="ticket_cal relative">
<div class="flex">
<div id="calendar" ref="ref_calendar"></div>
<div v-if="arOccupancy && day_selected" class="occupancy_view">
<template v-for="(t, i) of arOccupancy[day_selected].arTicket">
<h3>
<span><?php echo __('Ticket', 'wpsg'); ?> #{{t.id}} {{t.label}}</span>
<span>{{t.slots}} <?php echo __('Slots', 'wpsg'); ?></span>
</h3>
<ul>
<template v-for="(o, j) of t.order">
<li>
<a :href="o.order_link"><?php echo __('Bestellung', 'wpsg'); ?> {{o.order_nr}} / {{o.order_invoice_name}}</a>
<span>{{o.amount}} <?php echo __('Slots', 'wpsg'); ?></span>
</li>
</template>
</ul>
</template>
</div>
</div>
<div v-if="cal_loading" class="loading_layer">
<img src="<?php echo WPSG_URL; ?>views/gfx/ajax-loader.gif" alt="<?php echo __('Bitte warten ...', 'wpsg'); ?>" />
</div>
</div>
</div>
<div class="dialog" v-if="dialog_add">
<form class="inner" @submit.stop.prevent="dialog_submit">
<div class="head">
<span><?php echo __('Neue Termine', 'wpsg'); ?></span>
<a href="#" @click.prevent="closeDialog">X</a>
</div>
<div class="content">
<div class="form_col">
<div class="form_field">
<label>
<?php echo __('Start', 'wpsg'); ?>
</label>
<div class="flex gap-2 items-center">
<input type="date" v-model="dialog_add.from_date" required="required" />
<input type="time" v-model="dialog_add.from_time" />
</div>
</div>
<div class="form_field">
<label>
<?php echo __('Ende', 'wpsg'); ?>
</label>
<div class="flex gap-2 items-center">
<input type="date" v-model="dialog_add.to_date" />
<input type="time" v-model="dialog_add.to_time" />
</div>
</div>
<div class="form_field">
<label>
<?php echo __('Anzahl Slots', 'wpsg'); ?>
</label>
<div class="flex gap-2 items-center">
<input type="number" min="1" max="100" v-model="dialog_add.slots" />
</div>
</div>
<p style="max-width:500px; padding-top:1rem;">
<?php echo __('Ein Termin kann so oft gebucht/bestellt werden wie freie Slots verfügbar sind und er in der Zukunft liegt. Ein Termin kann über mehrere Tage gehen, dann wird der gesammte Zeitraum gebucht. Wird eine Startzeit angegeben, muss auch eine Endzeit angegeben werden', 'wpsg'); ?>
</p>
</div>
</div>
<div class="foot">
<input type="submit" class="button button-primary" value="<?php echo __('Termin anlegen', 'wpsg'); ?>" />
</div>
</form>
</div>
<div class="dialog" v-if="serial">
<form class="inner" @submit.stop.prevent="submitSerial">
<div class="head">
<span v-if="serial.id > 0"><?php echo __('Serientermin bearbeiten', 'wpsg'); ?></span>
<span v-else><?php echo __('Neuen Serientermin definieren', 'wpsg'); ?></span>
<a href="#" @click.prevent="closeSerialDialog">X</a>
</div>
<div class="content">
<div class="form_col">
<div class="form_field">
<label><?php echo __('Bezeichnung (optional)', 'wpsg'); ?></label>
<div>
<input type="text" v-model="serial.label" style="width:275px;" />
</div>
</div>
<div class="form_field">
<label><?php echo __('Kurztext (Kalender)', 'wpsg'); ?></label>
<div>
<input type="text" v-model="serial.label_short" style="width:275px;" />
</div>
</div>
<div class="form_field">
<label>
<?php echo __('Zeitraum', 'wpsg'); ?>
</label>
<div class="flex gap-2 items-center justify-between grow">
<input type="date" v-model="serial.from_date" required style="width:125px;" />
<span>-</span>
<input type="date" v-model="serial.to_date" required style="width:125px;" />
</div>
</div>
<div class="form_field">
<label>
<?php echo __('Uhrzeit (optional)', 'wpsg'); ?>
</label>
<div class="flex gap-2 items-center justify-between grow">
<input type="time" v-model="serial.event_data.from_time" style="width:125px;" />
<span>-</span>
<input type="time" v-model="serial.event_data.to_time" style="width:125px;" />
</div>
</div>
<div class="form_field">
<label>
<?php echo __('Slots', 'wpsg'); ?>
</label>
<div class="flex gap-2 items-center">
<input type="number" v-model.number="serial.event_data.slots" style="width:275px;" />
</div>
</div>
<div class="form_field">
<label>
<?php echo __('Tage im voraus planen', 'wpsg'); ?>
</label>
<div class="flex gap-2 items-center">
<select v-model.number="serial.days_future" class="w-full" style="width:275px;">
<option value="30">30</option>
<option value="60">60</option>
<option value="90">90</option>
</select>
</div>
</div>
<div class="form_field">
<label>
<?php echo __('Wochentage', 'wpsg'); ?>
</label>
<div class="weekday_wrap">
<label v-for="i in 7">
<div>
<template v-if="i === 1">Mo</template>
<template v-if="i === 2">Die</template>
<template v-if="i === 3">Mi</template>
<template v-if="i === 4">Do</template>
<template v-if="i === 5">Fr</template>
<template v-if="i === 6">Sa</template>
<template v-if="i === 7">So</template>
</div>
<div>
<input type="checkbox" @change="setWeekDay($event, i - 1)" :checked="serial.days.includes(i - 1)" />
</div>
</label>
</div>
</div>
<div v-if="serial.id > 0">
<br />
<?php echo __('Eine Bearbeitung des Serientermins wirkt sich nur auf', 'wpsg'); ?><br />
<?php echo __('zukünftige Termine dieses Serientermins aus.', 'wpsg'); ?>
</div>
</div>
</div>
<div class="foot">
<input v-if="serial.id > 0" type="submit" class="button button-primary" value="<?php echo __('Serientermin speichen', 'wpsg'); ?>" />
<input v-else type="submit" class="button button-primary" value="<?php echo __('Serientermin + Termine anlegen', 'wpsg'); ?>" />
</div>
</form>
</div>
<div v-if="loading" class="loading_layer">
<img src="<?php echo WPSG_URL; ?>views/gfx/ajax-loader.gif" alt="<?php echo __('Bitte warten ...', 'wpsg'); ?>" />
</div>
</template>
</div>
<style>
#wpsg_ticket_product .occupancy_view { padding-left:2rem; flex-grow:1;
h3 { padding:0; display:flex; justify-content:space-between; align-items:flex-start; margin:1.5rem 0 1rem 0;
* { font-size:14px; font-weight:bold; line-height:1.5rem; }
}
ul { padding-left:1.5rem; font-size:14px;
li { list-style:disc; display:flex; align-items:flex-start; justify-content:space-between; position:relative;
&:before { content:'-'; position:absolute; margin-left:-1rem; }
}
}
pre { white-space:break-spaces; }
}
#wpsg_ticket_product .flex { display:flex; }
#wpsg_ticket_product .items-center { align-items:center; }
#wpsg_ticket_product .justify-between { justify-content:space-between; }
#wpsg_ticket_product .grow { flex-grow:1; }
#wpsg_ticket_product .pr-4 { padding-right:1rem; }
#wpsg_ticket_product label { margin-bottom:0; }
#wpsg_ticket_product .dialog { position:fixed; left:0; top:0; height:100dvh; width:100dvw; background-color:rgba(0, 0, 0, 0.75); z-index:99999; display:flex; justify-content:center; align-items:center; }
#wpsg_ticket_product .dialog > .inner { background-color:white; border:1px solid black; min-width:500px; min-height:275px; display:flex; flex-direction:column; }
#wpsg_ticket_product .dialog > .inner > .head { padding:1rem 2rem; border-bottom:1px solid black; font-weight:bold; font-size:1em; display:flex; align-items:center; justify-content:space-between; }
#wpsg_ticket_product .dialog > .inner > .head a { color:black; font-weight:bold; font-size:1.5em; }
#wpsg_ticket_product .dialog > .inner > .head a:hover { text-decoration:none !important; }
#wpsg_ticket_product .dialog > .inner > .content { padding:1rem 2rem; flex-grow:1; }
#wpsg_ticket_product .dialog > .inner > .foot { padding:1rem 2rem; }
#wpsg_ticket_product .dialog > .inner .form_field { display:flex; align-items:center; justify-content:flex-start; }
#wpsg_ticket_product .dialog > .inner .form_field label { width:200px; }
#wpsg_ticket_product .dialog > .inner .form_col { display:flex; flex-direction:column; gap:0.5rem; }
#wpsg_ticket_product .ticket_list { display:flex; flex-direction:column; }
#wpsg_ticket_product .ticket_list .head .tablenav { display:flex; justify-content:space-between; align-items:center; padding-top:0;}
#wpsg_ticket_product .ticket_list .head .tablenav label { display:flex; justify-content:flex-start; align-items:center; gap:0.5rem; font-weight:normal; }
#wpsg_ticket_product .ticket_list .head .tablenav label input { margin:0; }
#wpsg_ticket_product .ticket_list .head .tablenav-pages { display:flex; align-items:center; justify-content:flex-start; margin:0; }
#wpsg_ticket_product .ticket_list .head .pagination-links { display:flex; align-items:center; justify-content:flex-start; gap:0.5rem; }
#wpsg_ticket_product .ticket_list .content { border:1px solid #c3c4c7; padding:0; }
#wpsg_ticket_product .ticket_list .content table { width:100%; }
#wpsg_ticket_product .ticket_list .content table thead tr th { border-bottom:1px solid #c3c4c7; }
#wpsg_ticket_product .ticket_list .content table > * > tr > * { padding:3px 5px 0px 5px; text-align:center; }
#wpsg_ticket_product .ticket_list .content table > * > tr > *:first-child { text-align:left; }
#wpsg_ticket_product .ticket_list .content table > * > tr > *:last-child { text-align:right; }
#wpsg_ticket_product .ticket_list .content table > * > tr > .col_action { padding-top:0; padding-bottom:3px; }
#wpsg_ticket_product .ticket_list .content table > * > tr > .col_action > .inner { display:flex; gap:0.5rem; justify-content:flex-start; align-items:center; flex-wrap:wrap; }
#wpsg_ticket_product .ticket_list .content table > * > tr > .col_date { width:250px; }
#wpsg_ticket_product .ticket_list .content table > * > tr > .col_order { text-align:left; padding-bottom:3px; }
#wpsg_ticket_product .ticket_list .content table > * > tr > .col_state .inner { display:flex; justify-content:flex-end; align-items:center; gap:0.5rem; }
#wpsg_ticket_product .ticket_list .content table > *:nth-child(even) > tr > * { background-color:#f6f7f7; }
#wpsg_ticket_product .ticket_list .content table .inactive,
#wpsg_ticket_product .text-red { color:red; }
#wpsg_ticket_product .ticket_list .content table .active,
#wpsg_ticket_product .text-green { color:green; }
#wpsg_ticket_product .flex { display:flex; }
#wpsg_ticket_product .grow { flex-grow:1; }
#wpsg_ticket_product .flex-wrap { flex-wrap:wrap; }
#wpsg_ticket_product .gap-2 { gap:0.5rem; }
#wpsg_ticket_product .gap-4 { gap:1rem; }
#wpsg_ticket_product .relative { position:relative; }
#wpsg_ticket_product { position:relative; padding:1rem 0; }
#wpsg_ticket_product .loading_layer { position:absolute; left:0; top:0; width:100%; height:100%; transition:all 0.1s; display:flex; align-items:center; justify-content:center; background-color:rgba(255, 255, 255, 0.75); }
#wpsg_ticket_product .ticket_cal { all:initial !important; font-family:'Arial' !important; }
#wpsg_ticket_product .ticket_cal * { font-family:'Arial' !important; }
#wpsg_ticket_product .ticket_cal .vanilla-calendar-week__day { font-size:12px !important; }
#wpsg_ticket_product .vanilla-calendar-month,
#wpsg_ticket_product .vanilla-calendar-year { font-size:14px !important; font-family:'Arial' !important; }
#wpsg_ticket_product .vanilla-calendar-days { column-gap:15px; }
#wpsg_ticket_product .vanilla-calendar-days { row-gap:0.5rem; }
#wpsg_ticket_product .vanilla-calendar-day__btn { font-size:1rem; }
#wpsg_ticket_product .vanilla-calendar-day__btn:not(.vanilla-calendar-day__btn_disabled) { background-color:#fde047; color:black; }
#wpsg_ticket_product .vanilla-calendar-day__btn.full { background-color:green; color:white; }
#wpsg_ticket_product .weekday_wrap { display:flex; flex-grow:1; justify-content:space-between; align-items:flex-start; }
#wpsg_ticket_product .weekday_wrap > label { display:flex; flex-direction:column; gap:0.125rem; width:initial !important; margin-bottom:0 !important; }
</style>
<script>
const el_ticket_product = document.getElementById('metaticket_product');
const el_wpsg_ticket_product = document.getElementById('wpsg_ticket_product');
const el_basket_multiple = document.getElementById('basket_multiple');
el_ticket_product.addEventListener('change', (event) => {
if (event.target.checked) {
el_basket_multiple.disabled = true;
el_basket_multiple.selectedIndex = 2;
wpsg_ticket_product.style.display = 'block';
} else {
el_basket_multiple.disabled = false;
wpsg_ticket_product.style.display = 'none';
}
});
el_ticket_product.dispatchEvent(new Event('change'));
</script>
<?php
\wpsg_drawForm_AdminboxEnd();