From 615f144d1df21ca1040edc2b7e840952f103aa2c Mon Sep 17 00:00:00 2001 From: Ernest Walzel Date: Fri, 15 Mar 2024 12:08:24 +0100 Subject: [PATCH 1/9] Subscription API --- .../Api/NewsletterSubscriptionController.php | 46 +++++++++++++++++++ app/Providers/AppServiceProvider.php | 18 +++++--- routes/api.php | 7 ++- .../Api/NewsletterSubscriptionsTest.php | 24 ++++++++++ 4 files changed, 88 insertions(+), 7 deletions(-) create mode 100644 app/Http/Controllers/Api/NewsletterSubscriptionController.php create mode 100644 tests/Feature/Api/NewsletterSubscriptionsTest.php diff --git a/app/Http/Controllers/Api/NewsletterSubscriptionController.php b/app/Http/Controllers/Api/NewsletterSubscriptionController.php new file mode 100644 index 000000000..7998ebcda --- /dev/null +++ b/app/Http/Controllers/Api/NewsletterSubscriptionController.php @@ -0,0 +1,46 @@ +validate([ + 'email' => 'required|email', + ]); + + $listId = config('mailchimp.lists.webumenia-newsletter.id'); + + $mailChimp->post("lists/{$listId}/members", [ + 'email_address' => $request->email, + 'status' => 'pending', + 'email_type' => 'html', + 'marketing_permissions' => [ + [ + 'marketing_permission_id' => config( + 'mailchimp.lists.webumenia-newsletter.marketing_permissions.default' + ), + 'enabled' => true, + ], + ], + ]); + + if (!$mailChimp->success()) { + abort(500, $mailChimp->getLastError()); + } + + return response('', 201)->cookie( + 'newsletterSubscribedAt', + Date::now()->toIso8601String(), + Date::now() + ->addYears(10) + ->diffInMinutes() + ); + } +} diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 6eaa56331..243d63348 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -8,6 +8,7 @@ use App\Harvest\Importers\ItemImporter; use App\Harvest\Mappers\BaseAuthorityMapper; use App\Services\Frontend; +use DrewM\MailChimp\MailChimp; use Illuminate\Filesystem\FilesystemAdapter; use Illuminate\Pagination\Paginator; use Illuminate\Support\Facades\Blade; @@ -35,20 +36,24 @@ public function register() $this->app->bind(AuthoritySearchRequestType::class); $this->app->bind(ItemSearchRequestType::class); - $this->app->when(AuthorityRepository::class) + $this->app + ->when(AuthorityRepository::class) ->needs('$locales') ->give(config('translatable.locales')); - $this->app->when(ItemRepository::class) + $this->app + ->when(ItemRepository::class) ->needs('$locales') ->give(config('translatable.locales')); - $this->app->when(ItemImporter::class) + $this->app + ->when(ItemImporter::class) ->needs(BaseAuthorityMapper::class) ->give(function () { return new BaseAuthorityMapper(); }); - $this->app->singleton(Frontend::class, fn () => new Frontend(FrontendEnum::WEBUMENIA)); + $this->app->singleton(Frontend::class, fn() => new Frontend(FrontendEnum::WEBUMENIA)); + $this->app->bind(MailChimp::class, fn() => new MailChimp(config('mailchimp.apiKey'))); } public function boot() @@ -77,9 +82,10 @@ public function boot() }); } - private function formatDate($expression, $format) { - return $expression? "locale(App::getLocale())->isoFormat('$format'); ?>": ""; + return $expression + ? "locale(App::getLocale())->isoFormat('$format'); ?>" + : ''; } } diff --git a/routes/api.php b/routes/api.php index ac102b56a..040386a83 100644 --- a/routes/api.php +++ b/routes/api.php @@ -1,11 +1,12 @@ names('api.articles') ->only(['show']); +Route::resource('/newsletter-subscriptions', NewsletterSubscriptionController::class)->names( + 'api.newsletter-subscriptions' +); + Route::prefix('v1') ->name('api.v1.') ->group(function () { diff --git a/tests/Feature/Api/NewsletterSubscriptionsTest.php b/tests/Feature/Api/NewsletterSubscriptionsTest.php new file mode 100644 index 000000000..5a68bfa53 --- /dev/null +++ b/tests/Feature/Api/NewsletterSubscriptionsTest.php @@ -0,0 +1,24 @@ +mock(MailChimp::class, function (MockInterface $mock) { + $mock->shouldReceive('post')->once(); + $mock->shouldReceive('success')->andReturn(true); + }); + + $this->post(route('api.newsletter-subscriptions.store'), [ + 'email' => 'aa@bb.com', + ]) + ->assertStatus(201) + ->assertCookie('newsletterSubscribedAt'); + } +} From 53ed536a4a1e9f572c1e72c3e85db8b89a686831 Mon Sep 17 00:00:00 2001 From: Ernest Walzel Date: Fri, 15 Mar 2024 13:06:57 +0100 Subject: [PATCH 2/9] Livewire-free NewsletterSignupForm template --- resources/js/app.js | 1 + .../NewsletterSignupFormController.vue | 32 ++++++++++ .../newsletter-signup-form.blade.php | 60 +++++++++++++++++++ .../views/frontend/articles/show.blade.php | 2 +- resources/views/informacie.blade.php | 2 +- resources/views/kolekcia.blade.php | 2 +- 6 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 resources/js/components/NewsletterSignupFormController.vue create mode 100644 resources/views/components/newsletter-signup-form.blade.php diff --git a/resources/js/app.js b/resources/js/app.js index 2941c218a..089306b9c 100644 --- a/resources/js/app.js +++ b/resources/js/app.js @@ -72,6 +72,7 @@ Vue.component('copy-to-clipboard-link', require('./components/CopyToClipboardLin Vue.component('bottom-modal', require('./components/BottomModal.vue').default); Vue.component('user-interaction-context', require('./components/UserInteractionContext.vue').default); Vue.component('livewire-vue-adaptor', require('./components/LivewireVueAdaptor.vue').default); +Vue.component('newsletter-signup-form-controller', require('./components/NewsletterSignupFormController.vue').default); Vue.component('slider', require('./components/vue/slider').default); Vue.component('color-slider', require('./components/vue/color-slider').default); diff --git a/resources/js/components/NewsletterSignupFormController.vue b/resources/js/components/NewsletterSignupFormController.vue new file mode 100644 index 000000000..eb764fe9e --- /dev/null +++ b/resources/js/components/NewsletterSignupFormController.vue @@ -0,0 +1,32 @@ + + + diff --git a/resources/views/components/newsletter-signup-form.blade.php b/resources/views/components/newsletter-signup-form.blade.php new file mode 100644 index 000000000..bffc31e27 --- /dev/null +++ b/resources/views/components/newsletter-signup-form.blade.php @@ -0,0 +1,60 @@ +@props(['tracking-variant' => 'inline']) + + +
+
+ + + +
+
+
+
+
{!! __('general.newsletter_sign_up.subtitle') !!}
+ +
+ + + + +
+
+ {!! __('general.newsletter_sign_up.privacy_policy.blurb') !!} + {{ __('general.newsletter_sign_up.privacy_policy.link') }}. +
+
+
+
+
+
diff --git a/resources/views/frontend/articles/show.blade.php b/resources/views/frontend/articles/show.blade.php index b1306acc7..8b3cb5e83 100644 --- a/resources/views/frontend/articles/show.blade.php +++ b/resources/views/frontend/articles/show.blade.php @@ -116,7 +116,7 @@
- +
diff --git a/resources/views/informacie.blade.php b/resources/views/informacie.blade.php index 0813416ae..28780541f 100644 --- a/resources/views/informacie.blade.php +++ b/resources/views/informacie.blade.php @@ -109,7 +109,7 @@
- +
diff --git a/resources/views/kolekcia.blade.php b/resources/views/kolekcia.blade.php index 0d6e26bad..9257ab433 100644 --- a/resources/views/kolekcia.blade.php +++ b/resources/views/kolekcia.blade.php @@ -163,7 +163,7 @@
- +
From 9d8220a6f01889683430f3e820bfd78601445f42 Mon Sep 17 00:00:00 2001 From: Ernest Walzel Date: Fri, 15 Mar 2024 13:30:06 +0100 Subject: [PATCH 3/9] Successful sign-up tracking --- .../NewsletterSignupFormController.vue | 26 ++++++++++++++++--- .../newsletter-signup-form.blade.php | 4 +-- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/resources/js/components/NewsletterSignupFormController.vue b/resources/js/components/NewsletterSignupFormController.vue index eb764fe9e..69d4202ad 100644 --- a/resources/js/components/NewsletterSignupFormController.vue +++ b/resources/js/components/NewsletterSignupFormController.vue @@ -4,7 +4,7 @@ import { useApiClient } from './useApiClient' const apiClient = useApiClient() -const props = defineProps(['url']) +const props = defineProps(['url', 'trackingVariant']) const error = ref(null) const success = ref(false) @@ -17,16 +17,36 @@ async function submit(event) { try { await apiClient.post(props.url, data) - success.value = true error.value = null + success.value = true + track('signupSuccessful', props.trackingVariant) } catch (e) { error.value = e.response.data.message } finally { loading.value = false } } + +function track(action, label = undefined) { + if (!window?.dataLayer) { + return + } + + window.dataLayer.push({ + event: 'NewsletterSignupFormEvent', + eventCategory: 'NewsletterSignupForm', + eventAction: action, + eventLabel: label, + }) +} diff --git a/resources/views/components/newsletter-signup-form.blade.php b/resources/views/components/newsletter-signup-form.blade.php index bffc31e27..29482eae2 100644 --- a/resources/views/components/newsletter-signup-form.blade.php +++ b/resources/views/components/newsletter-signup-form.blade.php @@ -1,7 +1,7 @@ -@props(['tracking-variant' => 'inline']) +@props(['trackingVariant' => 'inline']) + tracking-variant="{{ $trackingVariant }}" v-slot="c">