From 14fd54ab893fb58ce4fa6ef6932e8f8a52c09819 Mon Sep 17 00:00:00 2001 From: vhande Date: Wed, 19 Jun 2024 13:26:21 +0200 Subject: [PATCH 01/42] Add getOrganizers --- .../Controllers/IntegrationController.php | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/app/Domain/Integrations/Controllers/IntegrationController.php b/app/Domain/Integrations/Controllers/IntegrationController.php index ac8cb1c34..4b122eb6f 100644 --- a/app/Domain/Integrations/Controllers/IntegrationController.php +++ b/app/Domain/Integrations/Controllers/IntegrationController.php @@ -10,6 +10,7 @@ use App\Domain\Contacts\Repositories\ContactKeyVisibilityRepository; use App\Domain\Contacts\Repositories\ContactRepository; use App\Domain\Coupons\Repositories\CouponRepository; +use App\Domain\Integrations\FormRequests\GetOrganizersRequest; use App\Domain\Integrations\FormRequests\RequestActivationRequest; use App\Domain\Integrations\FormRequests\StoreContactRequest; use App\Domain\Integrations\FormRequests\StoreIntegrationRequest; @@ -42,6 +43,7 @@ use App\Router\TranslatedRoute; use App\UiTiDv1\Repositories\UiTiDv1ConsumerRepository; use Carbon\Carbon; +use GuzzleHttp\Client; use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\UniqueConstraintViolationException; use Illuminate\Http\RedirectResponse; @@ -172,6 +174,7 @@ public function show(string $id): Response 'oldCredentialsExpirationDate' => $oldCredentialsExpirationDate, 'email' => Auth::user()?->email, 'subscriptions' => $this->subscriptionRepository->all(), + 'organizers' => session('organizers'), ]); } @@ -311,6 +314,34 @@ public function storeKeyVisibilityUpgrade(string $id, KeyVisibilityUpgradeReques ); } + public function getOrganizers(string $id, GetOrganizersRequest $request): RedirectResponse + { + $organizerName = $request->input('organizer'); + $apiKey = config('search.api_key'); + $baseUrl = config('search.base_uri'); + $endpoint = 'organizers'; + $client = new Client(); + try { + $response = $client->request('GET', $baseUrl . $endpoint, [ + 'query' => [ + 'embed' => 'true', + 'limit' => 5, + 'apiKey' => $apiKey, + 'name' => $organizerName, + ], + ]); + $body = $response->getBody()->getContents(); + $data = json_decode($body, true); + $organizerNames = array_map(function ($member) { + return $member['name'] ?? []; + }, $data['member']); + return redirect()->back()->with('organizers', $organizerNames); + + } catch (\Exception $e) { + return redirect()->back()->withErrors('Failed to fetch organizers: ' . $e->getMessage()); + } + } + private function getKeyVisibility(Integration $integration): KeyVisibility { $contacts = new Collection($integration->contacts()); From 25635aeff3199c66ba28b22cee213b53e0e6b5b4 Mon Sep 17 00:00:00 2001 From: vhande Date: Wed, 19 Jun 2024 13:26:28 +0200 Subject: [PATCH 02/42] Create GetOrganizersRequest.php --- .../FormRequests/GetOrganizersRequest.php | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 app/Domain/Integrations/FormRequests/GetOrganizersRequest.php diff --git a/app/Domain/Integrations/FormRequests/GetOrganizersRequest.php b/app/Domain/Integrations/FormRequests/GetOrganizersRequest.php new file mode 100644 index 000000000..49d1882f2 --- /dev/null +++ b/app/Domain/Integrations/FormRequests/GetOrganizersRequest.php @@ -0,0 +1,20 @@ + + */ + public function rules(): array + { + return [ + 'organizer' => ['required', 'string'], + ]; + } +} From 4159067194db26189cc5c8a29f888838ae3c2b49 Mon Sep 17 00:00:00 2001 From: vhande Date: Wed, 19 Jun 2024 13:29:58 +0200 Subject: [PATCH 03/42] Modify UITPAS integration rules --- .../FormRequests/RequestActivationRequest.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/app/Domain/Integrations/FormRequests/RequestActivationRequest.php b/app/Domain/Integrations/FormRequests/RequestActivationRequest.php index 7258a3be5..599d7fbea 100644 --- a/app/Domain/Integrations/FormRequests/RequestActivationRequest.php +++ b/app/Domain/Integrations/FormRequests/RequestActivationRequest.php @@ -24,12 +24,18 @@ public function rules(): array $rules = collect([ ...(new CreateOrganizationRequest())->rules(), 'coupon' => ['nullable', 'string', 'max:255'], + 'organizers' => ['required','array'], + 'organizers.*' => ['string'], ]); - if (!$this->isAccountingInfoRequired()) { + if (!$this->isAccountingInfoRequired() || $this->isUITPAS()) { $rules->forget(['organization.invoiceEmail', 'organization.vat', 'coupon']); } + if (!$this->isUITPAS()) { + $rules->forget(['organizers']); + } + return $rules->toArray(); } @@ -45,4 +51,12 @@ private function isAccountingInfoRequired(): bool return $integration->type !== IntegrationType::EntryApi || $subscription->price > 0.0; } + + private function isUITPAS(): bool + { + /** @var IntegrationRepository $integrationRepository */ + $integrationRepository = App::get(IntegrationRepository::class); + $integration = $integrationRepository->getById(Uuid::fromString($this->id)); + return $integration->type === IntegrationType::UiTPAS; + } } From 5d59592c8988323f0b627f4ba5a4d6a8ffc13657 Mon Sep 17 00:00:00 2001 From: vhande Date: Wed, 19 Jun 2024 13:30:12 +0200 Subject: [PATCH 04/42] Add validation organizers --- lang/en/validation.php | 1 + lang/nl/validation.php | 1 + 2 files changed, 2 insertions(+) diff --git a/lang/en/validation.php b/lang/en/validation.php index 01d7332cf..05732014d 100644 --- a/lang/en/validation.php +++ b/lang/en/validation.php @@ -196,6 +196,7 @@ 'organization.address.zip' => 'postcode', 'organization.address.city' => 'city', 'organization.vat' => 'VAT or company number', + 'organizers' => 'organizers' ], ]; diff --git a/lang/nl/validation.php b/lang/nl/validation.php index 53eaa9c61..3b99a8642 100644 --- a/lang/nl/validation.php +++ b/lang/nl/validation.php @@ -211,6 +211,7 @@ 'organization.address.zip' => 'postcode', 'organization.address.city' => 'gemeente', 'organization.vat' => 'BTW of ondernemingsnummer', + 'organizers' => 'organisaties' ], ]; From dd7c27a85879308b754772545be545390e076e90 Mon Sep 17 00:00:00 2001 From: vhande Date: Wed, 19 Jun 2024 13:30:32 +0200 Subject: [PATCH 05/42] Add translations uitpas activation --- resources/translations/en.json | 8 ++++++++ resources/translations/nl.json | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/resources/translations/en.json b/resources/translations/en.json index 6cf490257..d20282997 100644 --- a/resources/translations/en.json +++ b/resources/translations/en.json @@ -184,6 +184,14 @@ "coupon": "Coupon", "plan": "Subscription", "year": "year" + }, + "uitpas": { + "partner": "Partner", + "organizers": { + "title": "UiTdatabank organizers", + "info": "Enter the UiTdatabank organizers for which you want to execute actions in UiTPAS.", + "label": "Organizers" + } } }, "documentation": { diff --git a/resources/translations/nl.json b/resources/translations/nl.json index 2e1ee65a0..dbe865953 100644 --- a/resources/translations/nl.json +++ b/resources/translations/nl.json @@ -184,6 +184,14 @@ "coupon": "Coupon", "plan": "Abonnement", "year": "jaar" + }, + "uitpas": { + "partner": "Partner", + "organizers": { + "title": "UiTdatabank organisaties", + "info": "Geef de UiTdatabank organisaties op waarvoor je acties in UiTPAS wilt uitvoeren.", + "label": "Organisaties" + } } }, "documentation": { From 1dd1912c557ab35f064a19b78f9c457d7e6cd253 Mon Sep 17 00:00:00 2001 From: vhande Date: Wed, 19 Jun 2024 13:31:20 +0200 Subject: [PATCH 06/42] Add organizers to the activation dialog --- resources/ts/Components/ActivationDialog.tsx | 162 ++++++++++++++++++- 1 file changed, 157 insertions(+), 5 deletions(-) diff --git a/resources/ts/Components/ActivationDialog.tsx b/resources/ts/Components/ActivationDialog.tsx index 3c1cafb06..f67f94aec 100644 --- a/resources/ts/Components/ActivationDialog.tsx +++ b/resources/ts/Components/ActivationDialog.tsx @@ -1,10 +1,10 @@ -import React, { useContext } from "react"; +import React, { useContext, useMemo, useState } from "react"; import { Dialog } from "./Dialog"; import { ButtonSecondary } from "./ButtonSecondary"; import { ButtonPrimary } from "./ButtonPrimary"; import { FormElement } from "./FormElement"; import { Input } from "./Input"; -import { useForm } from "@inertiajs/react"; +import { router, useForm } from "@inertiajs/react"; import { useTranslation } from "react-i18next"; import { IntegrationType } from "../types/IntegrationType"; import { useIsMobile } from "../hooks/useIsMobile"; @@ -13,6 +13,9 @@ import type { PricingPlan } from "../hooks/useGetPricingPlans"; import { formatCurrency } from "../utils/formatCurrency"; import { Heading } from "./Heading"; import { CouponInfoContext } from "../Context/CouponInfo"; +import { faTrash } from "@fortawesome/free-solid-svg-icons"; +import { ButtonIcon } from "./ButtonIcon"; +import { debounce } from "lodash"; const PriceOverview = ({ coupon, @@ -81,6 +84,26 @@ type Props = { email: string; }; +type Address = { + street: string; + zip: string; + city: string; + country: string; +}; + +type Organization = { + name: string; + invoiceEmail: string; + vat: string; + address: Address; +}; + +type InitialValues = { + organization: Organization; + organizers: string[]; + coupon: string; +}; + export const ActivationDialog = ({ isVisible, onClose, @@ -93,7 +116,7 @@ export const ActivationDialog = ({ const isMobile = useIsMobile(); - const initialValuesOrganization = { + const initialValuesOrganization: InitialValues = { organization: { name: "", invoiceEmail: "", @@ -105,6 +128,7 @@ export const ActivationDialog = ({ country: "Belgium", }, }, + organizers: [], coupon: "", }; @@ -121,6 +145,60 @@ export const ActivationDialog = ({ string | undefined >; + const isBillingInfoAndPriceOverviewVisible = + type !== IntegrationType.EntryApi && type !== IntegrationType.UiTPAS; + + const [isSearchListVisible, setIsSearchListVisible] = useState(false); + + const [organizerList, setOrganizerList] = useState([]); + + const handleGetOrganizers = debounce( + (e: React.ChangeEvent) => { + setOrganizerList([]); + router.post( + `/integrations/${id}/organizers`, + { + organizer: e.target.value, + }, + { + preserveScroll: true, + preserveState: true, + onSuccess: (page) => { + if (Array.isArray(page.props.organizers)) { + const organizers = page.props.organizers.map((organizer) => { + if (typeof organizer === "object" && "nl" in organizer) { + return organizer.nl; + } + return organizer; + }); + setOrganizerList(organizers); + } + }, + onError: (errors) => { + console.error(errors); + }, + } + ); + }, + 250 + ); + + const handleAddOrganizers = (e: React.MouseEvent) => { + const target = e.target as HTMLLIElement; + const newOrganizer = target.innerText; + let updatedOrganizers = [...organizationForm.data.organizers, newOrganizer]; + updatedOrganizers = [...new Set(updatedOrganizers)]; + organizationForm.setData("organizers", updatedOrganizers); + setIsSearchListVisible(false); + }; + + const handleDeleteOrganizer = (deletedOrganizer: string) => { + const updatedOrganizers = organizationForm.data.organizers.filter( + (organizer) => organizer !== deletedOrganizer + ); + organizationForm.setData("organizers", updatedOrganizers); + }; + if (!isVisible) { return null; } @@ -144,6 +222,11 @@ export const ActivationDialog = ({ contentStyles="gap-3" > <> + {type === IntegrationType.UiTPAS && ( + + {t("integrations.activation_dialog.uitpas.partner")} + + )} - {type !== IntegrationType.EntryApi && ( + {type === IntegrationType.UiTPAS && ( + <> +
+ + {t("integrations.activation_dialog.uitpas.organizers.title")} + + + {t("integrations.activation_dialog.uitpas.organizers.info")} + +
+
+ {organizationForm.data.organizers.length > 0 && + organizationForm.data.organizers.map((organizer) => ( +
+

{organizer}

+ handleDeleteOrganizer(organizer)} + /> +
+ ))} +
+ + { + e.target.value !== "" + ? (setIsSearchListVisible(true), handleGetOrganizers(e)) + : setIsSearchListVisible(false); + }} + onBlur={(e) => { + e.target.value = ""; + const timeoutId = setTimeout(() => { + setIsSearchListVisible(false); + clearTimeout(timeoutId); + }, 200); + }} + /> + {organizerList && + organizerList.length > 0 && + isSearchListVisible && ( +
    + {organizerList.map((organizer, index) => ( +
  • + {organizer} +
  • + ))} +
+ )} + + } + /> + + )} + {isBillingInfoAndPriceOverviewVisible && ( <> )} - {type !== IntegrationType.EntryApi && ( + {isBillingInfoAndPriceOverviewVisible && ( Date: Wed, 19 Jun 2024 13:31:38 +0200 Subject: [PATCH 07/42] Update styling --- resources/ts/Components/ButtonIcon.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/ts/Components/ButtonIcon.tsx b/resources/ts/Components/ButtonIcon.tsx index 7c75edac2..b652b14b1 100644 --- a/resources/ts/Components/ButtonIcon.tsx +++ b/resources/ts/Components/ButtonIcon.tsx @@ -23,6 +23,7 @@ export const ButtonIcon = ({ className={twMerge( classNames( "hover:bg-icon-gray-light focus:bg-icon-gray-dark group-focus:animate-pulse p-3 rounded-full grow-0 shrink-0 w-[2.8rem] h-[2.8rem] inline-flex items-center justify-center", + size === "sm" && "w-[1.2rem] h-[1.2rem]", className ) )} From d786366a291e6410ddfa1ff90253d7e64045a668 Mon Sep 17 00:00:00 2001 From: vhande Date: Wed, 19 Jun 2024 13:31:58 +0200 Subject: [PATCH 08/42] Add route organizers --- routes/web.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/routes/web.php b/routes/web.php index b831e7478..e32d1d589 100644 --- a/routes/web.php +++ b/routes/web.php @@ -98,6 +98,8 @@ Route::get('/integrations/{id}/widget', [IntegrationController::class, 'showWidget']); Route::post('/integrations/{id}/upgrade', [IntegrationController::class, 'storeKeyVisibilityUpgrade']); + + Route::post('/integrations/{id}/organizers', [IntegrationController::class, 'getOrganizers']); }); Route::fallback(function () { From 9ed7a86f9d2b2041e736fa089b4cd8f3f581c6fc Mon Sep 17 00:00:00 2001 From: vhande Date: Wed, 19 Jun 2024 15:08:02 +0200 Subject: [PATCH 09/42] Fix linting --- resources/ts/Components/ActivationDialog.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/resources/ts/Components/ActivationDialog.tsx b/resources/ts/Components/ActivationDialog.tsx index f67f94aec..9adecb575 100644 --- a/resources/ts/Components/ActivationDialog.tsx +++ b/resources/ts/Components/ActivationDialog.tsx @@ -1,4 +1,4 @@ -import React, { useContext, useMemo, useState } from "react"; +import React, { useContext, useState } from "react"; import { Dialog } from "./Dialog"; import { ButtonSecondary } from "./ButtonSecondary"; import { ButtonPrimary } from "./ButtonPrimary"; @@ -330,8 +330,11 @@ export const ActivationDialog = ({
{organizationForm.data.organizers.length > 0 && - organizationForm.data.organizers.map((organizer) => ( -
+ organizationForm.data.organizers.map((organizer, index) => ( +

{organizer}

Date: Mon, 24 Jun 2024 10:36:17 +0200 Subject: [PATCH 10/42] Add organizer object --- .../Controllers/IntegrationController.php | 12 ++++-- resources/ts/Components/ActivationDialog.tsx | 38 +++++++++++-------- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/app/Domain/Integrations/Controllers/IntegrationController.php b/app/Domain/Integrations/Controllers/IntegrationController.php index 4b122eb6f..732b2da95 100644 --- a/app/Domain/Integrations/Controllers/IntegrationController.php +++ b/app/Domain/Integrations/Controllers/IntegrationController.php @@ -332,10 +332,16 @@ public function getOrganizers(string $id, GetOrganizersRequest $request): Redire ]); $body = $response->getBody()->getContents(); $data = json_decode($body, true); - $organizerNames = array_map(function ($member) { - return $member['name'] ?? []; + $organizers = array_map(function ($member) { + $id = null; + if (isset($member['@id'])) { + $parts = explode('/', $member['@id']); + $id = end($parts); + } + $name = $member['name'] ?? null; + return ['name' => $name, 'id' => $id]; }, $data['member']); - return redirect()->back()->with('organizers', $organizerNames); + return redirect()->back()->with('organizers', $organizers); } catch (\Exception $e) { return redirect()->back()->withErrors('Failed to fetch organizers: ' . $e->getMessage()); diff --git a/resources/ts/Components/ActivationDialog.tsx b/resources/ts/Components/ActivationDialog.tsx index 9adecb575..a101bf10b 100644 --- a/resources/ts/Components/ActivationDialog.tsx +++ b/resources/ts/Components/ActivationDialog.tsx @@ -1,4 +1,4 @@ -import React, { useContext, useState } from "react"; +import React, { useContext, useEffect, useState } from "react"; import { Dialog } from "./Dialog"; import { ButtonSecondary } from "./ButtonSecondary"; import { ButtonPrimary } from "./ButtonPrimary"; @@ -100,10 +100,15 @@ type Organization = { type InitialValues = { organization: Organization; - organizers: string[]; + organizers: Organizer[]; coupon: string; }; +type Organizer = { + name: string; + id: string; +}; + export const ActivationDialog = ({ isVisible, onClose, @@ -150,7 +155,7 @@ export const ActivationDialog = ({ const [isSearchListVisible, setIsSearchListVisible] = useState(false); - const [organizerList, setOrganizerList] = useState([]); + const [organizerList, setOrganizerList] = useState([]); const handleGetOrganizers = debounce( (e: React.ChangeEvent) => { @@ -166,8 +171,11 @@ export const ActivationDialog = ({ onSuccess: (page) => { if (Array.isArray(page.props.organizers)) { const organizers = page.props.organizers.map((organizer) => { - if (typeof organizer === "object" && "nl" in organizer) { - return organizer.nl; + if ( + typeof organizer.name === "object" && + "nl" in organizer.name + ) { + return { name: organizer.name.nl, id: organizer.id }; } return organizer; }); @@ -183,10 +191,8 @@ export const ActivationDialog = ({ 250 ); - const handleAddOrganizers = (e: React.MouseEvent) => { - const target = e.target as HTMLLIElement; - const newOrganizer = target.innerText; - let updatedOrganizers = [...organizationForm.data.organizers, newOrganizer]; + const handleAddOrganizers = (organizer: Organizer) => { + let updatedOrganizers = [...organizationForm.data.organizers, organizer]; updatedOrganizers = [...new Set(updatedOrganizers)]; organizationForm.setData("organizers", updatedOrganizers); setIsSearchListVisible(false); @@ -194,7 +200,7 @@ export const ActivationDialog = ({ const handleDeleteOrganizer = (deletedOrganizer: string) => { const updatedOrganizers = organizationForm.data.organizers.filter( - (organizer) => organizer !== deletedOrganizer + (organizer) => organizer.name !== deletedOrganizer ); organizationForm.setData("organizers", updatedOrganizers); }; @@ -335,12 +341,12 @@ export const ActivationDialog = ({ key={`${organizer}${index}`} className="border rounded px-2 py-1 flex gap-1" > -

{organizer}

+

{organizer.name}

handleDeleteOrganizer(organizer)} + onClick={() => handleDeleteOrganizer(organizer.name)} />
))} @@ -374,13 +380,13 @@ export const ActivationDialog = ({ organizerList.length > 0 && isSearchListVisible && (
    - {organizerList.map((organizer, index) => ( + {organizerList.map((organizer) => (
  • handleAddOrganizers(organizer)} className="border-b px-3 py-1 hover:bg-gray-100" > - {organizer} + {organizer.name}
  • ))}
From 99ce6a97b941b05a5c079a84ed0c2d4889bc9c6f Mon Sep 17 00:00:00 2001 From: vhande Date: Mon, 24 Jun 2024 10:37:41 +0200 Subject: [PATCH 11/42] Change route get --- resources/ts/Components/ActivationDialog.tsx | 2 +- routes/web.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/ts/Components/ActivationDialog.tsx b/resources/ts/Components/ActivationDialog.tsx index a101bf10b..0b44dbb3c 100644 --- a/resources/ts/Components/ActivationDialog.tsx +++ b/resources/ts/Components/ActivationDialog.tsx @@ -160,7 +160,7 @@ export const ActivationDialog = ({ const handleGetOrganizers = debounce( (e: React.ChangeEvent) => { setOrganizerList([]); - router.post( + router.get( `/integrations/${id}/organizers`, { organizer: e.target.value, diff --git a/routes/web.php b/routes/web.php index e32d1d589..c7757fa65 100644 --- a/routes/web.php +++ b/routes/web.php @@ -99,7 +99,7 @@ Route::post('/integrations/{id}/upgrade', [IntegrationController::class, 'storeKeyVisibilityUpgrade']); - Route::post('/integrations/{id}/organizers', [IntegrationController::class, 'getOrganizers']); + Route::get('/integrations/{id}/organizers', [IntegrationController::class, 'getOrganizers']); }); Route::fallback(function () { From 850dfb1db03752457bbf7215b254b2e08e1c8981 Mon Sep 17 00:00:00 2001 From: vhande Date: Mon, 24 Jun 2024 10:39:40 +0200 Subject: [PATCH 12/42] Fix linting --- resources/ts/Components/ActivationDialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/ts/Components/ActivationDialog.tsx b/resources/ts/Components/ActivationDialog.tsx index 0b44dbb3c..d217b77e3 100644 --- a/resources/ts/Components/ActivationDialog.tsx +++ b/resources/ts/Components/ActivationDialog.tsx @@ -1,4 +1,4 @@ -import React, { useContext, useEffect, useState } from "react"; +import React, { useContext, useState } from "react"; import { Dialog } from "./Dialog"; import { ButtonSecondary } from "./ButtonSecondary"; import { ButtonPrimary } from "./ButtonPrimary"; From 6451864eaf75d8ceb377d8a3c59bc958ac286b65 Mon Sep 17 00:00:00 2001 From: vhande Date: Mon, 24 Jun 2024 10:49:58 +0200 Subject: [PATCH 13/42] Change rule --- .../Integrations/FormRequests/RequestActivationRequest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Domain/Integrations/FormRequests/RequestActivationRequest.php b/app/Domain/Integrations/FormRequests/RequestActivationRequest.php index 599d7fbea..ac7923fbe 100644 --- a/app/Domain/Integrations/FormRequests/RequestActivationRequest.php +++ b/app/Domain/Integrations/FormRequests/RequestActivationRequest.php @@ -25,7 +25,8 @@ public function rules(): array ...(new CreateOrganizationRequest())->rules(), 'coupon' => ['nullable', 'string', 'max:255'], 'organizers' => ['required','array'], - 'organizers.*' => ['string'], + 'organizers.*.name' => ['required', 'string'], + 'organizers.*.id' => ['required', 'string'], ]); if (!$this->isAccountingInfoRequired() || $this->isUITPAS()) { From ebbad235d2043098716841ede2ea6b035253d6a9 Mon Sep 17 00:00:00 2001 From: vhande Date: Mon, 24 Jun 2024 10:58:07 +0200 Subject: [PATCH 14/42] Save organizers --- .../Controllers/IntegrationController.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/app/Domain/Integrations/Controllers/IntegrationController.php b/app/Domain/Integrations/Controllers/IntegrationController.php index 732b2da95..2541ed35a 100644 --- a/app/Domain/Integrations/Controllers/IntegrationController.php +++ b/app/Domain/Integrations/Controllers/IntegrationController.php @@ -32,8 +32,10 @@ use App\Domain\Integrations\Mappers\UpdateContactInfoMapper; use App\Domain\Integrations\Mappers\UpdateIntegrationMapper; use App\Domain\Integrations\Mappers\UpdateIntegrationUrlsMapper; +use App\Domain\Integrations\Organizer; use App\Domain\Integrations\Repositories\IntegrationRepository; use App\Domain\Integrations\Repositories\IntegrationUrlRepository; +use App\Domain\Integrations\Repositories\OrganizerRepository; use App\Domain\KeyVisibilityUpgrades\KeyVisibilityUpgrade; use App\Domain\Organizations\Repositories\OrganizationRepository; use App\Domain\Subscriptions\Repositories\SubscriptionRepository; @@ -65,6 +67,7 @@ public function __construct( private readonly ContactRepository $contactRepository, private readonly ContactKeyVisibilityRepository $contactKeyVisibilityRepository, private readonly OrganizationRepository $organizationRepository, + private readonly OrganizerRepository $organizerRepository, private readonly CouponRepository $couponRepository, private readonly Auth0ClientRepository $auth0ClientRepository, private readonly UiTiDv1ConsumerRepository $uitidV1ConsumerRepository, @@ -291,6 +294,17 @@ public function requestActivation(string $id, RequestActivationRequest $request) $organization = OrganizationMapper::mapActivationRequest($request); $this->organizationRepository->save($organization); + $organizers = $request->input('organizers') ?? []; + foreach ($organizers as $organizer) { + $organizer = new Organizer( + Uuid::uuid4(), + Uuid::fromString($id), + Uuid::fromString($organizer['id']) + ); + + $this->organizerRepository->create($organizer); + } + $this->integrationRepository->requestActivation(Uuid::fromString($id), $organization->id, $request->input('coupon')); return Redirect::back(); From c34de556c02088b5b2ff32c839a1bbb8e47eb41f Mon Sep 17 00:00:00 2001 From: vhande Date: Mon, 24 Jun 2024 13:13:15 +0200 Subject: [PATCH 15/42] Update handleAddOrganizers --- resources/ts/Components/ActivationDialog.tsx | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/resources/ts/Components/ActivationDialog.tsx b/resources/ts/Components/ActivationDialog.tsx index d217b77e3..5282bfc23 100644 --- a/resources/ts/Components/ActivationDialog.tsx +++ b/resources/ts/Components/ActivationDialog.tsx @@ -192,10 +192,18 @@ export const ActivationDialog = ({ ); const handleAddOrganizers = (organizer: Organizer) => { - let updatedOrganizers = [...organizationForm.data.organizers, organizer]; - updatedOrganizers = [...new Set(updatedOrganizers)]; - organizationForm.setData("organizers", updatedOrganizers); - setIsSearchListVisible(false); + const isDuplicate = + organizationForm.data.organizers.length > 0 && + organizationForm.data.organizers.some( + (existingOrganizer) => existingOrganizer.id === organizer.id + ); + if (!isDuplicate) { + organizationForm.setData("organizers", [ + ...organizationForm.data.organizers, + organizer, + ]); + setIsSearchListVisible(false); + } }; const handleDeleteOrganizer = (deletedOrganizer: string) => { From c5b01680c1f1397bacd35013b7af09fc8afe8dfc Mon Sep 17 00:00:00 2001 From: vhande Date: Tue, 25 Jun 2024 03:02:46 +0200 Subject: [PATCH 16/42] Use search service --- .../Controllers/IntegrationController.php | 33 +++++++------------ 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/app/Domain/Integrations/Controllers/IntegrationController.php b/app/Domain/Integrations/Controllers/IntegrationController.php index 2541ed35a..dfcd2dfba 100644 --- a/app/Domain/Integrations/Controllers/IntegrationController.php +++ b/app/Domain/Integrations/Controllers/IntegrationController.php @@ -43,9 +43,9 @@ use App\Http\Controllers\Controller; use App\ProjectAanvraag\ProjectAanvraagUrl; use App\Router\TranslatedRoute; +use App\Search\Sapi3\SearchService; use App\UiTiDv1\Repositories\UiTiDv1ConsumerRepository; use Carbon\Carbon; -use GuzzleHttp\Client; use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\UniqueConstraintViolationException; use Illuminate\Http\RedirectResponse; @@ -72,7 +72,8 @@ public function __construct( private readonly Auth0ClientRepository $auth0ClientRepository, private readonly UiTiDv1ConsumerRepository $uitidV1ConsumerRepository, private readonly KeyVisibilityUpgradeRepository $keyVisibilityUpgradeRepository, - private readonly CurrentUser $currentUser + private readonly CurrentUser $currentUser, + private readonly SearchService $searchService ) { } @@ -330,31 +331,19 @@ public function storeKeyVisibilityUpgrade(string $id, KeyVisibilityUpgradeReques public function getOrganizers(string $id, GetOrganizersRequest $request): RedirectResponse { - $organizerName = $request->input('organizer'); - $apiKey = config('search.api_key'); - $baseUrl = config('search.base_uri'); - $endpoint = 'organizers'; - $client = new Client(); try { - $response = $client->request('GET', $baseUrl . $endpoint, [ - 'query' => [ - 'embed' => 'true', - 'limit' => 5, - 'apiKey' => $apiKey, - 'name' => $organizerName, - ], - ]); - $body = $response->getBody()->getContents(); - $data = json_decode($body, true); - $organizers = array_map(function ($member) { + $organizerName = $request->input('organizer'); + $data = $this->searchService->searchUiTPASOrganizer($organizerName)->getMember()->getItems(); + $organizers = array_map(function ($organizer) { $id = null; - if (isset($member['@id'])) { - $parts = explode('/', $member['@id']); + if (($organizer->getId())) { + $parts = explode('/', $organizer->getId()); $id = end($parts); } - $name = $member['name'] ?? null; + $name = $organizer->getName()->getValues() ?? null; return ['name' => $name, 'id' => $id]; - }, $data['member']); + }, $data); + return redirect()->back()->with('organizers', $organizers); } catch (\Exception $e) { From 38d5dd6b1a4222db96dc635a83bfe10e868e9ed2 Mon Sep 17 00:00:00 2001 From: vhande Date: Tue, 25 Jun 2024 03:03:09 +0200 Subject: [PATCH 17/42] Add limit --- app/Search/Sapi3/Sapi3SearchService.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Search/Sapi3/Sapi3SearchService.php b/app/Search/Sapi3/Sapi3SearchService.php index fb169697b..0eed9268b 100644 --- a/app/Search/Sapi3/Sapi3SearchService.php +++ b/app/Search/Sapi3/Sapi3SearchService.php @@ -20,6 +20,7 @@ public function searchUiTPASOrganizer(string $name): PagedCollection $searchQuery = new SearchQuery(); $searchQuery->addParameter(new Label('UiTPAS')); $searchQuery->addParameter(new Name($name)); + $searchQuery->setLimit(5); $searchQuery->setEmbed(true); return $this->searchClient->searchOrganizers($searchQuery); From e4045cf4651bcda79b309825face0ec965e61f9c Mon Sep 17 00:00:00 2001 From: vhande Date: Tue, 25 Jun 2024 03:11:15 +0200 Subject: [PATCH 18/42] Fix stan --- app/Domain/Integrations/Controllers/IntegrationController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Domain/Integrations/Controllers/IntegrationController.php b/app/Domain/Integrations/Controllers/IntegrationController.php index dfcd2dfba..153b3e5a1 100644 --- a/app/Domain/Integrations/Controllers/IntegrationController.php +++ b/app/Domain/Integrations/Controllers/IntegrationController.php @@ -333,7 +333,7 @@ public function getOrganizers(string $id, GetOrganizersRequest $request): Redire { try { $organizerName = $request->input('organizer'); - $data = $this->searchService->searchUiTPASOrganizer($organizerName)->getMember()->getItems(); + $data = $this->searchService->searchUiTPASOrganizer($organizerName)->getMember()?->getItems() ?? []; $organizers = array_map(function ($organizer) { $id = null; if (($organizer->getId())) { From d173e1b943edc93d87acd41a55441447cf15fd38 Mon Sep 17 00:00:00 2001 From: Luc Wollants Date: Tue, 25 Jun 2024 11:54:20 +0200 Subject: [PATCH 19/42] Move `getOrganizers` to dedicated controller --- .../Controllers/OrganizerController.php | 39 +++++++++++++++++++ routes/web.php | 5 ++- 2 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 app/Domain/Integrations/Controllers/OrganizerController.php diff --git a/app/Domain/Integrations/Controllers/OrganizerController.php b/app/Domain/Integrations/Controllers/OrganizerController.php new file mode 100644 index 000000000..c39417f8f --- /dev/null +++ b/app/Domain/Integrations/Controllers/OrganizerController.php @@ -0,0 +1,39 @@ +input('name'); + + $data = $this->searchService->searchUiTPASOrganizer($organizerName)->getMember()?->getItems() ?? []; + + $organizers = array_map(function (Organizer $organizer) { + return [ + 'id' => $organizer->getCdbid(), + 'name' => $organizer->getName()->getValues() ?? null, + ]; + }, $data); + + return redirect()->back()->with('organizers', $organizers); + + } catch (\Exception $e) { + return redirect()->back()->withErrors('Failed to fetch organizers: ' . $e->getMessage()); + } + } +} diff --git a/routes/web.php b/routes/web.php index c7757fa65..5326d6e04 100644 --- a/routes/web.php +++ b/routes/web.php @@ -6,6 +6,7 @@ use App\Domain\Auth\Controllers\LoginController; use App\Domain\Auth\Controllers\LogoutController; use App\Domain\Integrations\Controllers\IntegrationController; +use App\Domain\Integrations\Controllers\OrganizerController; use App\Domain\Newsletter\Controllers\NewsletterController; use Illuminate\Support\Facades\Route; use App\Router\TranslatedRoute; @@ -71,6 +72,8 @@ Route::post('/integrations', [IntegrationController::class, 'store']); + Route::get('/organizers', [OrganizerController::class, 'getOrganizers']); + Route::group(['middleware' => 'can:access-integration,id'], static function () { TranslatedRoute::get( [ @@ -98,8 +101,6 @@ Route::get('/integrations/{id}/widget', [IntegrationController::class, 'showWidget']); Route::post('/integrations/{id}/upgrade', [IntegrationController::class, 'storeKeyVisibilityUpgrade']); - - Route::get('/integrations/{id}/organizers', [IntegrationController::class, 'getOrganizers']); }); Route::fallback(function () { From 362755b8ce12bbf5f0ca4cf046a93103648f0c42 Mon Sep 17 00:00:00 2001 From: Luc Wollants Date: Tue, 25 Jun 2024 11:54:45 +0200 Subject: [PATCH 20/42] Remove the `getOrganizers` from `IntegrationController` --- .../Controllers/IntegrationController.php | 25 +------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/app/Domain/Integrations/Controllers/IntegrationController.php b/app/Domain/Integrations/Controllers/IntegrationController.php index 153b3e5a1..d614cd731 100644 --- a/app/Domain/Integrations/Controllers/IntegrationController.php +++ b/app/Domain/Integrations/Controllers/IntegrationController.php @@ -72,8 +72,7 @@ public function __construct( private readonly Auth0ClientRepository $auth0ClientRepository, private readonly UiTiDv1ConsumerRepository $uitidV1ConsumerRepository, private readonly KeyVisibilityUpgradeRepository $keyVisibilityUpgradeRepository, - private readonly CurrentUser $currentUser, - private readonly SearchService $searchService + private readonly CurrentUser $currentUser ) { } @@ -329,28 +328,6 @@ public function storeKeyVisibilityUpgrade(string $id, KeyVisibilityUpgradeReques ); } - public function getOrganizers(string $id, GetOrganizersRequest $request): RedirectResponse - { - try { - $organizerName = $request->input('organizer'); - $data = $this->searchService->searchUiTPASOrganizer($organizerName)->getMember()?->getItems() ?? []; - $organizers = array_map(function ($organizer) { - $id = null; - if (($organizer->getId())) { - $parts = explode('/', $organizer->getId()); - $id = end($parts); - } - $name = $organizer->getName()->getValues() ?? null; - return ['name' => $name, 'id' => $id]; - }, $data); - - return redirect()->back()->with('organizers', $organizers); - - } catch (\Exception $e) { - return redirect()->back()->withErrors('Failed to fetch organizers: ' . $e->getMessage()); - } - } - private function getKeyVisibility(Integration $integration): KeyVisibility { $contacts = new Collection($integration->contacts()); From 039502e909b03e57cb72ed5fd9efcdd6531190ca Mon Sep 17 00:00:00 2001 From: Luc Wollants Date: Tue, 25 Jun 2024 11:55:17 +0200 Subject: [PATCH 21/42] Rename search parameter to `name` --- app/Domain/Integrations/FormRequests/GetOrganizersRequest.php | 2 +- resources/ts/Components/ActivationDialog.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Domain/Integrations/FormRequests/GetOrganizersRequest.php b/app/Domain/Integrations/FormRequests/GetOrganizersRequest.php index 49d1882f2..6ccad2338 100644 --- a/app/Domain/Integrations/FormRequests/GetOrganizersRequest.php +++ b/app/Domain/Integrations/FormRequests/GetOrganizersRequest.php @@ -14,7 +14,7 @@ final class GetOrganizersRequest extends FormRequest public function rules(): array { return [ - 'organizer' => ['required', 'string'], + 'name' => ['required', 'string'], ]; } } diff --git a/resources/ts/Components/ActivationDialog.tsx b/resources/ts/Components/ActivationDialog.tsx index 5282bfc23..8e6817d31 100644 --- a/resources/ts/Components/ActivationDialog.tsx +++ b/resources/ts/Components/ActivationDialog.tsx @@ -163,7 +163,7 @@ export const ActivationDialog = ({ router.get( `/integrations/${id}/organizers`, { - organizer: e.target.value, + name: e.target.value, }, { preserveScroll: true, From fc19b034a10d4b51e9199c3d9b5c7e8968ffb76d Mon Sep 17 00:00:00 2001 From: Luc Wollants Date: Tue, 25 Jun 2024 11:55:28 +0200 Subject: [PATCH 22/42] Use new `organizers` endpoint --- resources/ts/Components/ActivationDialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/ts/Components/ActivationDialog.tsx b/resources/ts/Components/ActivationDialog.tsx index 8e6817d31..aae90acc4 100644 --- a/resources/ts/Components/ActivationDialog.tsx +++ b/resources/ts/Components/ActivationDialog.tsx @@ -161,7 +161,7 @@ export const ActivationDialog = ({ (e: React.ChangeEvent) => { setOrganizerList([]); router.get( - `/integrations/${id}/organizers`, + `/organizers`, { name: e.target.value, }, From 0c21ea7b397b2944bbc64db410ed6edd270e32b6 Mon Sep 17 00:00:00 2001 From: Luc Wollants Date: Tue, 25 Jun 2024 12:00:25 +0200 Subject: [PATCH 23/42] Linting --- app/Domain/Integrations/Controllers/IntegrationController.php | 2 -- app/Domain/Integrations/Controllers/OrganizerController.php | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/app/Domain/Integrations/Controllers/IntegrationController.php b/app/Domain/Integrations/Controllers/IntegrationController.php index d614cd731..a37e6c18f 100644 --- a/app/Domain/Integrations/Controllers/IntegrationController.php +++ b/app/Domain/Integrations/Controllers/IntegrationController.php @@ -10,7 +10,6 @@ use App\Domain\Contacts\Repositories\ContactKeyVisibilityRepository; use App\Domain\Contacts\Repositories\ContactRepository; use App\Domain\Coupons\Repositories\CouponRepository; -use App\Domain\Integrations\FormRequests\GetOrganizersRequest; use App\Domain\Integrations\FormRequests\RequestActivationRequest; use App\Domain\Integrations\FormRequests\StoreContactRequest; use App\Domain\Integrations\FormRequests\StoreIntegrationRequest; @@ -43,7 +42,6 @@ use App\Http\Controllers\Controller; use App\ProjectAanvraag\ProjectAanvraagUrl; use App\Router\TranslatedRoute; -use App\Search\Sapi3\SearchService; use App\UiTiDv1\Repositories\UiTiDv1ConsumerRepository; use Carbon\Carbon; use Illuminate\Database\Eloquent\ModelNotFoundException; diff --git a/app/Domain/Integrations/Controllers/OrganizerController.php b/app/Domain/Integrations/Controllers/OrganizerController.php index c39417f8f..b380e7bd5 100644 --- a/app/Domain/Integrations/Controllers/OrganizerController.php +++ b/app/Domain/Integrations/Controllers/OrganizerController.php @@ -26,7 +26,7 @@ public function getOrganizers(GetOrganizersRequest $request): RedirectResponse $organizers = array_map(function (Organizer $organizer) { return [ 'id' => $organizer->getCdbid(), - 'name' => $organizer->getName()->getValues() ?? null, + 'name' => $organizer->getName()?->getValues(), ]; }, $data); From edcde23db1d29e8e71fb42404bd261caf1837a9c Mon Sep 17 00:00:00 2001 From: vhande Date: Wed, 26 Jun 2024 11:50:49 +0200 Subject: [PATCH 24/42] Use JsonResponse --- .../Controllers/OrganizerController.php | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/app/Domain/Integrations/Controllers/OrganizerController.php b/app/Domain/Integrations/Controllers/OrganizerController.php index b380e7bd5..b3f280994 100644 --- a/app/Domain/Integrations/Controllers/OrganizerController.php +++ b/app/Domain/Integrations/Controllers/OrganizerController.php @@ -8,7 +8,7 @@ use App\Http\Controllers\Controller; use App\Search\Sapi3\SearchService; use CultuurNet\SearchV3\ValueObjects\Organizer; -use Illuminate\Http\RedirectResponse; +use Illuminate\Http\JsonResponse; final class OrganizerController extends Controller { @@ -16,24 +16,28 @@ public function __construct(private readonly SearchService $searchService) { } - public function getOrganizers(GetOrganizersRequest $request): RedirectResponse + public function getOrganizers(GetOrganizersRequest $request): JsonResponse { try { $organizerName = $request->input('name'); $data = $this->searchService->searchUiTPASOrganizer($organizerName)->getMember()?->getItems() ?? []; - $organizers = array_map(function (Organizer $organizer) { - return [ - 'id' => $organizer->getCdbid(), - 'name' => $organizer->getName()?->getValues(), - ]; - }, $data); - - return redirect()->back()->with('organizers', $organizers); + return new JsonResponse( + array_map(function (Organizer $organizer) { + return [ + 'id' => $organizer->getCdbid(), + 'name' => $organizer->getName()?->getValues(), + ]; + }, $data) + ); } catch (\Exception $e) { - return redirect()->back()->withErrors('Failed to fetch organizers: ' . $e->getMessage()); + return new JsonResponse( + ['exception' => $e->getMessage()], + 500 + ); + ; } } } From 364fda116c8ca4529cfa84fe94d1002c17a74dbe Mon Sep 17 00:00:00 2001 From: vhande Date: Wed, 26 Jun 2024 11:51:38 +0200 Subject: [PATCH 25/42] Use fetch --- resources/ts/Components/ActivationDialog.tsx | 49 +++++++------------- 1 file changed, 18 insertions(+), 31 deletions(-) diff --git a/resources/ts/Components/ActivationDialog.tsx b/resources/ts/Components/ActivationDialog.tsx index aae90acc4..5465ef250 100644 --- a/resources/ts/Components/ActivationDialog.tsx +++ b/resources/ts/Components/ActivationDialog.tsx @@ -4,7 +4,7 @@ import { ButtonSecondary } from "./ButtonSecondary"; import { ButtonPrimary } from "./ButtonPrimary"; import { FormElement } from "./FormElement"; import { Input } from "./Input"; -import { router, useForm } from "@inertiajs/react"; +import { useForm } from "@inertiajs/react"; import { useTranslation } from "react-i18next"; import { IntegrationType } from "../types/IntegrationType"; import { useIsMobile } from "../hooks/useIsMobile"; @@ -158,35 +158,19 @@ export const ActivationDialog = ({ const [organizerList, setOrganizerList] = useState([]); const handleGetOrganizers = debounce( - (e: React.ChangeEvent) => { + async (e: React.ChangeEvent) => { setOrganizerList([]); - router.get( - `/organizers`, - { - name: e.target.value, - }, - { - preserveScroll: true, - preserveState: true, - onSuccess: (page) => { - if (Array.isArray(page.props.organizers)) { - const organizers = page.props.organizers.map((organizer) => { - if ( - typeof organizer.name === "object" && - "nl" in organizer.name - ) { - return { name: organizer.name.nl, id: organizer.id }; - } - return organizer; - }); - setOrganizerList(organizers); - } - }, - onError: (errors) => { - console.error(errors); - }, + const response = await fetch(`/organizers?name=${e.target.value}`); + const data = await response.json(); + const organizers = data.map( + (organizer: { name: string | { nl: string }; id: string }) => { + if (typeof organizer.name === "object" && "nl" in organizer.name) { + return { name: organizer.name.nl, id: organizer.id }; + } + return organizer; } ); + setOrganizerList(organizers); }, 250 ); @@ -371,10 +355,13 @@ export const ActivationDialog = ({ { - e.target.value !== "" - ? (setIsSearchListVisible(true), handleGetOrganizers(e)) - : setIsSearchListVisible(false); + onChange={async (e) => { + if (e.target.value !== "") { + await handleGetOrganizers(e); + setIsSearchListVisible(true); + } else { + setIsSearchListVisible(false); + } }} onBlur={(e) => { e.target.value = ""; From 2f6f67ea1389c06788ac7de11300dff8a90172b1 Mon Sep 17 00:00:00 2001 From: vhande Date: Wed, 26 Jun 2024 14:28:48 +0200 Subject: [PATCH 26/42] Create type UiTPASOrganizer --- resources/ts/Components/ActivationDialog.tsx | 25 ++++---------------- resources/ts/types/UiTPASOrganizer.ts | 4 ++++ 2 files changed, 8 insertions(+), 21 deletions(-) create mode 100644 resources/ts/types/UiTPASOrganizer.ts diff --git a/resources/ts/Components/ActivationDialog.tsx b/resources/ts/Components/ActivationDialog.tsx index 5465ef250..32774d583 100644 --- a/resources/ts/Components/ActivationDialog.tsx +++ b/resources/ts/Components/ActivationDialog.tsx @@ -16,6 +16,8 @@ import { CouponInfoContext } from "../Context/CouponInfo"; import { faTrash } from "@fortawesome/free-solid-svg-icons"; import { ButtonIcon } from "./ButtonIcon"; import { debounce } from "lodash"; +import { Organization } from "../types/Organization"; +import { UiTPASOrganizer } from "../types/UitpasOrganizer"; const PriceOverview = ({ coupon, @@ -84,31 +86,12 @@ type Props = { email: string; }; -type Address = { - street: string; - zip: string; - city: string; - country: string; -}; - -type Organization = { - name: string; - invoiceEmail: string; - vat: string; - address: Address; -}; - type InitialValues = { - organization: Organization; - organizers: Organizer[]; + organization: Omit; + organizers: UiTPASOrganizer[]; coupon: string; }; -type Organizer = { - name: string; - id: string; -}; - export const ActivationDialog = ({ isVisible, onClose, diff --git a/resources/ts/types/UiTPASOrganizer.ts b/resources/ts/types/UiTPASOrganizer.ts new file mode 100644 index 000000000..449366547 --- /dev/null +++ b/resources/ts/types/UiTPASOrganizer.ts @@ -0,0 +1,4 @@ +export type UiTPASOrganizer = { + name: string; + id: string; +}; From ffe01fa318c56c7aa7e9c7520aa72eb936258605 Mon Sep 17 00:00:00 2001 From: vhande Date: Wed, 26 Jun 2024 14:33:07 +0200 Subject: [PATCH 27/42] Fix linting --- resources/ts/Components/ActivationDialog.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/ts/Components/ActivationDialog.tsx b/resources/ts/Components/ActivationDialog.tsx index 32774d583..660d3d92e 100644 --- a/resources/ts/Components/ActivationDialog.tsx +++ b/resources/ts/Components/ActivationDialog.tsx @@ -17,7 +17,7 @@ import { faTrash } from "@fortawesome/free-solid-svg-icons"; import { ButtonIcon } from "./ButtonIcon"; import { debounce } from "lodash"; import { Organization } from "../types/Organization"; -import { UiTPASOrganizer } from "../types/UitpasOrganizer"; +import type { UiTPASOrganizer } from "../types/UitpasOrganizer"; const PriceOverview = ({ coupon, @@ -87,7 +87,7 @@ type Props = { }; type InitialValues = { - organization: Omit; + organization: Omit; organizers: UiTPASOrganizer[]; coupon: string; }; @@ -138,7 +138,7 @@ export const ActivationDialog = ({ const [isSearchListVisible, setIsSearchListVisible] = useState(false); - const [organizerList, setOrganizerList] = useState([]); + const [organizerList, setOrganizerList] = useState([]); const handleGetOrganizers = debounce( async (e: React.ChangeEvent) => { @@ -158,7 +158,7 @@ export const ActivationDialog = ({ 250 ); - const handleAddOrganizers = (organizer: Organizer) => { + const handleAddOrganizers = (organizer: UiTPASOrganizer) => { const isDuplicate = organizationForm.data.organizers.length > 0 && organizationForm.data.organizers.some( From 6654804de5f411c12ffb8a489d378e3a90a9c010 Mon Sep 17 00:00:00 2001 From: vhande Date: Wed, 26 Jun 2024 14:57:10 +0200 Subject: [PATCH 28/42] Fix import --- resources/ts/Components/ActivationDialog.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/ts/Components/ActivationDialog.tsx b/resources/ts/Components/ActivationDialog.tsx index 660d3d92e..fadbfa356 100644 --- a/resources/ts/Components/ActivationDialog.tsx +++ b/resources/ts/Components/ActivationDialog.tsx @@ -16,8 +16,8 @@ import { CouponInfoContext } from "../Context/CouponInfo"; import { faTrash } from "@fortawesome/free-solid-svg-icons"; import { ButtonIcon } from "./ButtonIcon"; import { debounce } from "lodash"; -import { Organization } from "../types/Organization"; -import type { UiTPASOrganizer } from "../types/UitpasOrganizer"; +import type { Organization } from "../types/Organization"; +import type { UiTPASOrganizer } from "../types/UiTPASOrganizer"; const PriceOverview = ({ coupon, From 410fd611c2d6898a0077fc18bb4d28462aa350dd Mon Sep 17 00:00:00 2001 From: vhande Date: Wed, 26 Jun 2024 15:26:10 +0200 Subject: [PATCH 29/42] Change debounce time --- resources/ts/Components/ActivationDialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/ts/Components/ActivationDialog.tsx b/resources/ts/Components/ActivationDialog.tsx index fadbfa356..a88e3cae8 100644 --- a/resources/ts/Components/ActivationDialog.tsx +++ b/resources/ts/Components/ActivationDialog.tsx @@ -155,7 +155,7 @@ export const ActivationDialog = ({ ); setOrganizerList(organizers); }, - 250 + 750 ); const handleAddOrganizers = (organizer: UiTPASOrganizer) => { From 46f085b4661c1b48e2c73740986e76beb25488be Mon Sep 17 00:00:00 2001 From: vhande Date: Thu, 27 Jun 2024 10:33:05 +0200 Subject: [PATCH 30/42] Input forwardRef --- resources/ts/Components/Input.tsx | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/resources/ts/Components/Input.tsx b/resources/ts/Components/Input.tsx index 0bdb980d4..88b83b698 100644 --- a/resources/ts/Components/Input.tsx +++ b/resources/ts/Components/Input.tsx @@ -1,5 +1,5 @@ -import React from "react"; -import type { ComponentProps } from "react"; +import React, { forwardRef } from "react"; +import type { ComponentProps, ForwardedRef } from "react"; import { classNames } from "../utils/classNames"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import type { IconProp } from "@fortawesome/fontawesome-svg-core"; @@ -9,14 +9,10 @@ type Props = ComponentProps<"input"> & { inputId?: string; }; -export const Input = ({ - children, - className, - iconBack, - disabled, - inputId, - ...props -}: Props) => { +const InputComponent = ( + { children, className, iconBack, disabled, inputId, ...props }: Props, + ref: ForwardedRef +) => { return (
{children} @@ -40,3 +37,5 @@ export const Input = ({
); }; + +export const Input = forwardRef(InputComponent); From a7328ec2fc53abf52eb29ec7d749b7051ae26353 Mon Sep 17 00:00:00 2001 From: vhande Date: Thu, 27 Jun 2024 10:34:07 +0200 Subject: [PATCH 31/42] Improve ActivationDialog --- resources/ts/Components/ActivationDialog.tsx | 40 +++++++++++--------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/resources/ts/Components/ActivationDialog.tsx b/resources/ts/Components/ActivationDialog.tsx index a88e3cae8..63c9eae9e 100644 --- a/resources/ts/Components/ActivationDialog.tsx +++ b/resources/ts/Components/ActivationDialog.tsx @@ -1,4 +1,4 @@ -import React, { useContext, useState } from "react"; +import React, { useContext, useRef, useState } from "react"; import { Dialog } from "./Dialog"; import { ButtonSecondary } from "./ButtonSecondary"; import { ButtonPrimary } from "./ButtonPrimary"; @@ -140,9 +140,10 @@ export const ActivationDialog = ({ const [organizerList, setOrganizerList] = useState([]); + const organizersInputRef = useRef(null); + const handleGetOrganizers = debounce( async (e: React.ChangeEvent) => { - setOrganizerList([]); const response = await fetch(`/organizers?name=${e.target.value}`); const data = await response.json(); const organizers = data.map( @@ -170,6 +171,10 @@ export const ActivationDialog = ({ organizer, ]); setIsSearchListVisible(false); + setOrganizerList([]); + if (organizersInputRef.current) { + organizersInputRef.current.value = ""; + } } }; @@ -184,6 +189,18 @@ export const ActivationDialog = ({ return null; } + const handleInputOnChange = async ( + e: React.ChangeEvent + ) => { + if (e.target.value !== "") { + await handleGetOrganizers(e); + setIsSearchListVisible(true); + } else { + setIsSearchListVisible(false); + setOrganizerList([]); + } + }; + return ( { - if (e.target.value !== "") { - await handleGetOrganizers(e); - setIsSearchListVisible(true); - } else { - setIsSearchListVisible(false); - } - }} - onBlur={(e) => { - e.target.value = ""; - const timeoutId = setTimeout(() => { - setIsSearchListVisible(false); - clearTimeout(timeoutId); - }, 200); + await handleInputOnChange(e); }} /> {organizerList && organizerList.length > 0 && isSearchListVisible && ( -
    +
      {organizerList.map((organizer) => (
    • Date: Thu, 27 Jun 2024 10:49:57 +0200 Subject: [PATCH 32/42] Improve styling --- resources/ts/Components/Dialog.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/ts/Components/Dialog.tsx b/resources/ts/Components/Dialog.tsx index d22621173..ac8c15e4c 100644 --- a/resources/ts/Components/Dialog.tsx +++ b/resources/ts/Components/Dialog.tsx @@ -32,10 +32,10 @@ export const Dialog = ({ <>
      Date: Thu, 27 Jun 2024 10:50:17 +0200 Subject: [PATCH 33/42] Change function name --- app/Domain/Integrations/Controllers/OrganizerController.php | 2 +- routes/web.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Domain/Integrations/Controllers/OrganizerController.php b/app/Domain/Integrations/Controllers/OrganizerController.php index b3f280994..0e422ca2b 100644 --- a/app/Domain/Integrations/Controllers/OrganizerController.php +++ b/app/Domain/Integrations/Controllers/OrganizerController.php @@ -16,7 +16,7 @@ public function __construct(private readonly SearchService $searchService) { } - public function getOrganizers(GetOrganizersRequest $request): JsonResponse + public function index(GetOrganizersRequest $request): JsonResponse { try { $organizerName = $request->input('name'); diff --git a/routes/web.php b/routes/web.php index 5326d6e04..582cec288 100644 --- a/routes/web.php +++ b/routes/web.php @@ -72,7 +72,7 @@ Route::post('/integrations', [IntegrationController::class, 'store']); - Route::get('/organizers', [OrganizerController::class, 'getOrganizers']); + Route::get('/organizers', [OrganizerController::class, 'index']); Route::group(['middleware' => 'can:access-integration,id'], static function () { TranslatedRoute::get( From 67c9548c7f58b2b44871301ad1a72277c92fe35c Mon Sep 17 00:00:00 2001 From: vhande Date: Thu, 27 Jun 2024 10:54:09 +0200 Subject: [PATCH 34/42] Create function fetchIntegration --- .../FormRequests/RequestActivationRequest.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/app/Domain/Integrations/FormRequests/RequestActivationRequest.php b/app/Domain/Integrations/FormRequests/RequestActivationRequest.php index ac7923fbe..1bab4a091 100644 --- a/app/Domain/Integrations/FormRequests/RequestActivationRequest.php +++ b/app/Domain/Integrations/FormRequests/RequestActivationRequest.php @@ -40,11 +40,17 @@ public function rules(): array return $rules->toArray(); } - private function isAccountingInfoRequired(): bool + private function fetchIntegration() { /** @var IntegrationRepository $integrationRepository */ $integrationRepository = App::get(IntegrationRepository::class); - $integration = $integrationRepository->getById(Uuid::fromString($this->id)); + return $integrationRepository->getById(Uuid::fromString($this->id)); + } + + + private function isAccountingInfoRequired(): bool + { + $integration = $this->fetchIntegration(); /** @var SubscriptionRepository $subscriptionRepository */ $subscriptionRepository = App::get(SubscriptionRepository::class); @@ -55,9 +61,7 @@ private function isAccountingInfoRequired(): bool private function isUITPAS(): bool { - /** @var IntegrationRepository $integrationRepository */ - $integrationRepository = App::get(IntegrationRepository::class); - $integration = $integrationRepository->getById(Uuid::fromString($this->id)); + $integration = $this->fetchIntegration(); return $integration->type === IntegrationType::UiTPAS; } } From 49d0458d118ebb9e28f738bcd009a0244a27a3cc Mon Sep 17 00:00:00 2001 From: vhande Date: Thu, 27 Jun 2024 11:00:15 +0200 Subject: [PATCH 35/42] Fix stan --- .../Integrations/FormRequests/RequestActivationRequest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Domain/Integrations/FormRequests/RequestActivationRequest.php b/app/Domain/Integrations/FormRequests/RequestActivationRequest.php index 1bab4a091..265009220 100644 --- a/app/Domain/Integrations/FormRequests/RequestActivationRequest.php +++ b/app/Domain/Integrations/FormRequests/RequestActivationRequest.php @@ -4,6 +4,7 @@ namespace App\Domain\Integrations\FormRequests; +use App\Domain\Integrations\Integration; use App\Domain\Integrations\IntegrationType; use App\Domain\Integrations\Repositories\IntegrationRepository; use App\Domain\Subscriptions\Repositories\SubscriptionRepository; @@ -40,7 +41,7 @@ public function rules(): array return $rules->toArray(); } - private function fetchIntegration() + private function fetchIntegration(): Integration { /** @var IntegrationRepository $integrationRepository */ $integrationRepository = App::get(IntegrationRepository::class); From 91950094f54b23d1e7219f7dd644a9b97ed6ba4c Mon Sep 17 00:00:00 2001 From: vhande Date: Thu, 27 Jun 2024 11:22:45 +0200 Subject: [PATCH 36/42] Add DB::transaction --- .../Controllers/IntegrationController.php | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/app/Domain/Integrations/Controllers/IntegrationController.php b/app/Domain/Integrations/Controllers/IntegrationController.php index a37e6c18f..3dd66a8e0 100644 --- a/app/Domain/Integrations/Controllers/IntegrationController.php +++ b/app/Domain/Integrations/Controllers/IntegrationController.php @@ -290,20 +290,24 @@ public function requestActivation(string $id, RequestActivationRequest $request) } $organization = OrganizationMapper::mapActivationRequest($request); - $this->organizationRepository->save($organization); - $organizers = $request->input('organizers') ?? []; - foreach ($organizers as $organizer) { - $organizer = new Organizer( - Uuid::uuid4(), - Uuid::fromString($id), - Uuid::fromString($organizer['id']) - ); - $this->organizerRepository->create($organizer); - } + DB::transaction(function () use ($organizers, $id, $organization, $request): void { + $this->organizationRepository->save($organization); + + foreach ($organizers as $organizer) { + $organizer = new Organizer( + Uuid::uuid4(), + Uuid::fromString($id), + Uuid::fromString($organizer['id']) + ); + $this->organizerRepository->create($organizer); + } + + $this->integrationRepository->requestActivation(Uuid::fromString($id), $organization->id, $request->input('coupon')); + + }); - $this->integrationRepository->requestActivation(Uuid::fromString($id), $organization->id, $request->input('coupon')); return Redirect::back(); } From c17bec60f3210d4a48c40befd950ed1a087a06f6 Mon Sep 17 00:00:00 2001 From: vhande Date: Thu, 27 Jun 2024 12:05:13 +0200 Subject: [PATCH 37/42] Handle exception --- .../Controllers/OrganizerController.php | 3 +-- resources/ts/Components/ActivationDialog.tsx | 13 ++++++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/app/Domain/Integrations/Controllers/OrganizerController.php b/app/Domain/Integrations/Controllers/OrganizerController.php index 0e422ca2b..2aee7d1f0 100644 --- a/app/Domain/Integrations/Controllers/OrganizerController.php +++ b/app/Domain/Integrations/Controllers/OrganizerController.php @@ -34,8 +34,7 @@ public function index(GetOrganizersRequest $request): JsonResponse } catch (\Exception $e) { return new JsonResponse( - ['exception' => $e->getMessage()], - 500 + ['exception' => $e->getMessage()] ); ; } diff --git a/resources/ts/Components/ActivationDialog.tsx b/resources/ts/Components/ActivationDialog.tsx index 63c9eae9e..9e7439a25 100644 --- a/resources/ts/Components/ActivationDialog.tsx +++ b/resources/ts/Components/ActivationDialog.tsx @@ -18,6 +18,7 @@ import { ButtonIcon } from "./ButtonIcon"; import { debounce } from "lodash"; import type { Organization } from "../types/Organization"; import type { UiTPASOrganizer } from "../types/UiTPASOrganizer"; +import { Alert } from "./Alert"; const PriceOverview = ({ coupon, @@ -137,8 +138,8 @@ export const ActivationDialog = ({ type !== IntegrationType.EntryApi && type !== IntegrationType.UiTPAS; const [isSearchListVisible, setIsSearchListVisible] = useState(false); - const [organizerList, setOrganizerList] = useState([]); + const [organizerError, setOrganizerError] = useState(false); const organizersInputRef = useRef(null); @@ -146,6 +147,10 @@ export const ActivationDialog = ({ async (e: React.ChangeEvent) => { const response = await fetch(`/organizers?name=${e.target.value}`); const data = await response.json(); + if (data.hasOwnProperty("exception")) { + setOrganizerError(true); + return; + } const organizers = data.map( (organizer: { name: string | { nl: string }; id: string }) => { if (typeof organizer.name === "object" && "nl" in organizer.name) { @@ -155,6 +160,9 @@ export const ActivationDialog = ({ } ); setOrganizerList(organizers); + if (organizerError) { + setOrganizerError(false); + } }, 750 ); @@ -343,6 +351,9 @@ export const ActivationDialog = ({
      ))}
      + {organizerError && ( + {t("dialog.invite_error")} + )} Date: Thu, 27 Jun 2024 13:45:27 +0200 Subject: [PATCH 38/42] Fix linting --- resources/ts/Components/ActivationDialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/ts/Components/ActivationDialog.tsx b/resources/ts/Components/ActivationDialog.tsx index 9e7439a25..e7f5ce680 100644 --- a/resources/ts/Components/ActivationDialog.tsx +++ b/resources/ts/Components/ActivationDialog.tsx @@ -147,7 +147,7 @@ export const ActivationDialog = ({ async (e: React.ChangeEvent) => { const response = await fetch(`/organizers?name=${e.target.value}`); const data = await response.json(); - if (data.hasOwnProperty("exception")) { + if ("exception" in data) { setOrganizerError(true); return; } From 327a8a8c822e650669bb1eb436fb5115d9a087b6 Mon Sep 17 00:00:00 2001 From: vhande Date: Thu, 27 Jun 2024 13:45:47 +0200 Subject: [PATCH 39/42] Add OrganizerMapper --- .../Integrations/Mappers/OrganizerMapper.php | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 app/Domain/Integrations/Mappers/OrganizerMapper.php diff --git a/app/Domain/Integrations/Mappers/OrganizerMapper.php b/app/Domain/Integrations/Mappers/OrganizerMapper.php new file mode 100644 index 000000000..f0d0a17e0 --- /dev/null +++ b/app/Domain/Integrations/Mappers/OrganizerMapper.php @@ -0,0 +1,33 @@ +input('organizers') ?? [] as $organizer) { + $organizers[] = new Organizer( + Uuid::uuid4(), + Uuid::fromString($id), + Uuid::fromString($organizer['id']) + ); + } + + return $organizers; + } +} From 8c330f64745da73271b0457b14db9376970953f9 Mon Sep 17 00:00:00 2001 From: vhande Date: Thu, 27 Jun 2024 13:46:47 +0200 Subject: [PATCH 40/42] Implement DB logic --- .../Controllers/IntegrationController.php | 22 +++++-------------- .../EloquentOrganizerRepository.php | 17 +++++++++----- .../Repositories/OrganizerRepository.php | 2 +- 3 files changed, 17 insertions(+), 24 deletions(-) diff --git a/app/Domain/Integrations/Controllers/IntegrationController.php b/app/Domain/Integrations/Controllers/IntegrationController.php index 3dd66a8e0..9a08cc437 100644 --- a/app/Domain/Integrations/Controllers/IntegrationController.php +++ b/app/Domain/Integrations/Controllers/IntegrationController.php @@ -24,6 +24,7 @@ use App\Domain\Integrations\IntegrationUrl; use App\Domain\Integrations\KeyVisibility; use App\Domain\Integrations\Mappers\OrganizationMapper; +use App\Domain\Integrations\Mappers\OrganizerMapper; use App\Domain\Integrations\Mappers\StoreContactMapper; use App\Domain\Integrations\Mappers\StoreIntegrationMapper; use App\Domain\Integrations\Mappers\StoreIntegrationUrlMapper; @@ -31,7 +32,6 @@ use App\Domain\Integrations\Mappers\UpdateContactInfoMapper; use App\Domain\Integrations\Mappers\UpdateIntegrationMapper; use App\Domain\Integrations\Mappers\UpdateIntegrationUrlsMapper; -use App\Domain\Integrations\Organizer; use App\Domain\Integrations\Repositories\IntegrationRepository; use App\Domain\Integrations\Repositories\IntegrationUrlRepository; use App\Domain\Integrations\Repositories\OrganizerRepository; @@ -290,24 +290,12 @@ public function requestActivation(string $id, RequestActivationRequest $request) } $organization = OrganizationMapper::mapActivationRequest($request); - $organizers = $request->input('organizers') ?? []; - - DB::transaction(function () use ($organizers, $id, $organization, $request): void { - $this->organizationRepository->save($organization); - - foreach ($organizers as $organizer) { - $organizer = new Organizer( - Uuid::uuid4(), - Uuid::fromString($id), - Uuid::fromString($organizer['id']) - ); - $this->organizerRepository->create($organizer); - } - - $this->integrationRepository->requestActivation(Uuid::fromString($id), $organization->id, $request->input('coupon')); + $this->organizationRepository->save($organization); - }); + $organizers = OrganizerMapper::map($request, $id); + $this->organizerRepository->save(...$organizers); + $this->integrationRepository->requestActivation(Uuid::fromString($id), $organization->id, $request->input('coupon')); return Redirect::back(); } diff --git a/app/Domain/Integrations/Repositories/EloquentOrganizerRepository.php b/app/Domain/Integrations/Repositories/EloquentOrganizerRepository.php index a3610d229..3714224c7 100644 --- a/app/Domain/Integrations/Repositories/EloquentOrganizerRepository.php +++ b/app/Domain/Integrations/Repositories/EloquentOrganizerRepository.php @@ -6,15 +6,20 @@ use App\Domain\Integrations\Models\OrganizerModel; use App\Domain\Integrations\Organizer; +use Illuminate\Support\Facades\DB; final class EloquentOrganizerRepository implements OrganizerRepository { - public function create(Organizer $organizer): void + public function create(Organizer ...$organizers): void { - OrganizerModel::query()->create([ - 'id' => $organizer->id->toString(), - 'integration_id' => $organizer->integrationId->toString(), - 'organizer_id' => $organizer->organizerId->toString(), - ]); + DB::transaction(function () use ($organizers): void { + foreach ($organizers as $organizer) { + OrganizerModel::query()->create([ + 'id' => $organizer->id->toString(), + 'integration_id' => $organizer->integrationId->toString(), + 'organizer_id' => $organizer->organizerId->toString(), + ]); + } + }); } } diff --git a/app/Domain/Integrations/Repositories/OrganizerRepository.php b/app/Domain/Integrations/Repositories/OrganizerRepository.php index b234244ec..12be40211 100644 --- a/app/Domain/Integrations/Repositories/OrganizerRepository.php +++ b/app/Domain/Integrations/Repositories/OrganizerRepository.php @@ -8,5 +8,5 @@ interface OrganizerRepository { - public function create(Organizer $organizer): void; + public function create(Organizer ...$organizer): void; } From 7f78b2085136c8b3664c7c2ed8d9814a6a4135e1 Mon Sep 17 00:00:00 2001 From: vhande Date: Thu, 27 Jun 2024 14:20:06 +0200 Subject: [PATCH 41/42] Fix stan --- app/Domain/Integrations/Controllers/IntegrationController.php | 2 +- app/Domain/Integrations/Mappers/OrganizerMapper.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Domain/Integrations/Controllers/IntegrationController.php b/app/Domain/Integrations/Controllers/IntegrationController.php index 9a08cc437..72cd433ac 100644 --- a/app/Domain/Integrations/Controllers/IntegrationController.php +++ b/app/Domain/Integrations/Controllers/IntegrationController.php @@ -293,7 +293,7 @@ public function requestActivation(string $id, RequestActivationRequest $request) $this->organizationRepository->save($organization); $organizers = OrganizerMapper::map($request, $id); - $this->organizerRepository->save(...$organizers); + $this->organizerRepository->create(...$organizers); $this->integrationRepository->requestActivation(Uuid::fromString($id), $organization->id, $request->input('coupon')); diff --git a/app/Domain/Integrations/Mappers/OrganizerMapper.php b/app/Domain/Integrations/Mappers/OrganizerMapper.php index f0d0a17e0..bbd35facc 100644 --- a/app/Domain/Integrations/Mappers/OrganizerMapper.php +++ b/app/Domain/Integrations/Mappers/OrganizerMapper.php @@ -4,7 +4,7 @@ namespace App\Domain\Integrations\Mappers; -use App\Domain\Integrations\FormRequests\GetOrganizersRequest; +use App\Domain\Integrations\FormRequests\RequestActivationRequest; use App\Domain\Integrations\Organizer; use Ramsey\Uuid\Uuid; @@ -13,7 +13,7 @@ final class OrganizerMapper /** * @return Organizer[] */ - public static function map(GetOrganizersRequest $request, string $id): array + public static function map(RequestActivationRequest $request, string $id): array { /** * @var Organizer[] $organizers From 19416af4f672e8147e2e40308e96460fd948c540 Mon Sep 17 00:00:00 2001 From: vhande Date: Thu, 27 Jun 2024 15:52:49 +0200 Subject: [PATCH 42/42] Improve keyboard accessibility --- resources/ts/Components/ActivationDialog.tsx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/resources/ts/Components/ActivationDialog.tsx b/resources/ts/Components/ActivationDialog.tsx index e7f5ce680..18e094e1c 100644 --- a/resources/ts/Components/ActivationDialog.tsx +++ b/resources/ts/Components/ActivationDialog.tsx @@ -209,6 +209,15 @@ export const ActivationDialog = ({ } }; + const handleKeyDown = ( + event: React.KeyboardEvent, + organizer: UiTPASOrganizer + ) => { + if (event.key === "Enter") { + handleAddOrganizers(organizer); + } + }; + return ( {organizerList.map((organizer) => (
    • handleAddOrganizers(organizer)} + onKeyDown={(e) => handleKeyDown(e, organizer)} className="border-b px-3 py-1 hover:bg-gray-100" > {organizer.name}