stuff #37

Merged
csimonis merged 4 commits from stuff into main 2025-02-28 11:53:10 +00:00
9 changed files with 82 additions and 22 deletions

View File

@ -12,6 +12,7 @@ export default class extends Controller {
"ticketType", "ticketType",
"foodType", "foodType",
"note", "note",
"donation"
]; ];
stripe; stripe;
@ -191,6 +192,7 @@ export default class extends Controller {
lastname: this.lastnameTarget.value.trim(), lastname: this.lastnameTarget.value.trim(),
email: this.emailTarget.value.trim(), email: this.emailTarget.value.trim(),
phone: this.phoneTarget.value.trim(), phone: this.phoneTarget.value.trim(),
donation: Number(this.donationTarget.value) ?? null
}; };
} }

View File

@ -4,19 +4,16 @@ namespace App\Controller\Admin;
use App\Entity\Customer; use App\Entity\Customer;
use App\Entity\Payment; use App\Entity\Payment;
use App\Enum\TicketData; use App\Form\TicketType;
use Doctrine\Common\Collections\Collection;
use EasyCorp\Bundle\EasyAdminBundle\Config\Action; use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions; use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud; use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController; use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField; use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
use EasyCorp\Bundle\EasyAdminBundle\Field\ChoiceField;
use EasyCorp\Bundle\EasyAdminBundle\Field\CollectionField; use EasyCorp\Bundle\EasyAdminBundle\Field\CollectionField;
use EasyCorp\Bundle\EasyAdminBundle\Field\EmailField; use EasyCorp\Bundle\EasyAdminBundle\Field\EmailField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TelephoneField; use EasyCorp\Bundle\EasyAdminBundle\Field\TelephoneField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField; use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use App\Form\TicketType;
class CustomerCrudController extends AbstractCrudController class CustomerCrudController extends AbstractCrudController
{ {

View File

@ -9,6 +9,7 @@ use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController; use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField; use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
use EasyCorp\Bundle\EasyAdminBundle\Field\BooleanField; use EasyCorp\Bundle\EasyAdminBundle\Field\BooleanField;
use EasyCorp\Bundle\EasyAdminBundle\Field\NumberField;
class PaymentCrudController extends AbstractCrudController class PaymentCrudController extends AbstractCrudController
{ {
@ -23,6 +24,8 @@ class PaymentCrudController extends AbstractCrudController
->setCrudController(CustomerCrudController::class) ->setCrudController(CustomerCrudController::class)
->formatValue(fn($value, $payment) => $payment->getCustomer()->getEmail()); ->formatValue(fn($value, $payment) => $payment->getCustomer()->getEmail());
yield BooleanField::new('completed', 'Bezahlt')->renderAsSwitch(false); yield BooleanField::new('completed', 'Bezahlt')->renderAsSwitch(false);
yield NumberField::new('donation', 'Spende')
->formatValue(fn (?float $donation) => ($donation??'0').'€');
} }
public function configureActions(Actions $actions): Actions public function configureActions(Actions $actions): Actions

View File

@ -9,6 +9,7 @@ class PersonalData
public string $lastname, public string $lastname,
public string $email, public string $email,
public string $phone, public string $phone,
public ?float $donation,
) { ) {
} }
} }

View File

@ -24,6 +24,9 @@ class Payment
#[ORM\JoinColumn(nullable: false)] #[ORM\JoinColumn(nullable: false)]
private ?Customer $customer = null; private ?Customer $customer = null;
#[ORM\Column(nullable: true)]
private ?float $donation = null;
public function getId(): ?int public function getId(): ?int
{ {
return $this->id; return $this->id;
@ -71,4 +74,16 @@ class Payment
return $total + TicketData::TICKET_DATA[$ticket->getType()]['price']; return $total + TicketData::TICKET_DATA[$ticket->getType()]['price'];
}, 0); }, 0);
} }
public function getDonation(): ?float
{
return $this->donation;
}
public function setDonation(?float $donation): static
{
$this->donation = $donation;
return $this;
}
} }

View File

