feat: MailJet newsletter subscription via MyE&P API endpoint
This commit is contained in:
@@ -27,15 +27,54 @@ namespace EP\EpProducts\Controller;
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
use EP\EpProducts\Domain\Model\Dto\NewsletterSubscriptionRequest;
|
||||
use EP\EpProducts\MyEP\ApiClient;
|
||||
use EP\EpProducts\MyEP\ApiException;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
|
||||
class NewsletterController extends ActionController
|
||||
{
|
||||
private ApiClient $apiClient;
|
||||
|
||||
public function __construct(ApiClient $apiClient)
|
||||
{
|
||||
$this->apiClient = $apiClient;
|
||||
}
|
||||
|
||||
public function indexAction()
|
||||
{
|
||||
$this->view->assign('result', GeneralUtility::_GET('result'));
|
||||
}
|
||||
|
||||
public function subscriptionFormAction(?NewsletterSubscriptionRequest $subscriptionRequest = null)
|
||||
{
|
||||
if (null === $subscriptionRequest) {
|
||||
$subscriptionRequest = new NewsletterSubscriptionRequest();
|
||||
}
|
||||
|
||||
try {
|
||||
$lists = $this->apiClient->getNewsletterLists();
|
||||
} catch (ApiException $e) {
|
||||
$lists = [];
|
||||
}
|
||||
|
||||
$this->view->assign('subscriptionRequest', $subscriptionRequest);
|
||||
$this->view->assign('lists', $lists);
|
||||
}
|
||||
|
||||
public function subscriptionFormSubmitAction(NewsletterSubscriptionRequest $subscriptionRequest)
|
||||
{
|
||||
try {
|
||||
$result = $this->apiClient->subscribeToNewsletters($subscriptionRequest);
|
||||
$result['success'] = true;
|
||||
} catch (ApiException $e) {
|
||||
$result = [
|
||||
'success' => false,
|
||||
'message' => $e->getMessage(),
|
||||
];
|
||||
}
|
||||
|
||||
$this->view->assign('result', $result);
|
||||
}
|
||||
}
|
||||
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Domain\Model\Dto;
|
||||
|
||||
use JsonSerializable;
|
||||
|
||||
class NewsletterSubscriptionRequest implements JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty")
|
||||
*/
|
||||
private ?string $firstName = null;
|
||||
|
||||
/**
|
||||
* @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty")
|
||||
*/
|
||||
private ?string $lastName = null;
|
||||
|
||||
/**
|
||||
* @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty")
|
||||
* @TYPO3\CMS\Extbase\Annotation\Validate("EmailAddress")
|
||||
*/
|
||||
private ?string $email = null;
|
||||
|
||||
/**
|
||||
* @var list<int>
|
||||
* @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty")
|
||||
*/
|
||||
private array $listIds = [];
|
||||
|
||||
/**
|
||||
* @TYPO3\CMS\Extbase\Annotation\Validate("Boolean", options={"is": true})
|
||||
*/
|
||||
private bool $consent = false;
|
||||
|
||||
public function getFirstName(): ?string
|
||||
{
|
||||
return $this->firstName;
|
||||
}
|
||||
|
||||
public function setFirstName(?string $firstName): self
|
||||
{
|
||||
$this->firstName = $firstName;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLastName(): ?string
|
||||
{
|
||||
return $this->lastName;
|
||||
}
|
||||
|
||||
public function setLastName(?string $lastName): self
|
||||
{
|
||||
$this->lastName = $lastName;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getEmail(): ?string
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
public function setEmail(?string $email): self
|
||||
{
|
||||
$this->email = $email;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<int>
|
||||
*/
|
||||
public function getListIds(): array
|
||||
{
|
||||
return $this->listIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<int|string> $listIds
|
||||
*/
|
||||
public function setListIds(array $listIds): self
|
||||
{
|
||||
$this->listIds = $listIds;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isConsent(): bool
|
||||
{
|
||||
return $this->consent;
|
||||
}
|
||||
|
||||
public function setConsent(bool $consent): self
|
||||
{
|
||||
$this->consent = $consent;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return [
|
||||
'firstName' => $this->firstName,
|
||||
'lastName' => $this->lastName,
|
||||
'email' => $this->email,
|
||||
'listIds' => array_map(function($value) {
|
||||
return (int) $value;
|
||||
}, $this->listIds),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -2,16 +2,20 @@
|
||||
|
||||
namespace EP\EpProducts\MyEP;
|
||||
|
||||
use EP\EpProducts\Domain\Model\Dto\NewsletterSubscriptionRequest;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use League\OAuth2\Client\Provider\AbstractProvider;
|
||||
use League\OAuth2\Client\Provider\GenericProvider;
|
||||
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
|
||||
use League\OAuth2\Client\Token\AccessToken;
|
||||
use Psr\Log\LoggerAwareInterface;
|
||||
use Psr\Log\LoggerAwareTrait;
|
||||
use Symfony\Component\HttpClient\Exception\ClientException;
|
||||
use Symfony\Component\HttpClient\HttpClient;
|
||||
use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
use Symfony\Contracts\HttpClient\ResponseInterface;
|
||||
use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
@@ -26,30 +30,18 @@ class ApiClient implements LoggerAwareInterface
|
||||
*/
|
||||
public function getLastUpdateAt(): ?\DateTimeImmutable
|
||||
{
|
||||
$httpClient = $this->getHttpClient();
|
||||
$data = $this->requestJson('GET', 'last-update');
|
||||
|
||||
try {
|
||||
$response = $httpClient->request('GET', 'last-update');
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
$this->logger->error($e->getMessage());
|
||||
throw new ApiException($e->getMessage());
|
||||
if (!isset($data['timestamp']) || null === $data['timestamp'] || '' === $data['timestamp']) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
if (200 !== $response->getStatusCode()) {
|
||||
throw new ApiException($response->getStatusCode());
|
||||
}
|
||||
|
||||
$data = $response->toArray(false);
|
||||
|
||||
if (null === $data['timestamp'] ?? null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new \DateTimeImmutable($data['timestamp']);
|
||||
} catch (\Throwable $e) {
|
||||
$this->logger->error($e->getMessage());
|
||||
throw new ApiException($e->getMessage());
|
||||
$message = sprintf('Invalid timestamp returned by MyEP API for GET last-update: %s', $e->getMessage());
|
||||
$this->logError($message, ['exception' => $e]);
|
||||
throw new ApiException($message, 0, $e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,25 +50,7 @@ class ApiClient implements LoggerAwareInterface
|
||||
*/
|
||||
public function getPickups(): array
|
||||
{
|
||||
$httpClient = $this->getHttpClient();
|
||||
|
||||
try {
|
||||
$response = $httpClient->request('GET', 'pickups');
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
$this->logger->error($e->getMessage());
|
||||
throw new ApiException($e->getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
if (200 !== $response->getStatusCode()) {
|
||||
throw new ApiException($response->getStatusCode());
|
||||
}
|
||||
|
||||
return $response->toArray(false);
|
||||
} catch (\Throwable $e) {
|
||||
$this->logger->error($e->getMessage());
|
||||
throw new ApiException($e->getMessage());
|
||||
}
|
||||
return $this->requestJson('GET', 'pickups');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,25 +58,7 @@ class ApiClient implements LoggerAwareInterface
|
||||
*/
|
||||
public function getTravels(): array
|
||||
{
|
||||
$httpClient = $this->getHttpClient();
|
||||
|
||||
try {
|
||||
$response = $httpClient->request('GET', 'travels');
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
$this->logger->error($e->getMessage());
|
||||
throw new ApiException($e->getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
if (200 !== $response->getStatusCode()) {
|
||||
throw new ApiException($response->getStatusCode());
|
||||
}
|
||||
|
||||
return $response->toArray(false);
|
||||
} catch (\Throwable $e) {
|
||||
$this->logger->error($e->getMessage());
|
||||
throw new ApiException($e->getMessage());
|
||||
}
|
||||
return $this->requestJson('GET', 'travels');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,18 +66,33 @@ class ApiClient implements LoggerAwareInterface
|
||||
*/
|
||||
public function registerAddress(array $addressData): void
|
||||
{
|
||||
$httpClient = $this->getHttpClient();
|
||||
$response = $this->request('POST', 'contactform', [
|
||||
'json' => $addressData,
|
||||
]);
|
||||
|
||||
try {
|
||||
$httpClient->request('POST', 'contactform', [
|
||||
'json' => $addressData,
|
||||
]);
|
||||
} catch (ClientException $e) {
|
||||
$this->logger->warning($e->getMessage());
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
$this->logger->error($e->getMessage());
|
||||
throw new ApiException($e->getMessage());
|
||||
}
|
||||
$this->assertStatusCode($response, [Response::HTTP_OK, Response::HTTP_CREATED, Response::HTTP_ACCEPTED, Response::HTTP_NO_CONTENT], 'POST', 'contactform');
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiException
|
||||
*/
|
||||
public function getNewsletterLists(): array
|
||||
{
|
||||
return $this->requestJson('GET', 'newsletters');
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiException
|
||||
*/
|
||||
public function subscribeToNewsletters(NewsletterSubscriptionRequest $subscriptionRequest): array
|
||||
{
|
||||
$response = $this->request('POST', 'newsletter-subscriptions', [
|
||||
'json' => $subscriptionRequest,
|
||||
]);
|
||||
|
||||
$this->assertStatusCode($response, [Response::HTTP_OK, Response::HTTP_ACCEPTED], 'POST', 'newsletter-subscriptions');
|
||||
|
||||
return $this->decodeResponse($response, 'POST', 'newsletter-subscriptions');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -129,23 +100,7 @@ class ApiClient implements LoggerAwareInterface
|
||||
*/
|
||||
public function getTravel(string $productCode): array
|
||||
{
|
||||
$httpClient = $this->getHttpClient();
|
||||
|
||||
try {
|
||||
$response = $httpClient->request('GET', 'travels/' . $productCode);
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
throw new ApiException($e->getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
if (200 !== $response->getStatusCode()) {
|
||||
throw new ApiException($response->getStatusCode());
|
||||
}
|
||||
|
||||
return $response->toArray(false);
|
||||
} catch (\Throwable $e) {
|
||||
throw new ApiException($e->getMessage());
|
||||
}
|
||||
return $this->requestJson('GET', 'travels/' . $productCode);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -153,22 +108,75 @@ class ApiClient implements LoggerAwareInterface
|
||||
*/
|
||||
public function getPickupsPlanning(string $travelCode): array
|
||||
{
|
||||
$httpClient = $this->getHttpClient();
|
||||
return $this->requestJson('GET', 'pickups-planning/' . $travelCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiException
|
||||
*/
|
||||
private function requestJson(string $method, string $uri, array $options = [], array $expectedStatusCodes = [Response::HTTP_OK]): array
|
||||
{
|
||||
$response = $this->request($method, $uri, $options);
|
||||
|
||||
$this->assertStatusCode($response, $expectedStatusCodes, $method, $uri);
|
||||
|
||||
return $this->decodeResponse($response, $method, $uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiException
|
||||
*/
|
||||
private function request(string $method, string $uri, array $options = []): ResponseInterface
|
||||
{
|
||||
try {
|
||||
$response = $httpClient->request('GET', 'pickups-planning/' . $travelCode);
|
||||
return $this->getHttpClient()->request($method, $uri, $options);
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
throw new ApiException($e->getMessage());
|
||||
$message = sprintf('MyEP API transport error for %s %s: %s', $method, $uri, $e->getMessage());
|
||||
$this->logError($message, ['exception' => $e]);
|
||||
throw new ApiException($message, 0, $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int[] $expectedStatusCodes
|
||||
*
|
||||
* @throws ApiException
|
||||
*/
|
||||
private function assertStatusCode(ResponseInterface $response, array $expectedStatusCodes, string $method, string $uri): void
|
||||
{
|
||||
try {
|
||||
$statusCode = $response->getStatusCode();
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
$message = sprintf('MyEP API transport error while reading status for %s %s: %s', $method, $uri, $e->getMessage());
|
||||
$this->logError($message, ['exception' => $e]);
|
||||
throw new ApiException($message, 0, $e);
|
||||
}
|
||||
|
||||
try {
|
||||
if (200 !== $response->getStatusCode()) {
|
||||
throw new ApiException($response->getStatusCode());
|
||||
}
|
||||
if (true === in_array($statusCode, $expectedStatusCodes, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$message = sprintf('MyEP API returned unexpected status %d for %s %s', $statusCode, $method, $uri);
|
||||
$this->logWarning($message);
|
||||
|
||||
throw new ApiException($message, $statusCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiException
|
||||
*/
|
||||
private function decodeResponse(ResponseInterface $response, string $method, string $uri): array
|
||||
{
|
||||
try {
|
||||
return $response->toArray(false);
|
||||
} catch (\Throwable $e) {
|
||||
throw new ApiException($e->getMessage());
|
||||
} catch (DecodingExceptionInterface $e) {
|
||||
$message = sprintf('MyEP API returned invalid JSON for %s %s: %s', $method, $uri, $e->getMessage());
|
||||
$this->logError($message, ['exception' => $e]);
|
||||
throw new ApiException($message, 0, $e);
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
$message = sprintf('MyEP API transport error while reading body for %s %s: %s', $method, $uri, $e->getMessage());
|
||||
$this->logError($message, ['exception' => $e]);
|
||||
throw new ApiException($message, 0, $e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,18 +185,41 @@ class ApiClient implements LoggerAwareInterface
|
||||
$config = GeneralUtility::makeInstance(ExtensionConfiguration::class)
|
||||
->get('ep_products');
|
||||
|
||||
if (null === static::$accessToken || true === static::$accessToken->hasExpired()) {
|
||||
static::$accessToken = $this
|
||||
->getProvider($config)
|
||||
->getAccessToken('client_credentials')
|
||||
;
|
||||
}
|
||||
static::$accessToken = $this->getAccessToken($config);
|
||||
|
||||
return HttpClient::createForBaseUri($config['myEpApiBaseUrl'], [
|
||||
'auth_bearer' => static::$accessToken->getToken(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiException
|
||||
*/
|
||||
private function getAccessToken(array $config): AccessToken
|
||||
{
|
||||
if (null !== static::$accessToken && false === static::$accessToken->hasExpired()) {
|
||||
return static::$accessToken;
|
||||
}
|
||||
|
||||
try {
|
||||
static::$accessToken = $this->getProvider($config)->getAccessToken('client_credentials');
|
||||
} catch (IdentityProviderException $e) {
|
||||
$message = sprintf('MyEP OAuth token request failed: %s', $e->getMessage());
|
||||
$this->logError($message, ['exception' => $e]);
|
||||
throw new ApiException($message, 0, $e);
|
||||
} catch (\UnexpectedValueException $e) {
|
||||
$message = sprintf('MyEP OAuth token response was invalid: %s', $e->getMessage());
|
||||
$this->logError($message, ['exception' => $e]);
|
||||
throw new ApiException($message, 0, $e);
|
||||
} catch (GuzzleException $e) {
|
||||
$message = sprintf('MyEP OAuth token transport failed: %s', $e->getMessage());
|
||||
$this->logError($message, ['exception' => $e]);
|
||||
throw new ApiException($message, 0, $e);
|
||||
}
|
||||
|
||||
return static::$accessToken;
|
||||
}
|
||||
|
||||
private function getProvider(array $config): AbstractProvider
|
||||
{
|
||||
return new GenericProvider([
|
||||
@@ -201,4 +232,18 @@ class ApiClient implements LoggerAwareInterface
|
||||
'scopes' => 'api',
|
||||
]);
|
||||
}
|
||||
|
||||
private function logError(string $message, array $context = []): void
|
||||
{
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->error($message, $context);
|
||||
}
|
||||
}
|
||||
|
||||
private function logWarning(string $message, array $context = []): void
|
||||
{
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->warning($message, $context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,6 +131,12 @@ call_user_func(function () {
|
||||
'Newsletter'
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
|
||||
'EP.EpProducts',
|
||||
'newsletter_subscription',
|
||||
'Newsletter-/RA-Registrierung'
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
|
||||
'EP.EpProducts',
|
||||
'maps',
|
||||
|
||||
@@ -57,6 +57,7 @@ plugin.tx_epproducts {
|
||||
logoImage = {$plugin.tx_eptheme.settings.logoImage}
|
||||
themekey = {$plugin.tx_eptheme.settings.themekey}
|
||||
globalConceptCode = {$plugin.tx_eptheme.settings.globalConceptCode}
|
||||
dataProtectionPageUid = {$plugin.tx_eptheme.settings.dataProtectionPageUid}
|
||||
datePickerPresets {
|
||||
1 {
|
||||
label = Silvester
|
||||
|
||||
@@ -213,6 +213,17 @@ $boot = function () {
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'newsletter_subscription',
|
||||
[
|
||||
'Newsletter' => 'subscriptionForm,subscriptionFormSubmit',
|
||||
],
|
||||
[
|
||||
'Newsletter' => 'subscriptionForm,subscriptionFormSubmit',
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'maps',
|
||||
|
||||
@@ -85,6 +85,9 @@
|
||||
<trans-unit id="tx_eptheme.message.contactForm.firstName.1221560718">
|
||||
<target>Bitte angeben</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="tx_eptheme.message.contactForm.lastName.1221560718">
|
||||
<target>Bitte angeben</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="tx_eptheme.message.contactForm.email.1221560718">
|
||||
<target>Bitte angeben</target>
|
||||
</trans-unit>
|
||||
@@ -92,7 +95,14 @@
|
||||
<target>Bitte angeben</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="tx_eptheme.message.contactForm.email.1221559976">
|
||||
<target>Ungültige E-Mail Adresse</target>
|
||||
<target>Bitte gib eine gültige E-Mail Adresse an</target>
|
||||
</trans-unit>
|
||||
|
||||
<trans-unit id="tx_eptheme.message.newsletter.listIds.1347992400">
|
||||
<target>Bitte wähle mindestens einen Newsletter</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="tx_eptheme.message.newsletter.consent.1361959228">
|
||||
<target>Bitte stimme den Datenschutzbestimmungen zu</target>
|
||||
</trans-unit>
|
||||
|
||||
<trans-unit id="label.whatsapp_instructions">
|
||||
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en"
|
||||
xmlns:f="http://typo3.org/ns/fluid/ViewHelpers">
|
||||
|
||||
<f:layout name="Default"/>
|
||||
|
||||
<f:section name="Main">
|
||||
<a id="newsletter-form" class="anchor"></a>
|
||||
<div class="container">
|
||||
<f:form method="post" action="subscriptionFormSubmit" name="subscriptionRequest" section="newsletter-form" object="{subscriptionRequest}">
|
||||
<div class="grid lg:grid-cols-2 lg:gap-x-8 items-start">
|
||||
<div>
|
||||
<h3>
|
||||
Meine Daten
|
||||
</h3>
|
||||
<f:render section="Field" arguments="{property: 'firstName', label: 'Vorname'}"/>
|
||||
<f:render section="Field" arguments="{property: 'lastName', label: 'Nachname'}"/>
|
||||
<f:render section="Field" arguments="{property: 'email', label: 'E-Mail'}"/>
|
||||
<div class="mb-4">
|
||||
<f:form.validationResults for="subscriptionRequest.consent">
|
||||
<label class="inline-flex items-center">
|
||||
<f:form.checkbox property="consent" value="1" class="form-checkbox{f:if(condition: validationResults.errors.0, then: ' form-checkbox--has-error')}"/>
|
||||
<span class="block ml-2">Ich akzeptiere die <f:link.typolink parameter="{settings.dataProtectionPageUid}" class="underline" target="_blank">Datenschutzbestimmungen</f:link.typolink>*</span>
|
||||
</label>
|
||||
<f:if condition="{validationResults.flattenedErrors}">
|
||||
<div class="text-red-500 mt-2" role="alert">
|
||||
<f:for each="{validationResults.errors}" as="error">
|
||||
{f:translate(key: 'tx_eptheme.message.newsletter.consent.{error.code}', extensionName: 'ep_theme')}
|
||||
<br />
|
||||
</f:for>
|
||||
</div>
|
||||
</f:if>
|
||||
</f:form.validationResults>
|
||||
</div>
|
||||
<div class="hidden lg:block">
|
||||
<button type="submit" class="button bg-button">
|
||||
Anmelden
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<h3>
|
||||
Ich möchte folgende Newsletter erhalten
|
||||
</h3>
|
||||
<f:form.validationResults for="subscriptionRequest.listIds">
|
||||
<f:for each="{lists}" as="list">
|
||||
<label for="list-{list.id}" class="flex items-center">
|
||||
<f:form.checkbox property="listIds" multiple="1" value="{list.id}" class="form-checkbox"/>
|
||||
<span class="block ml-2">{list.label}</span>
|
||||
</label>
|
||||
</f:for>
|
||||
<f:if condition="{validationResults.flattenedErrors}">
|
||||
<div class="text-red-500 mt-2" role="alert">
|
||||
<f:for each="{validationResults.errors}" as="error">
|
||||
{f:translate(key: 'tx_eptheme.message.newsletter.listIds.{error.code}', extensionName: 'ep_theme')}
|
||||
<br />
|
||||
</f:for>
|
||||
</div>
|
||||
</f:if>
|
||||
</f:form.validationResults>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lg:hidden mt-4">
|
||||
<button type="submit" class="button bg-button">
|
||||
Anmelden
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</f:form>
|
||||
</div>
|
||||
</f:section>
|
||||
|
||||
<f:section name="Field">
|
||||
<f:form.validationResults for="subscriptionRequest.{property}">
|
||||
<f:variable name="hasErrors" value="{validationResults.errors.0}"/>
|
||||
<label class="block mb-4">
|
||||
<span class="{f:if(condition: hasErrors, then: 'text-red-500', else: 'text-zinc-700')}">{label}*</span>
|
||||
<f:form.textfield property="{property}" class="form-field {f:if(condition: hasErrors, then: 'form-field--has-error')}"/>
|
||||
<f:if condition="{validationResults.flattenedErrors}">
|
||||
<div class="text-red-500 mt-2" role="alert">
|
||||
<f:for each="{validationResults.errors}" as="error">
|
||||
{f:translate(key: 'tx_eptheme.message.contactForm.{property}.{error.code}', extensionName: 'ep_theme')}
|
||||
<br />
|
||||
</f:for>
|
||||
</div>
|
||||
</f:if>
|
||||
</label>
|
||||
</f:form.validationResults>
|
||||
</f:section>
|
||||
|
||||
</html>
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en"
|
||||
xmlns:f="http://typo3.org/ns/fluid/ViewHelpers">
|
||||
|
||||
<f:layout name="Default"/>
|
||||
|
||||
<f:section name="Main">
|
||||
<div class="container">
|
||||
<div class="bg-ep-primary-light text-white p-4">
|
||||
<h2>
|
||||
Vielen Dank für dein Interesse
|
||||
</h2>
|
||||
<p>
|
||||
Deine Anmeldung muss noch bestätigt werden. Bitte nutze den Link aus der Bestätigungs-E-Mail, die in
|
||||
Kürze bei dir eintreffen sollte.
|
||||
</p>
|
||||
<p class="text-sm">
|
||||
Sieh am besten auch im Spam-Ordner nach.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</f:section>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user