feat: display included services in dates view
addresses #869c93zxj
This commit is contained in:
@@ -176,6 +176,7 @@ class AjaxTableController extends ActionController
|
|||||||
$bookableDates = array_filter($allDates, function (array $date) {
|
$bookableDates = array_filter($allDates, function (array $date) {
|
||||||
return $date['available'] > 0;
|
return $date['available'] > 0;
|
||||||
});
|
});
|
||||||
|
$includedServices = $this->dateService->groupIncludedServices($bookableDates);
|
||||||
|
|
||||||
$altProductLink = null;
|
$altProductLink = null;
|
||||||
$altLabel = null;
|
$altLabel = null;
|
||||||
@@ -205,6 +206,8 @@ class AjaxTableController extends ActionController
|
|||||||
$this->view->assignMultiple([
|
$this->view->assignMultiple([
|
||||||
'allDates' => $allDates,
|
'allDates' => $allDates,
|
||||||
'bookableDates' => $bookableDates,
|
'bookableDates' => $bookableDates,
|
||||||
|
'includedServicesAllDates' => $includedServices['allDates'],
|
||||||
|
'includedServicesSomeDates' => $includedServices['someDates'],
|
||||||
'bookable' => $product->getBookable(),
|
'bookable' => $product->getBookable(),
|
||||||
'unavailable' => 0 === count($allDates),
|
'unavailable' => 0 === count($allDates),
|
||||||
'product' => $product,
|
'product' => $product,
|
||||||
|
|||||||
@@ -442,6 +442,70 @@ class DateService implements SingletonInterface
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Group included services across bookable dates.
|
||||||
|
*
|
||||||
|
* Returns services that appear in every supplied date and services that
|
||||||
|
* appear in at least one supplied date but not all of them.
|
||||||
|
*
|
||||||
|
* @param array $dates
|
||||||
|
* @return array{allDates: array, someDates: array}
|
||||||
|
*/
|
||||||
|
public function groupIncludedServices(array $dates): array
|
||||||
|
{
|
||||||
|
$serviceCounts = [];
|
||||||
|
$serviceOrder = [];
|
||||||
|
$dateCount = count($dates);
|
||||||
|
|
||||||
|
foreach ($dates as $date) {
|
||||||
|
$dateServices = $date['servicesIncluded'] ?? [];
|
||||||
|
if (!is_array($dateServices)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$seenInDate = [];
|
||||||
|
foreach ($dateServices as $service) {
|
||||||
|
if (!is_string($service) || '' === trim($service)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($seenInDate[$service])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$seenInDate[$service] = true;
|
||||||
|
|
||||||
|
if (!array_key_exists($service, $serviceCounts)) {
|
||||||
|
$serviceCounts[$service] = 0;
|
||||||
|
$serviceOrder[] = $service;
|
||||||
|
}
|
||||||
|
|
||||||
|
$serviceCounts[$service]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$groupedServices = [
|
||||||
|
'allDates' => [],
|
||||||
|
'someDates' => [],
|
||||||
|
];
|
||||||
|
|
||||||
|
if (0 === $dateCount) {
|
||||||
|
return $groupedServices;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($serviceOrder as $service) {
|
||||||
|
$count = $serviceCounts[$service] ?? 0;
|
||||||
|
if ($dateCount === $count) {
|
||||||
|
$groupedServices['allDates'][] = $service;
|
||||||
|
} elseif ($count > 0) {
|
||||||
|
$groupedServices['someDates'][] = $service;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort($groupedServices['someDates'], SORT_NATURAL | SORT_FLAG_CASE);
|
||||||
|
|
||||||
|
return $groupedServices;
|
||||||
|
}
|
||||||
|
|
||||||
public function checkSurcharcheOrDiscount(array $tableData): array
|
public function checkSurcharcheOrDiscount(array $tableData): array
|
||||||
{
|
{
|
||||||
$data = [
|
$data = [
|
||||||
|
|||||||
+79
-38
@@ -176,69 +176,110 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<ul class="divide-y divide-zinc-200">
|
<ul class="divide-y divide-zinc-200 mb-4">
|
||||||
<f:if condition="{hasSurcharge}">
|
<f:if condition="{hasSurcharge}">
|
||||||
<li class="py-2">
|
<li class="py-2">
|
||||||
<button type="button"
|
<button type="button"
|
||||||
data-action="pricetable#toggleSurcharge"
|
data-action="pricetable#toggleSurcharge"
|
||||||
class="flex items-center space-x-1 focus:outline-none text-ep-primary-dark ser:text-ser-primary-dark">
|
class="flex items-center space-x-1 focus:outline-none text-ep-primary-dark ser:text-ser-primary-dark">
|
||||||
<svg class="w-6 h-6">
|
<svg class="w-6 h-6">
|
||||||
<use href="{f:uri.image(src: 'EXT:ep_theme/Resources/Public/images/icons_sprite.svg')}#icon-arrow-circle-right"></use>
|
<use href="{f:uri.image(src: 'EXT:ep_theme/Resources/Public/images/icons_sprite.svg')}#icon-arrow-circle-right"></use>
|
||||||
</svg>
|
</svg>
|
||||||
<span data-pricetable-target="surchargeToggleLabel"
|
<span data-pricetable-target="surchargeToggleLabel"
|
||||||
data-label-default="Preise für Eigenanreise anzeigen"
|
data-label-default="Preise für Eigenanreise anzeigen"
|
||||||
data-label-alt="Preise für Busanreise anzeigen">
|
data-label-alt="Preise für Busanreise anzeigen">
|
||||||
Preise für Eigenanreise anzeigen
|
Preise für Eigenanreise anzeigen
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</f:if>
|
</f:if>
|
||||||
<f:if condition="{hasDiscount}">
|
<f:if condition="{hasDiscount}">
|
||||||
<li class="py-2">
|
<li class="py-2">
|
||||||
<button type="button"
|
<button type="button"
|
||||||
data-action="pricetable#toggleDiscount"
|
data-action="pricetable#toggleDiscount"
|
||||||
class="flex items-center space-x-1 focus:outline-none text-ep-primary-dark ser:text-ser-primary-dark">
|
class="flex items-center space-x-1 focus:outline-none text-ep-primary-dark ser:text-ser-primary-dark">
|
||||||
<svg class="w-6 h-6">
|
<svg class="w-6 h-6">
|
||||||
<use href="{f:uri.image(src: 'EXT:ep_theme/Resources/Public/images/icons_sprite.svg')}#icon-arrow-circle-right"></use>
|
<use href="{f:uri.image(src: 'EXT:ep_theme/Resources/Public/images/icons_sprite.svg')}#icon-arrow-circle-right"></use>
|
||||||
</svg>
|
</svg>
|
||||||
<span data-pricetable-target="discountToggleLabel"
|
<span data-pricetable-target="discountToggleLabel"
|
||||||
data-label-default="Preise für Busanreise anzeigen"
|
data-label-default="Preise für Busanreise anzeigen"
|
||||||
data-label-alt="Preise für Eigenanreise anzeigen">
|
data-label-alt="Preise für Eigenanreise anzeigen">
|
||||||
Preise für Busanreise anzeigen
|
Preise für Busanreise anzeigen
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</f:if>
|
</f:if>
|
||||||
<f:if condition="{bookableDates -> f:count()} > 5">
|
<f:if condition="{bookableDates -> f:count()} > 5">
|
||||||
<li class="py-2">
|
<li class="py-2">
|
||||||
<button type="button"
|
<button type="button"
|
||||||
class="flex items-center space-x-1 focus:outline-none text-ep-primary-dark ser:text-ser-primary-dark"
|
class="flex items-center space-x-1 focus:outline-none text-ep-primary-dark ser:text-ser-primary-dark"
|
||||||
data-action="pricetable#toggleRows">
|
data-action="pricetable#toggleRows">
|
||||||
<svg class="w-6 h-6">
|
<svg class="w-6 h-6">
|
||||||
<use href="{f:uri.image(src: 'EXT:ep_theme/Resources/Public/images/icons_sprite.svg')}#icon-plus-circle"
|
<use href="{f:uri.image(src: 'EXT:ep_theme/Resources/Public/images/icons_sprite.svg')}#icon-plus-circle"
|
||||||
data-pricetable-target="rowToggleIcon"></use>
|
data-pricetable-target="rowToggleIcon"></use>
|
||||||
</svg>
|
</svg>
|
||||||
<span data-pricetable-target="rowToggleLabel">
|
<span data-pricetable-target="rowToggleLabel">
|
||||||
Alle Termine anzeigen
|
Alle Termine anzeigen
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</f:if>
|
</f:if>
|
||||||
<f:if condition="{altProductLink}">
|
<f:if condition="{altProductLink}">
|
||||||
<li class="py-2">
|
<li class="py-2">
|
||||||
<a href="{altProductLink}"
|
<a href="{altProductLink}"
|
||||||
title="{altLabel}"
|
title="{altLabel}"
|
||||||
class="flex items-center space-x-1 focus:outline-none text-ep-primary-dark ser:text-ser-primary-dark">
|
class="flex items-center space-x-1 focus:outline-none text-ep-primary-dark ser:text-ser-primary-dark">
|
||||||
<svg class="w-6 h-6">
|
<svg class="w-6 h-6">
|
||||||
<use href="{f:uri.image(src: 'EXT:ep_theme/Resources/Public/images/icons_sprite.svg')}#icon-arrow-circle-right"></use>
|
<use href="{f:uri.image(src: 'EXT:ep_theme/Resources/Public/images/icons_sprite.svg')}#icon-arrow-circle-right"></use>
|
||||||
</svg>
|
</svg>
|
||||||
<span>
|
<span>
|
||||||
{altLabel}
|
{altLabel}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</f:if>
|
</f:if>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<f:if condition="{includedServicesAllDates}">
|
||||||
|
<div class="headline--3 headline--underlined">
|
||||||
|
Inklusivleistungen
|
||||||
|
</div>
|
||||||
|
<div class="bg-zinc-50 p-4 mb-8">
|
||||||
|
<ul class="grid gap-2 sm:grid-cols-2">
|
||||||
|
<f:for each="{includedServicesAllDates}" as="service">
|
||||||
|
<li class="flex items-start space-x-2">
|
||||||
|
<svg class="w-5 h-5 mt-0.5 flex-none text-ep-primary-dark ser:text-ser-primary-dark">
|
||||||
|
<use href="{f:uri.image(src: 'EXT:ep_theme/Resources/Public/images/icons_sprite.svg')}#icon-check"></use>
|
||||||
|
</svg>
|
||||||
|
<span class="text-sm md:text-base">
|
||||||
|
{service}
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</f:for>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</f:if>
|
||||||
|
|
||||||
|
<f:if condition="{includedServicesSomeDates}">
|
||||||
|
<div class="headline--3 headline--underlined">
|
||||||
|
Teilweise inklusive
|
||||||
|
</div>
|
||||||
|
<div class="bg-zinc-50 p-4 mb-8">
|
||||||
|
<ul class="grid gap-2 sm:grid-cols-2">
|
||||||
|
<f:for each="{includedServicesSomeDates}" as="service">
|
||||||
|
<li class="flex items-start space-x-2">
|
||||||
|
<svg class="w-5 h-5 mt-0.5 flex-none text-ep-primary-dark ser:text-ser-primary-dark">
|
||||||
|
<use href="{f:uri.image(src: 'EXT:ep_theme/Resources/Public/images/icons_sprite.svg')}#icon-check"></use>
|
||||||
|
</svg>
|
||||||
|
<span class="text-sm md:text-base">
|
||||||
|
{service}
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</f:for>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</f:if>
|
||||||
|
|
||||||
</f:if>
|
</f:if>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user