@ -30,7 +30,7 @@ class TicketService
public function handleTicketData(TicketFormData $data): Session public function handleTicketData(TicketFormData $data): Session
{ {
$session = $this->createSession($this->getLineItems($data->tickets), $data->personal->email); $session = $this->createSession($this->getLineItems($data->tickets, $data->personal->donation), $data->personal->email);
$this->saveTicketData($data, $session->id); $this->saveTicketData($data, $session->id);
@ -57,16 +57,30 @@ class TicketService
$payment = (new Payment()) $payment = (new Payment())
->setSessionId($sessionId) ->setSessionId($sessionId)
->setCompleted(false) ->setCompleted(false)
->setCustomer($this->createEntityFromData($data)); ->setCustomer($this->createEntityFromData($data))
->setDonation($data->personal->donation);
$this->em->persist($payment); $this->em->persist($payment);
$this->em->flush(); $this->em->flush();
} }
private function getLineItems(array $tickets): array private function getLineItems(array $tickets, float $donation = null): array
{ {
$lineItems = []; $lineItems = [];
if ($donation) {
$lineItems[] = [
'price_data' => [
'currency' => 'eur',
'product_data' => [
'name' => 'Spende',
],
'unit_amount' => $donation * 100,
],
'quantity' => 1,
];
}
foreach ($tickets as $ticket) { foreach ($tickets as $ticket) {
$ticketData = TicketEnum::TICKET_DATA[$ticket->ticketType]; $ticketData = TicketEnum::TICKET_DATA[$ticket->ticketType];
$lineItems[] = [ $lineItems[] = [

View File

@ -12,16 +12,7 @@
<tr> <tr>
<td> <td>
<font color="#1f2937" size="5" face="Arial, Helvetica, sans-serif">Contact Details</font> <font color="#1f2937" size="5" face="Arial, Helvetica, sans-serif">Contact Details</font>
{% if data.phone %}
<table cellpadding="15" cellspacing="0" border="1" width="100%" bgcolor="#f9fafb" bordercolor="#e5e7eb" style="border-collapse: collapse; margin-top: 20px;">
<tr>
<td>
<font color="#6b7280" size="2" face="Arial, Helvetica, sans-serif">Email</font><br>
<font color="#1f2937" size="3" face="Arial, Helvetica, sans-serif">{{ data.email }}</font>
</td>
</tr>
</table>
<table cellpadding="15" cellspacing="0" border="1" width="100%" bgcolor="#f9fafb" bordercolor="#e5e7eb" style="border-collapse: collapse; margin-top: 20px;"> <table cellpadding="15" cellspacing="0" border="1" width="100%" bgcolor="#f9fafb" bordercolor="#e5e7eb" style="border-collapse: collapse; margin-top: 20px;">
<tr> <tr>
<td> <td>
@ -30,7 +21,7 @@
</td> </td>
</tr> </tr>
</table> </table>
{% endif %}
<table cellpadding="15" cellspacing="0" border="1" width="100%" bgcolor="#f9fafb" bordercolor="#e5e7eb" style="border-collapse: collapse; margin-top: 20px;"> <table cellpadding="15" cellspacing="0" border="1" width="100%" bgcolor="#f9fafb" bordercolor="#e5e7eb" style="border-collapse: collapse; margin-top: 20px;">
<tr> <tr>
<td> <td>

View File

@ -5,7 +5,7 @@
{% block body %} {% block body %}
<div class="min-h-screen bg-gradient-to-br from-yellow-50 via-white to-orange-50 relative overflow-hidden"> <div class="min-h-screen bg-gradient-to-br from-yellow-50 via-white to-orange-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"> <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"> <div class="container mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 py-3 sm:py-4 flex justify-between items-center">
<img src="{{ asset('images/logo.png') }}" alt="Logo" <img src="{{ asset('images/logo.png') }}" alt="Logo"
class="w-32 sm:w-36 md:w-40 h-auto hover:opacity-90 transition-opacity"/> class="w-32 sm:w-36 md:w-40 h-auto hover:opacity-90 transition-opacity"/>
<a href="{{ path('app_contact') }}" <a href="{{ path('app_contact') }}"
@ -15,11 +15,11 @@
</div> </div>
</header> </header>
<main 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"> <main class="container mx-auto max-w-7xl 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">
<h1 class="text-3xl sm:text-4xl md:text-5xl font-bold text-gray-800 text-center mb-6 sm:mb-8 tracking-tight leading-tight"> <h1 class="text-3xl sm:text-4xl md:text-5xl font-bold text-gray-800 text-center mb-6 sm:mb-8 tracking-tight leading-tight">
Willkommen zum <span class="bg-clip-text text-transparent bg-gradient-to-r from-red-500 to-orange-500">Abiball 2025</span> Willkommen zum <span class="bg-clip-text text-transparent bg-gradient-to-r from-red-500 to-orange-500">Abiball 2025</span>
</h1> </h1>
<div class="w-full max-w-4xl"> <div class="w-full max-w-6xl">
<div class="bg-white/80 backdrop-blur-md shadow-xl rounded-2xl sm:rounded-3xl p-6 sm:p-8 md:p-10 mb-6 sm:mb-8 transform transition-all duration-300 border border-gray-100"> <div class="bg-white/80 backdrop-blur-md shadow-xl rounded-2xl sm:rounded-3xl p-6 sm:p-8 md:p-10 mb-6 sm:mb-8 transform transition-all duration-300 border border-gray-100">
<h1 class="text-3xl">Willkommen zum Abiball 2025! 🎉🎓</h1> <h1 class="text-3xl">Willkommen zum Abiball 2025! 🎉🎓</h1>
<p class="text-base sm:text-lg text-gray-700 leading-relaxed whitespace-pre-line text-wrap"> <p class="text-base sm:text-lg text-gray-700 leading-relaxed whitespace-pre-line text-wrap">
@ -31,7 +31,7 @@
</p> </p>
</div> </div>
<div class="grid grid-cols-1 sm:grid-cols-2 w-full gap-3 mb-5"> <div class="grid grid-cols-1 sm:grid-cols-3 w-full gap-3 mb-5">
<div class="bg-white/80 backdrop-blur-md shadow-xl rounded-2xl sm:rounded-3xl p-5 mb-3 sm:mb-12 transform transition-all duration-300 border border-gray-100"> <div class="bg-white/80 backdrop-blur-md shadow-xl rounded-2xl sm:rounded-3xl p-5 mb-3 sm:mb-12 transform transition-all duration-300 border border-gray-100">
<h2 class="text-xl text-center font-semibold mb-4 bg-clip-text text-transparent bg-gradient-to-r from-red-500 to-orange-500">Datum & Uhrzeit</h2> <h2 class="text-xl text-center font-semibold mb-4 bg-clip-text text-transparent bg-gradient-to-r from-red-500 to-orange-500">Datum & Uhrzeit</h2>
<div class="space-y-3"> <div class="space-y-3">
@ -75,6 +75,39 @@
</div> </div>
</div> </div>
</div> </div>
<div class="bg-white/80 backdrop-blur-md shadow-xl rounded-2xl sm:rounded-3xl p-5 mb-3 sm:mb-12 transform transition-all duration-300 border border-gray-100">
<h2 class="text-xl text-center font-semibold mb-4 bg-clip-text text-transparent bg-gradient-to-r from-red-500 to-orange-500">Ticket Preise</h2>
<div class="space-y-3">
<div class="flex items-center space-x-3">
<twig:ux:icon name="heroicons:ticket" class="w-5 h-5 text-orange-600" />
<div class="text-gray-700">
<span class="font-medium">All-Inclusive Ticket</span>
<span class="ml-2">50€</span>
</div>
</div>
<div class="flex items-center space-x-3">
<twig:ux:icon name="heroicons:cake" class="w-5 h-5 text-orange-600" />
<div class="text-gray-700">
<span class="font-medium">After-Show Ticket</span>
<span class="ml-2">20€</span>
</div>
</div>
<div class="flex items-center space-x-3">
<twig:ux:icon name="heroicons:musical-note" class="w-5 h-5 text-orange-600" />
<div class="text-gray-700">
<span class="font-medium">Kind (6-12 Jahre)</span>
<span class="ml-2">15€</span>
</div>
</div>
<div class="flex items-center space-x-3">
<twig:ux:icon name="heroicons:musical-note" class="w-5 h-5 text-orange-600" />
<div class="text-gray-700">
<span class="font-medium">Kind (0-6 Jahre)</span>
<span class="ml-2">0€</span>
</div>
</div>
</div>
</div>
</div> </div>
<div class="text-center space-y-6"> <div class="text-center space-y-6">

View File

@ -49,6 +49,10 @@
<twig:ux:icon name="ic:baseline-phone" class="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400" /> <twig:ux:icon name="ic:baseline-phone" class="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400" />
<input name="phone" data-form-target="phone" class="w-full pl-10 pr-4 py-3 rounded-xl border border-gray-200 focus:border-orange-500 focus:ring-2 focus:ring-orange-200 transition-all" type="tel" placeholder="Telefon (optional)"> <input name="phone" data-form-target="phone" class="w-full pl-10 pr-4 py-3 rounded-xl border border-gray-200 focus:border-orange-500 focus:ring-2 focus:ring-orange-200 transition-all" type="tel" placeholder="Telefon (optional)">
</div> </div>
<div class="relative">
<twig:ux:icon name="tabler:coin" class="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400" />
<input name="donation" data-form-target="donation" class="w-full pl-10 pr-4 py-3 rounded-xl border border-gray-200 focus:border-orange-500 focus:ring-2 focus:ring-orange-200 transition-all" type="number" placeholder="Spende (optional)">
</div>
</div> </div>
</section> </section>