add success page #27
3
.ddev/commands/host/cf
Executable file
3
.ddev/commands/host/cf
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
cloudflared tunnel --url "https://127.0.0.1/$DDEV_HOST_HTTPS_PORT" --http-host-header "$DDEV_SITENAME.$DDEV_TLD"
|
@ -10,11 +10,32 @@ use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
class SuccessController extends AbstractController
|
||||
{
|
||||
#[Route(path: '/success', name: 'app_success_page', methods: Request::METHOD_GET)]
|
||||
public function __invoke(TicketService $service, Request $request): Response
|
||||
#[Route(path: '/success', name: 'app_order_success', methods: Request::METHOD_GET)]
|
||||
public function success(Request $request, TicketService $service): Response
|
||||
{
|
||||
$service->completePayment((string)$request->query->get('session_id'));
|
||||
$sessionId = $request->query->get('session_id');
|
||||
|
||||
if (!$sessionId) {
|
||||
noty()->error('Etwas ist schiefgelaufen');
|
||||
|
||||
return $this->redirectToRoute('app_ticket');
|
||||
}
|
||||
|
||||
if (!$service->completePayment($sessionId)) {
|
||||
noty()->error('Etwas ist schiefgelaufen');
|
||||
|
||||
return $this->redirectToRoute('app_ticket');
|
||||
}
|
||||
|
||||
return $this->render('ticket/success.html.twig');
|
||||
}
|
||||
|
||||
#[Route(path: '/cancelled', name: 'app_cancelled', methods: Request::METHOD_GET)]
|
||||
public function cancel(): Response
|
||||
{
|
||||
noty()->error('Bezahlung abgebrochen');
|
||||
|
||||
return $this->redirectToRoute('app_ticket');
|
||||
}
|
||||
|
||||
}
|
@ -3,8 +3,8 @@
|
||||
namespace App\Controller;
|
||||
|
||||
use App\DataObjects\TicketFormData;
|
||||
use App\Service\EventService;
|
||||
use App\Service\TicketService;
|
||||
use Stripe\Stripe;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
@ -16,6 +16,7 @@ final class TicketController extends AbstractController
|
||||
public function __construct(
|
||||
private TicketService $service,
|
||||
private SerializerInterface $serializer,
|
||||
private EventService $eventService,
|
||||
) {
|
||||
}
|
||||
|
||||
@ -33,31 +34,14 @@ final class TicketController extends AbstractController
|
||||
return $this->json(['id' => $this->service->handleTicketData($ticketData)->id]);
|
||||
}
|
||||
|
||||
#[Route(path: '/success', name: 'app_order_success', methods: Request::METHOD_GET)]
|
||||
public function success(Request $request): Response
|
||||
#[Route(path: '/calendar', name: 'app_calendar')]
|
||||
public function calendar(Request $request): Response
|
||||
{
|
||||
$sessionId = $request->query->get('session_id');
|
||||
$userAgent = $request->headers->get('User-Agent');
|
||||
$isApple = str_contains($userAgent, 'Mac') || str_contains($userAgent, 'iPhone') || str_contains($userAgent, 'iPad');
|
||||
|
||||
if (!$sessionId) {
|
||||
noty()->error('Etwas ist schiefgelaufen');
|
||||
|
||||
return $this->redirectToRoute('app_ticket');
|
||||
}
|
||||
|
||||
if (!$this->service->completePayment($sessionId)) {
|
||||
noty()->error('Etwas ist schiefgelaufen');
|
||||
|
||||
return $this->redirectToRoute('app_ticket');
|
||||
}
|
||||
|
||||
return $this->redirectToRoute('app_success_page');
|
||||
}
|
||||
|
||||
#[Route(path: '/cancelled', name: 'app_cancelled', methods: Request::METHOD_GET)]
|
||||
public function cancel(): Response
|
||||
{
|
||||
noty()->error('Bezahlung abgebrochen');
|
||||
|
||||
return $this->redirectToRoute('app_ticket');
|
||||
return $isApple
|
||||
? $this->eventService->generateIcs()
|
||||
: $this->eventService->generateGoogleRedirect();
|
||||
}
|
||||
}
|
||||
|
50
src/Service/EventService.php
Normal file
50
src/Service/EventService.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class EventService
|
||||
{
|
||||
private const EVENT_DATA = [
|
||||
'title' => 'Abiball 2025',
|
||||
'description' => 'Der Abiball der Freien Waldorfschule Bremen Osterholz und Touler Straße',
|
||||
'location' => 'Graubündener Str. 4, 28325 Bremen',
|
||||
'start' => '20250628T173000',
|
||||
'end' => '20250629T030000',
|
||||
];
|
||||
|
||||
public function generateIcs(): Response
|
||||
{
|
||||
$data = [
|
||||
'BEGIN:VCALENDAR',
|
||||
'VERSION:2.0',
|
||||
'BEGIN:VEVENT',
|
||||
'DTSTART:' . self::EVENT_DATA['start'],
|
||||
'DTEND:' . self::EVENT_DATA['end'],
|
||||
'SUMMARY:' . self::EVENT_DATA['title'],
|
||||
'DESCRIPTION:' . self::EVENT_DATA['description'],
|
||||
'LOCATION:' . self::EVENT_DATA['location'],
|
||||
'END:VEVENT',
|
||||
'END:VCALENDAR'
|
||||
];
|
||||
|
||||
return new Response(implode("\r\n", $data), headers: [
|
||||
'Content-Type' => 'text/calendar; charset=utf-8',
|
||||
'Content-Disposition' => 'attachment; filename="event.ics"'
|
||||
]);
|
||||
}
|
||||
|
||||
public function generateGoogleRedirect(): Response
|
||||
{
|
||||
return new RedirectResponse('https://calendar.google.com/calendar/render?' . http_build_query([
|
||||
'action' => 'TEMPLATE',
|
||||
'text' => self::EVENT_DATA['title'],
|
||||
'dates' => self::EVENT_DATA['start'] . '/' . self::EVENT_DATA['end'],
|
||||
'details' => self::EVENT_DATA['description'],
|
||||
'location' => self::EVENT_DATA['location'],
|
||||
]));
|
||||
}
|
||||
}
|
@ -1,15 +1,93 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}
|
||||
Success
|
||||
Danke
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h1 class="text-center">Success</h1>
|
||||
<p class="text-center">Your ticket has been successfully created.</p>
|
||||
<div class="min-h-screen bg-gradient-to-b from-white to-gray-50 relative overflow-hidden">
|
||||
<header class="w-full bg-white/90 backdrop-blur-md shadow-lg fixed top-0 z-50 border-b border-gray-100">
|
||||
<div class="container mx-auto px-4 sm:px-6 lg:px-8 py-3 sm:py-4 flex justify-between items-center">
|
||||
<a href="{{ path('app_home') }}" class="flex items-center space-x-2 group">
|
||||
<img src="{{ asset('images/logo.png') }}" alt="Logo" class="w-32 sm:w-36 md:w-40 h-auto group-hover:opacity-90 transition-opacity" />
|
||||
</a>
|
||||
<a href="{{ path('app_home') }}" class="bg-gradient-to-r from-red-500 to-orange-500 hover:from-red-600 hover:to-orange-600 text-white px-6 py-2.5 rounded-full text-sm font-medium shadow-md hover:shadow-lg transition-all duration-300 flex items-center space-x-2">
|
||||
<twig:ux:icon name="line-md:home" class="w-4 h-4" />
|
||||
<span>Zurück zur Startseite</span>
|
||||
</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="container mx-auto px-4 sm:px-6 lg:px-8 pt-24 sm:pt-28 md:pt-32 pb-16 sm:pb-20 flex flex-col items-center justify-center relative z-10">
|
||||
<div class="w-full max-w-3xl mx-auto text-center">
|
||||
<div class="mb-8">
|
||||
<div class="inline-flex items-center justify-center w-16 h-16 rounded-full bg-green-100 mb-6">
|
||||
<twig:ux:icon name="heroicons:check-circle" class="w-10 h-10 text-green-500" />
|
||||
</div>
|
||||
<h1 class="text-3xl sm:text-4xl font-bold text-gray-900 mb-4">Vielen Dank für deine Bestellung!</h1>
|
||||
<p class="text-lg text-gray-600">Wir freuen uns, dich beim Abiball zu sehen.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-5">
|
||||
<div class="bg-white rounded-2xl shadow-lg p-8 border border-gray-100 col-1">
|
||||
<h2 class="text-2xl font-semibold mb-6 w-full bg-clip-text text-transparent bg-gradient-to-r from-red-500 to-orange-500">Veranstaltungsdetails</h2>
|
||||
<div class="max-w-xs mx-auto">
|
||||
<div class="space-y-4">
|
||||
<div class="flex justify-start space-x-3">
|
||||
<twig:ux:icon name="heroicons:calendar" class="w-6 h-6 text-gray-400" />
|
||||
<p class="text-gray-700">Sa. 28.06.2025</p>
|
||||
</div>
|
||||
<div class="flex justify-start space-x-3">
|
||||
<twig:ux:icon name="heroicons:clock" class="w-6 h-6 text-gray-400" />
|
||||
<p class="text-gray-700">17:30 - Open End</p>
|
||||
</div>
|
||||
<div class="flex justify-start space-x-3">
|
||||
<twig:ux:icon name="heroicons:map-pin" class="w-6 h-6 text-gray-400" />
|
||||
<p class="text-gray-700">Graubündener Str. 4, 28325 Bremen</p>
|
||||
</div>
|
||||
<div class="flex justify-start space-x-3">
|
||||
<twig:ux:icon name="tabler:shirt" class="w-6 h-6 text-gray-400" />
|
||||
<p class="text-gray-700">Abendkleidung</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-2xl shadow-lg p-8 border border-gray-100 col-2">
|
||||
<h2 class="text-2xl font-semibold mb-6 w-full bg-clip-text text-transparent bg-gradient-to-r from-red-500 to-orange-500">Ablauf</h2>
|
||||
<div class="max-w-xs mx-auto">
|
||||
<div class="space-y-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<twig:ux:icon name="heroicons:ticket" class="w-6 h-6 text-gray-400 flex-shrink-0" />
|
||||
<span class="text-gray-600 font-medium whitespace-nowrap">17:30-19:30</span>
|
||||
<span class="text-gray-700">Einlass & Platznehmen</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<twig:ux:icon name="heroicons:cake" class="w-6 h-6 text-gray-400 flex-shrink-0" />
|
||||
<span class="text-gray-600 font-medium whitespace-nowrap">19:30-22:00</span>
|
||||
<span class="text-gray-700">Dinner & Beisammensein</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<twig:ux:icon name="heroicons:musical-note" class="w-6 h-6 text-gray-400 flex-shrink-0" />
|
||||
<span class="text-gray-600 font-medium whitespace-nowrap">ab 22:00</span>
|
||||
<span class="text-gray-700">Feier & Tanz im Saal</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-8 pt-6 border-t border-gray-200 text-center">
|
||||
<div class="flex items-center justify-center">
|
||||
<a href="{{ path('app_calendar') }}"
|
||||
target="_blank"
|
||||
class="inline-flex items-center px-6 py-3 bg-gray-200 hover:bg-gray-300 rounded transition-colors">
|
||||
<twig:ux:icon name="heroicons:calendar" class="w-5 h-5 text-gray-600 mr-2" />
|
||||
<span class="text-sm font-medium text-gray-700">Zum Kalender hinzufügen</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user