From 9eabf144d4366dbe8beddb8780ef4b25e5f8505f Mon Sep 17 00:00:00 2001 From: Emma Fabre Date: Sat, 19 Oct 2024 12:11:24 +0200 Subject: [PATCH 01/21] Add dummy buttons to ownerships page --- .../[organizerId]/ownerships/index.page.tsx | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx index f46543963..54afc0d79 100644 --- a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx +++ b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx @@ -1,17 +1,34 @@ import { Page } from '@/ui/Page'; import { getApplicationServerSideProps } from '@/utils/getApplicationServerSideProps'; +import { Stack } from '@/ui/Stack'; +import { Inline } from '@/ui/Inline'; +import { Button, ButtonVariants } from '@/ui/Button'; const Ownership = () => { return ( Hello world -
- Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolore eos - nisi maiores. Doloribus molestias magnam facilis! Eum rerum ea fugit - excepturi doloribus, assumenda quod vitae magni tempore voluptatum - adipisci aliquam. -
+ +
+ Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolore eos + nisi maiores. Doloribus molestias magnam facilis! Eum rerum ea fugit + excepturi doloribus, assumenda quod vitae magni tempore voluptatum + adipisci aliquam. +
+ + + + +
); From 5b1d2486361f7714cbe31cce0b4683b7cdfb993a Mon Sep 17 00:00:00 2001 From: Emma Fabre Date: Sat, 19 Oct 2024 12:37:13 +0200 Subject: [PATCH 02/21] Add modal skeleton --- .../[organizerId]/ownerships/index.page.tsx | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx index 54afc0d79..b8be311fd 100644 --- a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx +++ b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx @@ -3,8 +3,23 @@ import { getApplicationServerSideProps } from '@/utils/getApplicationServerSideP import { Stack } from '@/ui/Stack'; import { Inline } from '@/ui/Inline'; import { Button, ButtonVariants } from '@/ui/Button'; +import { Modal, ModalSizes, ModalVariants } from '@/ui/Modal'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useForm } from 'react-hook-form'; +import { Input } from '@/ui/Input'; +import { FormElement } from '@/ui/FormElement'; const Ownership = () => { + const { t } = useTranslation(); + const [isOpen, setIsOpen] = useState(false); + const { register, formState, getValues } = useForm(); + + const handleConfirm = () => { + const email = getValues('email'); + console.log({ email }); + }; + return ( Hello world @@ -23,12 +38,33 @@ const Ownership = () => { adipisci aliquam. - + + setIsOpen(false)} + > + + } + label={'Emailadres'} + error={formState.errors.email && 'email is required'} + /> + + ); From 74eac94bfb911d128035692dd746d257bf3248e8 Mon Sep 17 00:00:00 2001 From: Emma Fabre Date: Sat, 19 Oct 2024 12:41:54 +0200 Subject: [PATCH 03/21] Add translations block --- src/i18n/nl.json | 15 +++++++++++++++ .../[organizerId]/ownerships/index.page.tsx | 19 ++++++++++++------- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/i18n/nl.json b/src/i18n/nl.json index 09aeae77a..7597921f0 100644 --- a/src/i18n/nl.json +++ b/src/i18n/nl.json @@ -1015,6 +1015,21 @@ "intro": "Voeg een afbeelding toe zodat bezoekers je organisatie beter herkennen" } } + }, + "ownerships": { + "title": "Beheerders van {{name}}", + "actions": { + "add": "Nieuwe beheerder toevoegen", + "back": "Terug naar organisatiepagina" + }, + "modal": { + "title": "Beheerder toevoegen aon {{name}}", + "email": "E-mailadres", + "actions": { + "confirm": "Beheerder toevoegen", + "cancel": "Annuleren" + } + } } }, "selectionTable": { diff --git a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx index b8be311fd..c492003b8 100644 --- a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx +++ b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx @@ -14,6 +14,7 @@ const Ownership = () => { const { t } = useTranslation(); const [isOpen, setIsOpen] = useState(false); const { register, formState, getValues } = useForm(); + const organizer = { name: 'foobar' }; const handleConfirm = () => { const email = getValues('email'); @@ -22,7 +23,9 @@ const Ownership = () => { return ( - Hello world + + {t('organizers.ownerships.title', { name: organizer.name })} + { @@ -50,9 +53,11 @@ const Ownership = () => { visible={isOpen} variant={ModalVariants.QUESTION} size={ModalSizes.MD} - title={'Beheerder toevoegen aon Democrazy'} - confirmTitle={t('organizer.add_modal.actions.add')} - cancelTitle={t('organizer.add_modal.actions.cancel')} + title={t('organizers.ownerships.modal.title', { + name: organizer.name, + })} + confirmTitle={t('organizers.ownerships.modal.actions.confirm')} + cancelTitle={t('organizers.ownerships.modal.actions.cancel')} onConfirm={handleConfirm} onClose={() => setIsOpen(false)} > @@ -60,7 +65,7 @@ const Ownership = () => { } - label={'Emailadres'} + label={t('organizers.ownerships.modal.email')} error={formState.errors.email && 'email is required'} /> From c72a684e9017bad957352a06ddb00327f8837ef2 Mon Sep 17 00:00:00 2001 From: Emma Fabre Date: Sat, 19 Oct 2024 12:46:52 +0200 Subject: [PATCH 04/21] Get organizer from server side --- src/i18n/nl.json | 2 +- src/pages/organizers/[organizerId]/edit/index.page.tsx | 1 + .../organizers/[organizerId]/ownerships/index.page.tsx | 8 ++++---- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/i18n/nl.json b/src/i18n/nl.json index 7597921f0..b36c7f46d 100644 --- a/src/i18n/nl.json +++ b/src/i18n/nl.json @@ -1023,7 +1023,7 @@ "back": "Terug naar organisatiepagina" }, "modal": { - "title": "Beheerder toevoegen aon {{name}}", + "title": "Beheerder toevoegen aan {{name}}", "email": "E-mailadres", "actions": { "confirm": "Beheerder toevoegen", diff --git a/src/pages/organizers/[organizerId]/edit/index.page.tsx b/src/pages/organizers/[organizerId]/edit/index.page.tsx index fbfbd3d36..4eef8e126 100644 --- a/src/pages/organizers/[organizerId]/edit/index.page.tsx +++ b/src/pages/organizers/[organizerId]/edit/index.page.tsx @@ -18,6 +18,7 @@ export const getServerSideProps = getApplicationServerSideProps( return { props: { + organizer, dehydratedState: dehydrate(queryClient), cookies, }, diff --git a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx index c492003b8..ed9636d01 100644 --- a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx +++ b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx @@ -1,5 +1,4 @@ import { Page } from '@/ui/Page'; -import { getApplicationServerSideProps } from '@/utils/getApplicationServerSideProps'; import { Stack } from '@/ui/Stack'; import { Inline } from '@/ui/Inline'; import { Button, ButtonVariants } from '@/ui/Button'; @@ -9,12 +8,13 @@ import { useTranslation } from 'react-i18next'; import { useForm } from 'react-hook-form'; import { Input } from '@/ui/Input'; import { FormElement } from '@/ui/FormElement'; +import { getServerSideProps as getServerProps } from '../edit/index.page'; +import { Organizer } from '@/types/Organizer'; -const Ownership = () => { +const Ownership = ({ organizer }: { organizer: Organizer }) => { const { t } = useTranslation(); const [isOpen, setIsOpen] = useState(false); const { register, formState, getValues } = useForm(); - const organizer = { name: 'foobar' }; const handleConfirm = () => { const email = getValues('email'); @@ -75,6 +75,6 @@ const Ownership = () => { ); }; -export const getServerSideProps = getApplicationServerSideProps(); +export const getServerSideProps = getServerProps; export default Ownership; From e40a1b99fe8e901664fb8f8b935a1ad457ea6373 Mon Sep 17 00:00:00 2001 From: Emma Fabre Date: Sat, 19 Oct 2024 13:02:21 +0200 Subject: [PATCH 05/21] Work on mutation logic --- src/hooks/api/ownerships.ts | 25 +++++++++++++++++++ .../[organizerId]/ownerships/index.page.tsx | 15 ++++++++--- 2 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 src/hooks/api/ownerships.ts diff --git a/src/hooks/api/ownerships.ts b/src/hooks/api/ownerships.ts new file mode 100644 index 000000000..1b78bde48 --- /dev/null +++ b/src/hooks/api/ownerships.ts @@ -0,0 +1,25 @@ +import { useAuthenticatedMutation } from '@/hooks/api/authenticated-query'; +import { fetchFromApi } from '@/utils/fetchFromApi'; + +const createOwnership = async ({ headers, itemId, itemType, ownerId }) => + fetchFromApi({ + path: `/ownerships`, + options: { + method: 'POST', + headers, + body: JSON.stringify({ + ownerId, + itemId, + itemType, + }), + }, + }); + +const useCreateOwnershipMutation = (configuration = {}) => + useAuthenticatedMutation({ + mutationFn: createOwnership, + mutationKey: 'ownerships-add-ownership', + ...configuration, + }); + +export { useCreateOwnershipMutation }; diff --git a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx index ed9636d01..ed5d73e51 100644 --- a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx +++ b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx @@ -10,15 +10,25 @@ import { Input } from '@/ui/Input'; import { FormElement } from '@/ui/FormElement'; import { getServerSideProps as getServerProps } from '../edit/index.page'; import { Organizer } from '@/types/Organizer'; +import { useCreateOrganizerOwnershipMutation } from '@/hooks/api/organizers'; +import { useCreateOwnershipMutation } from '@/hooks/api/ownerships'; const Ownership = ({ organizer }: { organizer: Organizer }) => { const { t } = useTranslation(); const [isOpen, setIsOpen] = useState(false); const { register, formState, getValues } = useForm(); + const createOwnership = useCreateOwnershipMutation(); - const handleConfirm = () => { + const handleConfirm = async () => { const email = getValues('email'); - console.log({ email }); + return; + const response = await createOwnership.mutate({ + ownerId: email, + itemType: 'organizer', + itemId: organizer['@id'], + }); + + const ownershipId = response.data.id; }; return ( @@ -66,7 +76,6 @@ const Ownership = ({ organizer }: { organizer: Organizer }) => { id={'email'} Component={} label={t('organizers.ownerships.modal.email')} - error={formState.errors.email && 'email is required'} /> From 550a715cf7214fc7ba24f9a4e30a3fb602eef09b Mon Sep 17 00:00:00 2001 From: Emma Fabre Date: Sat, 19 Oct 2024 13:10:16 +0200 Subject: [PATCH 06/21] Add approval --- src/hooks/api/ownerships.ts | 17 +++++++++++++++-- .../[organizerId]/ownerships/index.page.tsx | 9 +++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/hooks/api/ownerships.ts b/src/hooks/api/ownerships.ts index 1b78bde48..00e2d11a1 100644 --- a/src/hooks/api/ownerships.ts +++ b/src/hooks/api/ownerships.ts @@ -15,11 +15,24 @@ const createOwnership = async ({ headers, itemId, itemType, ownerId }) => }, }); +const approveOwnership = ({ headers, ownershipId }) => + fetchFromApi({ + path: `/ownerships/${ownershipId}/approve`, + options: { headers, method: 'POST' }, + }); + const useCreateOwnershipMutation = (configuration = {}) => useAuthenticatedMutation({ mutationFn: createOwnership, - mutationKey: 'ownerships-add-ownership', + mutationKey: 'ownerships-create-ownership', + ...configuration, + }); + +const useApproveOwnershipMutation = (configuration = {}) => + useAuthenticatedMutation({ + mutationFn: approveOwnership, + mutationKey: 'ownerships-approve-ownership', ...configuration, }); -export { useCreateOwnershipMutation }; +export { useApproveOwnershipMutation, useCreateOwnershipMutation }; diff --git a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx index ed5d73e51..029ebe29b 100644 --- a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx +++ b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx @@ -11,13 +11,17 @@ import { FormElement } from '@/ui/FormElement'; import { getServerSideProps as getServerProps } from '../edit/index.page'; import { Organizer } from '@/types/Organizer'; import { useCreateOrganizerOwnershipMutation } from '@/hooks/api/organizers'; -import { useCreateOwnershipMutation } from '@/hooks/api/ownerships'; +import { + useApproveOwnershipMutation, + useCreateOwnershipMutation, +} from '@/hooks/api/ownerships'; const Ownership = ({ organizer }: { organizer: Organizer }) => { const { t } = useTranslation(); const [isOpen, setIsOpen] = useState(false); const { register, formState, getValues } = useForm(); const createOwnership = useCreateOwnershipMutation(); + const approveOwnership = useApproveOwnershipMutation(); const handleConfirm = async () => { const email = getValues('email'); @@ -28,7 +32,8 @@ const Ownership = ({ organizer }: { organizer: Organizer }) => { itemId: organizer['@id'], }); - const ownershipId = response.data.id; + await approveOwnership.mutate({ ownershipId: response.data.id }); + // Show flash message }; return ( From 7b7376537d2c12fecbbb9a8b399a009333ff9391 Mon Sep 17 00:00:00 2001 From: Emma Fabre Date: Mon, 21 Oct 2024 14:38:07 +0200 Subject: [PATCH 07/21] Linting --- .../[organizerId]/ownerships/index.page.tsx | 39 +++++++++++++------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx index 029ebe29b..61094069b 100644 --- a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx +++ b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx @@ -1,20 +1,23 @@ -import { Page } from '@/ui/Page'; -import { Stack } from '@/ui/Stack'; -import { Inline } from '@/ui/Inline'; -import { Button, ButtonVariants } from '@/ui/Button'; -import { Modal, ModalSizes, ModalVariants } from '@/ui/Modal'; import { useState } from 'react'; -import { useTranslation } from 'react-i18next'; import { useForm } from 'react-hook-form'; -import { Input } from '@/ui/Input'; -import { FormElement } from '@/ui/FormElement'; -import { getServerSideProps as getServerProps } from '../edit/index.page'; -import { Organizer } from '@/types/Organizer'; -import { useCreateOrganizerOwnershipMutation } from '@/hooks/api/organizers'; +import { useTranslation } from 'react-i18next'; + import { useApproveOwnershipMutation, useCreateOwnershipMutation, } from '@/hooks/api/ownerships'; +import { useToast } from '@/pages/manage/movies/useToast'; +import { Organizer } from '@/types/Organizer'; +import { Button, ButtonVariants } from '@/ui/Button'; +import { FormElement } from '@/ui/FormElement'; +import { Inline } from '@/ui/Inline'; +import { Input } from '@/ui/Input'; +import { Modal, ModalSizes, ModalVariants } from '@/ui/Modal'; +import { Page } from '@/ui/Page'; +import { Stack } from '@/ui/Stack'; +import { Toast } from '@/ui/Toast'; + +import { getServerSideProps as getServerProps } from '../edit/index.page'; const Ownership = ({ organizer }: { organizer: Organizer }) => { const { t } = useTranslation(); @@ -22,6 +25,12 @@ const Ownership = ({ organizer }: { organizer: Organizer }) => { const { register, formState, getValues } = useForm(); const createOwnership = useCreateOwnershipMutation(); const approveOwnership = useApproveOwnershipMutation(); + const toast = useToast({ + messages: { + success: t('organizers.ownerships.toast.success'), + error: t('organizers.ownerships.toast.error'), + }, + }); const handleConfirm = async () => { const email = getValues('email'); @@ -33,7 +42,7 @@ const Ownership = ({ organizer }: { organizer: Organizer }) => { }); await approveOwnership.mutate({ ownershipId: response.data.id }); - // Show flash message + toast.trigger('success'); }; return ( @@ -84,6 +93,12 @@ const Ownership = ({ organizer }: { organizer: Organizer }) => { /> + toast.clear()} + /> ); From 7394fc790248f6b95bc08462732412bbd1d31454 Mon Sep 17 00:00:00 2001 From: Emma Fabre Date: Wed, 23 Oct 2024 15:36:51 +0200 Subject: [PATCH 08/21] Use new ownerEmail parameter --- .../organizers/[organizerId]/ownerships/index.page.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx index 9fda93c28..590850b66 100644 --- a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx +++ b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx @@ -34,7 +34,7 @@ const Ownership = () => { const router = useRouter(); const { t, i18n } = useTranslation(); const [isOpen, setIsOpen] = useState(false); - const { register, formState, getValues } = useForm(); + const { register, getValues } = useForm(); const organizerId = useMemo( () => router.query.organizerId as string, @@ -77,14 +77,13 @@ const Ownership = () => { const handleConfirm = async () => { const email = getValues('email'); - return; - const response = await createOwnership.mutate({ - ownerId: email, + const response = createOwnership.mutateAsync({ + ownerEmail: email, itemType: 'organizer', itemId: organizer['@id'], }); - await approveOwnership.mutate({ ownershipId: response.data.id }); + await approveOwnership.mutateAsync({ ownershipId: response.data.id }); toast.trigger('success'); }; From ca1d2297f00b9fdc5d91df2cc292fbbb4ddd1601 Mon Sep 17 00:00:00 2001 From: Emma Fabre Date: Thu, 31 Oct 2024 12:32:02 +0100 Subject: [PATCH 09/21] Work on centralizing logic --- src/hooks/api/ownerships.ts | 10 +-- src/i18n/nl.json | 6 +- .../[organizerId]/ownerships/index.page.tsx | 83 ++++++++----------- 3 files changed, 41 insertions(+), 58 deletions(-) diff --git a/src/hooks/api/ownerships.ts b/src/hooks/api/ownerships.ts index 891e532a5..ace130b8a 100644 --- a/src/hooks/api/ownerships.ts +++ b/src/hooks/api/ownerships.ts @@ -25,7 +25,7 @@ export const RequestState = { type RequestState = Values; -const createOwnership = async ({ headers, itemId, itemType, ownerId }) => +const requestOwnership = async ({ headers, itemId, itemType, ownerId }) => fetchFromApi({ path: `/ownerships`, options: { @@ -39,10 +39,10 @@ const createOwnership = async ({ headers, itemId, itemType, ownerId }) => }, }); -const useCreateOwnershipMutation = (configuration = {}) => +const useRequestOwnershipMutation = (configuration = {}) => useAuthenticatedMutation({ - mutationFn: createOwnership, - mutationKey: 'ownerships-create-ownership', + mutationFn: requestOwnership, + mutationKey: 'ownerships-request-ownership', ...configuration, }); @@ -131,7 +131,7 @@ const useDeleteOwnershipRequestMutation = (configuration = {}) => export { useApproveOwnershipRequestMutation, - useCreateOwnershipMutation, + useRequestOwnershipMutation, useDeleteOwnershipRequestMutation, useGetOwnershipRequestsQuery, useRejectOwnershipRequestMutation, diff --git a/src/i18n/nl.json b/src/i18n/nl.json index 000314e3a..0e60b7477 100644 --- a/src/i18n/nl.json +++ b/src/i18n/nl.json @@ -1032,7 +1032,9 @@ "reject": "Afkeuren" } }, - "modal": { + "pending": "Openstaande aanvragen tot beheer", + "close": "Sluiten", + "request_modal": { "title": "Beheerder toevoegen aan {{name}}", "email": "E-mailadres", "actions": { @@ -1040,8 +1042,6 @@ "cancel": "Annuleren" } }, - "pending": "Openstaande aanvragen tot beheer", - "close": "Sluiten", "confirm_modal": { "title": "Aanvraag tot beheer goedkeuren", "body": "Ben je zeker dat je de aanvraag van {{ownerEmail}} wilt goedkeuren?

Van zodra je de aanvraag goedkeurt zal {{ownerEmail}} de organisatiepagina en de evenementen van {{organizerName}} kunnen bewerken.", diff --git a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx index d71ce35a3..d9803d2d6 100644 --- a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx +++ b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx @@ -10,33 +10,32 @@ import { OwnershipRequest, RequestState, useApproveOwnershipRequestMutation, - useCreateOwnershipMutation, + useRequestOwnershipMutation, useDeleteOwnershipRequestMutation, useGetOwnershipRequestsQuery, useRejectOwnershipRequestMutation, } from '@/hooks/api/ownerships'; -import { useToast } from '@/pages/manage/movies/useToast'; import { Organizer } from '@/types/Organizer'; import { Values } from '@/types/Values'; import { Alert, AlertVariants } from '@/ui/Alert'; import { Box } from '@/ui/Box'; import { Button, ButtonVariants } from '@/ui/Button'; import { FormElement } from '@/ui/FormElement'; -import { Icon, Icons } from '@/ui/Icon'; +import { Icons } from '@/ui/Icon'; import { Inline } from '@/ui/Inline'; import { Input } from '@/ui/Input'; import { Modal, ModalSizes, ModalVariants } from '@/ui/Modal'; import { Page } from '@/ui/Page'; import { Stack } from '@/ui/Stack'; import { Title } from '@/ui/Title'; -import { Toast } from '@/ui/Toast'; import { getApplicationServerSideProps } from '@/utils/getApplicationServerSideProps'; import { OwnershipsTable } from './OwnershipsTable'; const ActionType = { - APPROVE: 'approve', + APPROVE: 'confirm', REJECT: 'reject', + REQUEST: 'request', } as const; type ActionType = Values; @@ -45,17 +44,15 @@ const Ownership = () => { const router = useRouter(); const { t, i18n } = useTranslation(); const queryClient = useQueryClient(); - const [selectedRequest, setSelectedRequest] = useState(); - const [requestToBeDeleted, setRequestToBeDeleted] = - useState(); - const [isQuestionModalVisible, setIsQuestionModalVisible] = useState(false); const [actionType, setActionType] = useState(); + const [isOpen, setIsOpen] = useState(false); + const [isQuestionModalVisible, setIsQuestionModalVisible] = useState(false); const [isSuccessAlertVisible, setIsSuccessAlertVisible] = useState(false); + const [requestToBeDeleted, setRequestToBeDeleted] = + useState(); + const [selectedRequest, setSelectedRequest] = useState(); const isApproveAction = actionType === ActionType.APPROVE; - const translationsPath = `organizers.ownerships.${ - isApproveAction ? 'confirm' : 'reject' - }_modal`; - const [isOpen, setIsOpen] = useState(false); + const translationsPath = `organizers.ownerships.${ActionType}_modal`; const { register, getValues } = useForm(); const organizerId = useMemo( @@ -96,6 +93,13 @@ const Ownership = () => { }, }); + const requestOwnership = useRequestOwnershipMutation({ + onSuccess: () => + approveOwnershipRequestMutation.mutateAsync({ + ownershipId: response.data.id, + }), + }); + const rejectOwnershipRequestMutation = useRejectOwnershipRequestMutation({ onSuccess: async () => { await queryClient.invalidateQueries('ownership-requests'); @@ -112,40 +116,25 @@ const Ownership = () => { }); const handleConfirm = () => { - if (isApproveAction) { - approveOwnershipRequestMutation.mutate({ - ownershipId: selectedRequest.id, - }); - } else { - rejectOwnershipRequestMutation.mutate({ - ownershipId: selectedRequest.id, - }); + switch (actionType) { + case ActionType.APPROVE: + return approveOwnershipRequestMutation.mutate({ + ownershipId: selectedRequest.id, + }); + case ActionType.REJECT: + return rejectOwnershipRequestMutation.mutate({ + ownershipId: selectedRequest.id, + }); + case ActionType.REQUEST: + const email = getValues('email'); + return requestOwnership.mutateAsync({ + ownerEmail: email, + itemType: 'organizer', + itemId: organizer['@id'], + }); } }; - const createOwnership = useCreateOwnershipMutation(); - const toast = useToast({ - messages: { - success: t('organizers.ownerships.toast.success'), - error: t('organizers.ownerships.toast.error'), - }, - }); - - const handleConfirmRequest = async () => { - const email = getValues('email'); - const response = createOwnership.mutateAsync({ - ownerEmail: email, - itemType: 'organizer', - itemId: organizer['@id'], - }); - - await approveOwnershipRequestMutation.mutateAsync({ - ownershipId: response.data.id, - }); - setIsSuccessAlertVisible(true); - setIsQuestionModalVisible(false); - }; - return ( @@ -309,12 +298,6 @@ const Ownership = () => { /> - toast.clear()} - /> ); From 0cd81f0375033ab00a539cdbc98577768c74e5a4 Mon Sep 17 00:00:00 2001 From: Emma Fabre Date: Thu, 31 Oct 2024 14:45:27 +0100 Subject: [PATCH 10/21] Work on centralizing logic from actions --- src/hooks/api/ownerships.ts | 2 +- src/i18n/nl.json | 1 + .../[organizerId]/ownerships/index.page.tsx | 37 ++++++++++++------- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/hooks/api/ownerships.ts b/src/hooks/api/ownerships.ts index ace130b8a..e721d02d0 100644 --- a/src/hooks/api/ownerships.ts +++ b/src/hooks/api/ownerships.ts @@ -39,7 +39,7 @@ const requestOwnership = async ({ headers, itemId, itemType, ownerId }) => }, }); -const useRequestOwnershipMutation = (configuration = {}) => +const useRequestOwnershipMutation = (configuration: UseQueryOptions = {}) => useAuthenticatedMutation({ mutationFn: requestOwnership, mutationKey: 'ownerships-request-ownership', diff --git a/src/i18n/nl.json b/src/i18n/nl.json index 0e60b7477..302dbb385 100644 --- a/src/i18n/nl.json +++ b/src/i18n/nl.json @@ -1037,6 +1037,7 @@ "request_modal": { "title": "Beheerder toevoegen aan {{name}}", "email": "E-mailadres", + "email_error": "Geen geldig e-mailadres", "actions": { "confirm": "Beheerder toevoegen", "cancel": "Annuleren" diff --git a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx index d9803d2d6..5a6f26b12 100644 --- a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx +++ b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx @@ -51,9 +51,8 @@ const Ownership = () => { const [requestToBeDeleted, setRequestToBeDeleted] = useState(); const [selectedRequest, setSelectedRequest] = useState(); - const isApproveAction = actionType === ActionType.APPROVE; const translationsPath = `organizers.ownerships.${ActionType}_modal`; - const { register, getValues } = useForm(); + const { register, formState, getValues, setError } = useForm(); const organizerId = useMemo( () => router.query.organizerId as string, @@ -94,10 +93,13 @@ const Ownership = () => { }); const requestOwnership = useRequestOwnershipMutation({ - onSuccess: () => - approveOwnershipRequestMutation.mutateAsync({ + onSuccess: (response) => { + console.log({ response }); + approveOwnershipRequestMutation.mutate({ ownershipId: response.data.id, - }), + }); + }, + onError: (error) => setError('email', error.message), }); const rejectOwnershipRequestMutation = useRejectOwnershipRequestMutation({ @@ -126,9 +128,8 @@ const Ownership = () => { ownershipId: selectedRequest.id, }); case ActionType.REQUEST: - const email = getValues('email'); - return requestOwnership.mutateAsync({ - ownerEmail: email, + return requestOwnership.mutate({ + ownerEmail: getValues('email'), itemType: 'organizer', itemId: organizer['@id'], }); @@ -264,7 +265,11 @@ const Ownership = () => { @@ -282,11 +287,13 @@ const Ownership = () => { visible={isOpen} variant={ModalVariants.QUESTION} size={ModalSizes.MD} - title={t('organizers.ownerships.modal.title', { + title={t('organizers.ownerships.request_modal.title', { name: organizer.name, })} - confirmTitle={t('organizers.ownerships.modal.actions.confirm')} - cancelTitle={t('organizers.ownerships.modal.actions.cancel')} + confirmTitle={t( + 'organizers.ownerships.request_modal.actions.confirm', + )} + cancelTitle={t('organizers.ownerships.request_modal.actions.cancel')} onConfirm={handleConfirm} onClose={() => setIsOpen(false)} > @@ -294,7 +301,11 @@ const Ownership = () => { } - label={t('organizers.ownerships.modal.email')} + label={t('organizers.ownerships.request_modal.email')} + error={ + formState.errors.email && + t(`organizers.ownerships.request_modal.email_error`) + } /> From 0dc3f498626ee5a3ae7b9e566e8d13aafb7ce154 Mon Sep 17 00:00:00 2001 From: Emma Fabre Date: Thu, 31 Oct 2024 15:36:45 +0100 Subject: [PATCH 11/21] Fixed unparsed @id --- src/hooks/api/ownerships.ts | 2 +- .../[organizerId]/ownerships/index.page.tsx | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/hooks/api/ownerships.ts b/src/hooks/api/ownerships.ts index e721d02d0..33b5ca3bd 100644 --- a/src/hooks/api/ownerships.ts +++ b/src/hooks/api/ownerships.ts @@ -131,8 +131,8 @@ const useDeleteOwnershipRequestMutation = (configuration = {}) => export { useApproveOwnershipRequestMutation, - useRequestOwnershipMutation, useDeleteOwnershipRequestMutation, useGetOwnershipRequestsQuery, useRejectOwnershipRequestMutation, + useRequestOwnershipMutation, }; diff --git a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx index 5a6f26b12..959ab0f72 100644 --- a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx +++ b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx @@ -10,10 +10,10 @@ import { OwnershipRequest, RequestState, useApproveOwnershipRequestMutation, - useRequestOwnershipMutation, useDeleteOwnershipRequestMutation, useGetOwnershipRequestsQuery, useRejectOwnershipRequestMutation, + useRequestOwnershipMutation, } from '@/hooks/api/ownerships'; import { Organizer } from '@/types/Organizer'; import { Values } from '@/types/Values'; @@ -29,6 +29,7 @@ import { Page } from '@/ui/Page'; import { Stack } from '@/ui/Stack'; import { Title } from '@/ui/Title'; import { getApplicationServerSideProps } from '@/utils/getApplicationServerSideProps'; +import { parseOfferId } from '@/utils/parseOfferId'; import { OwnershipsTable } from './OwnershipsTable'; @@ -51,7 +52,7 @@ const Ownership = () => { const [requestToBeDeleted, setRequestToBeDeleted] = useState(); const [selectedRequest, setSelectedRequest] = useState(); - const translationsPath = `organizers.ownerships.${ActionType}_modal`; + const translationsPath = `organizers.ownerships.${actionType}_modal`; const { register, formState, getValues, setError } = useForm(); const organizerId = useMemo( @@ -93,13 +94,11 @@ const Ownership = () => { }); const requestOwnership = useRequestOwnershipMutation({ - onSuccess: (response) => { - console.log({ response }); - approveOwnershipRequestMutation.mutate({ - ownershipId: response.data.id, - }); - }, onError: (error) => setError('email', error.message), + onSuccess: (data) => + approveOwnershipRequestMutation.mutate({ + ownershipId: data.id, + }), }); const rejectOwnershipRequestMutation = useRejectOwnershipRequestMutation({ @@ -131,7 +130,7 @@ const Ownership = () => { return requestOwnership.mutate({ ownerEmail: getValues('email'), itemType: 'organizer', - itemId: organizer['@id'], + itemId: parseOfferId(organizer['@id']), }); } }; From a61d891151b16b9643b7e3613752e3195fa199b4 Mon Sep 17 00:00:00 2001 From: Emma Fabre Date: Fri, 15 Nov 2024 16:14:54 +0100 Subject: [PATCH 12/21] Work on ownership request flow --- src/hooks/api/ownerships.ts | 4 +-- src/i18n/nl.json | 1 + .../[organizerId]/ownerships/index.page.tsx | 27 ++++++++++++++----- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/hooks/api/ownerships.ts b/src/hooks/api/ownerships.ts index 33b5ca3bd..26851332d 100644 --- a/src/hooks/api/ownerships.ts +++ b/src/hooks/api/ownerships.ts @@ -25,14 +25,14 @@ export const RequestState = { type RequestState = Values; -const requestOwnership = async ({ headers, itemId, itemType, ownerId }) => +const requestOwnership = async ({ headers, itemId, itemType, ownerEmail }) => fetchFromApi({ path: `/ownerships`, options: { method: 'POST', headers, body: JSON.stringify({ - ownerId, + ownerEmail, itemId, itemType, }), diff --git a/src/i18n/nl.json b/src/i18n/nl.json index b31828c9f..5669ff203 100644 --- a/src/i18n/nl.json +++ b/src/i18n/nl.json @@ -1038,6 +1038,7 @@ "title": "Beheerder toevoegen aan {{name}}", "email": "E-mailadres", "email_error": "Geen geldig e-mailadres", + "success": "{{ownerEmail}} is nu beheerder van {{organizerName}} en kan voortaan de organisatiepagina en evenementen van {{organizerName}} bewerken.", "actions": { "confirm": "Beheerder toevoegen", "cancel": "Annuleren" diff --git a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx index e13061e09..8619e34f4 100644 --- a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx +++ b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx @@ -97,11 +97,23 @@ const Ownership = () => { }); const requestOwnership = useRequestOwnershipMutation({ - onError: (error) => setError('email', error.message), - onSuccess: (data) => - approveOwnershipRequestMutation.mutate({ + onError: async (error) => { + if (error.body.status === 409) { + const ownershipId = error.body.detail.split('with id ')[1]; + setIsSuccessAlertVisible(true); + setIsOpen(false); + await approveOwnershipRequestMutation.mutateAsync({ ownershipId }); + } else { + setError('email', { message: error.body.detail || error.title }); + } + }, + onSuccess: async (data) => { + setIsSuccessAlertVisible(true); + setIsOpen(false); + await approveOwnershipRequestMutation.mutateAsync({ ownershipId: data.id, - }), + }); + }, }); const rejectOwnershipRequestMutation = useRejectOwnershipRequestMutation({ @@ -165,8 +177,9 @@ const Ownership = () => { @@ -256,7 +269,7 @@ const Ownership = () => { i18nKey={`${translationsPath}.body`} values={{ ownerEmail: selectedRequest?.ownerEmail, - organizerName: organizerName, + organizerName, }} /> From c41c7b8b70ea0c02262ce404ed7bad8091310f84 Mon Sep 17 00:00:00 2001 From: Emma Fabre Date: Fri, 15 Nov 2024 16:34:21 +0100 Subject: [PATCH 13/21] Remove leftover prop --- src/pages/organizers/[organizerId]/edit/index.page.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/organizers/[organizerId]/edit/index.page.tsx b/src/pages/organizers/[organizerId]/edit/index.page.tsx index 4eef8e126..fbfbd3d36 100644 --- a/src/pages/organizers/[organizerId]/edit/index.page.tsx +++ b/src/pages/organizers/[organizerId]/edit/index.page.tsx @@ -18,7 +18,6 @@ export const getServerSideProps = getApplicationServerSideProps( return { props: { - organizer, dehydratedState: dehydrate(queryClient), cookies, }, From 8a9fdf1ae29eb6705339551c82998124ba57f2ea Mon Sep 17 00:00:00 2001 From: Emma Fabre Date: Mon, 18 Nov 2024 13:13:56 +0100 Subject: [PATCH 14/21] Add types --- .../[organizerId]/ownerships/index.page.tsx | 22 +++++++++---------- src/utils/fetchFromApi.ts | 14 +++++++----- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx index 8619e34f4..f1ac2ba89 100644 --- a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx +++ b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx @@ -32,6 +32,7 @@ import { getApplicationServerSideProps } from '@/utils/getApplicationServerSideP import { parseOfferId } from '@/utils/parseOfferId'; import { OwnershipsTable } from './OwnershipsTable'; +import { ErrorBody, FetchError } from '@/utils/fetchFromApi'; const ActionType = { APPROVE: 'confirm', @@ -96,24 +97,23 @@ const Ownership = () => { }, }); + const approveRequestedOwnership = async (ownershipId: string) => { + setIsSuccessAlertVisible(true); + setIsOpen(false); + + return approveOwnershipRequestMutation.mutateAsync({ ownershipId }); + }; + const requestOwnership = useRequestOwnershipMutation({ - onError: async (error) => { + onError: async (error: FetchError) => { if (error.body.status === 409) { const ownershipId = error.body.detail.split('with id ')[1]; - setIsSuccessAlertVisible(true); - setIsOpen(false); - await approveOwnershipRequestMutation.mutateAsync({ ownershipId }); + await approveRequestedOwnership(ownershipId); } else { setError('email', { message: error.body.detail || error.title }); } }, - onSuccess: async (data) => { - setIsSuccessAlertVisible(true); - setIsOpen(false); - await approveOwnershipRequestMutation.mutateAsync({ - ownershipId: data.id, - }); - }, + onSuccess: (data: { id: string }) => approveRequestedOwnership(data.id), }); const rejectOwnershipRequestMutation = useRejectOwnershipRequestMutation({ diff --git a/src/utils/fetchFromApi.ts b/src/utils/fetchFromApi.ts index a839dc2d0..00c35b7b3 100644 --- a/src/utils/fetchFromApi.ts +++ b/src/utils/fetchFromApi.ts @@ -1,9 +1,10 @@ import omit from 'lodash/omit'; import getConfig from 'next/config'; -class FetchError extends Error { +class FetchError extends Error { + title?: string; status: number; - body?: any; + body?: TBody; constructor(status: number, message: string, body?: any) { super(message); @@ -18,15 +19,18 @@ type ErrorObject = { message: string; }; -export type DuplicatePlaceErrorBody = { +export type ErrorBody = { detail: string; - query?: string; - duplicatePlaceUri?: string; status: number; title: string; type: string; }; +export type DuplicatePlaceErrorBody = ErrorBody & { + query?: string; + duplicatePlaceUri?: string; +}; + const isErrorObject = (value: any): value is ErrorObject => { return ( value.type === 'ERROR' && From 63c93c35445f9f5d6391329da94a8e9c37b15524 Mon Sep 17 00:00:00 2001 From: Emma Fabre Date: Mon, 18 Nov 2024 14:58:34 +0100 Subject: [PATCH 15/21] Linting --- src/pages/organizers/[organizerId]/ownerships/index.page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx index f1ac2ba89..cbd69848b 100644 --- a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx +++ b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx @@ -28,11 +28,11 @@ import { Modal, ModalSizes, ModalVariants } from '@/ui/Modal'; import { Page } from '@/ui/Page'; import { Stack } from '@/ui/Stack'; import { Title } from '@/ui/Title'; +import { ErrorBody, FetchError } from '@/utils/fetchFromApi'; import { getApplicationServerSideProps } from '@/utils/getApplicationServerSideProps'; import { parseOfferId } from '@/utils/parseOfferId'; import { OwnershipsTable } from './OwnershipsTable'; -import { ErrorBody, FetchError } from '@/utils/fetchFromApi'; const ActionType = { APPROVE: 'confirm', From b1bfa87fcb5f8b04ddd85fd85a471ffead41a8d1 Mon Sep 17 00:00:00 2001 From: Emma Fabre Date: Mon, 18 Nov 2024 16:13:02 +0100 Subject: [PATCH 16/21] Add translations --- src/i18n/de.json | 10 ++++++++++ src/i18n/fr.json | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/i18n/de.json b/src/i18n/de.json index d2bae64b2..7aa75f1e9 100644 --- a/src/i18n/de.json +++ b/src/i18n/de.json @@ -1034,6 +1034,16 @@ }, "pending": "Ausstehende Anfragen zur Verwaltung", "close": "Schließen", + "request_modal": { + "title": "Verwalter zu {{name}} hinzufügen", + "email": "E-Mail-Adresse", + "email_error": "Not a valid email address", + "success": "{{ownerEmail}} ist jetzt Verwalter von {{organizerName}} und kann ab sofort die Organisationsseite und Veranstaltungen von {{organizerName}} bearbeiten.", + "actions": { + "confirm": "Verwalter hinzufügen", + "cancel": "Abbrechen" + } + }, "confirm_modal": { "title": "Verwaltungsantrag genehmigen", "body": "Sind Sie sicher, dass Sie den Antrag von {{ownerEmail}} genehmigen möchten?

Sobald Sie den Antrag genehmigen, kann {{ownerEmail}} die Organisationsseite und die Veranstaltungen von {{organizerName}} bearbeiten.", diff --git a/src/i18n/fr.json b/src/i18n/fr.json index 5de57e84f..8da7ae856 100644 --- a/src/i18n/fr.json +++ b/src/i18n/fr.json @@ -1034,6 +1034,16 @@ }, "pending": "Demandes de gestion en attente", "close": "Fermer", + "request_modal": { + "title": "Ajouter un gestionnaire à :organizer.name", + "email": "Adresse e-mail", + "email_error": "Adresse e-mail non valide", + "success": "{{ownerEmail}} est maintenant gestionnaire de {{organizerName}} et peut désormais modifier la page de l'organisation et les événements de {{organizerName}}", + "actions": { + "confirm": "Ajouter un gestionnaire", + "cancel": "Annuler" + } + }, "confirm_modal": { "title": "Approuver la demande de gestion", "body": "Êtes-vous sûr de vouloir approuver la demande de {{ownerEmail}} ?

Une fois approuvée, {{ownerEmail}} pourra modifier la page de l'organisation et les événements de {{organizerName}}.", From 5bd45a17768f829de241632ce4319352875538b4 Mon Sep 17 00:00:00 2001 From: Emma Fabre Date: Wed, 20 Nov 2024 15:37:23 +0100 Subject: [PATCH 17/21] Add start of ownership test --- src/test/e2e/create-organizer.spec.ts | 105 +++++++++++++++----------- 1 file changed, 62 insertions(+), 43 deletions(-) diff --git a/src/test/e2e/create-organizer.spec.ts b/src/test/e2e/create-organizer.spec.ts index b6792e1b5..ac57122dc 100644 --- a/src/test/e2e/create-organizer.spec.ts +++ b/src/test/e2e/create-organizer.spec.ts @@ -18,55 +18,74 @@ const dummyOrganizer = { }; test('create an organizer', async ({ baseURL, page }) => { - await page.goto(`${baseURL}/organizers/create`); + let organizerUrl; - await page.getByLabel('Naam').click(); - await page.getByLabel('Naam').fill(dummyOrganizer.name); - await page.getByLabel('Website', { exact: true }).click(); - await page - .getByLabel('Website', { exact: true }) - .fill(dummyOrganizer.website); - await page.getByRole('button', { name: 'Opslaan' }).click(); + await test.step('Step 1: Create an organizer', async () => { + await page.goto(`${baseURL}/organizers/create`); - await page.getByRole('tab', { name: 'Beschrijving' }).click(); - await page.getByLabel('rdw-editor').click(); - await page.getByLabel('rdw-editor').fill(dummyOrganizer.description); + await page.getByLabel('Naam').click(); + await page.getByLabel('Naam').fill(dummyOrganizer.name); + await page.getByLabel('Website', { exact: true }).click(); + await page + .getByLabel('Website', { exact: true }) + .fill(dummyOrganizer.website); + await page.getByRole('button', { name: 'Opslaan' }).click(); - await page.getByRole('tab', { name: 'Contact' }).click(); - await page.getByRole('button', { name: 'Contactgegevens toevoegen' }).click(); - await page.locator('#contact-info-value-1').click(); - await page.locator('#contact-info-value-1').fill(dummyOrganizer.email); - await page.locator('#contact-info-value-1').blur(); + await page.getByRole('tab', { name: 'Beschrijving' }).click(); + await page.getByLabel('rdw-editor').click(); + await page.getByLabel('rdw-editor').fill(dummyOrganizer.description); - await page.getByRole('tab', { name: 'Labels' }).click(); - await page.getByLabel('Verfijn met labels').click(); - await page.getByLabel('Verfijn met labels').fill(dummyOrganizer.label); - await page.getByLabel(dummyOrganizer.label).click(); - await page.getByText(dummyOrganizer.label).click(); + await page.getByRole('tab', { name: 'Contact' }).click(); + await page + .getByRole('button', { name: 'Contactgegevens toevoegen' }) + .click(); + await page.locator('#contact-info-value-1').click(); + await page.locator('#contact-info-value-1').fill(dummyOrganizer.email); + await page.locator('#contact-info-value-1').blur(); - await page.getByRole('tab', { name: 'Afbeeldingen' }).click(); - await page.getByRole('button', { name: 'Afbeelding toevoegen' }).click(); - await page.getByRole('button', { name: 'Kies bestand' }).click(); - await page - .locator('input[type=file]') - .setInputFiles('./src/test/data/image.png'); - await page.getByLabel('Beschrijving').click(); - await page.getByLabel('Beschrijving').fill(dummyOrganizer.image.name); - await page.getByLabel('Copyright').click(); - await page.getByLabel('Copyright').fill(dummyOrganizer.image.copyright); - await page.getByRole('button', { name: 'Uploaden' }).click(); - await page.getByText(`© ${dummyOrganizer.image.copyright}`).click(); + await page.getByRole('tab', { name: 'Labels' }).click(); + await page.getByLabel('Verfijn met labels').click(); + await page.getByLabel('Verfijn met labels').fill(dummyOrganizer.label); + await page.getByLabel(dummyOrganizer.label).click(); + await page.getByText(dummyOrganizer.label).click(); - await page.getByRole('tab', { name: 'Adres' }).click(); - await page.getByLabel('Gemeente').click(); - await page.getByLabel('Gemeente').fill(dummyOrganizer.location.municipality); - await page.getByLabel(dummyOrganizer.location.municipality).click(); - const streetField = await page.getByLabel('Straat en nummer').nth(0); - await streetField.click(); - await streetField.fill(dummyOrganizer.location.address); - await streetField.blur(); + await page.getByRole('tab', { name: 'Afbeeldingen' }).click(); + await page.getByRole('button', { name: 'Afbeelding toevoegen' }).click(); + await page.getByRole('button', { name: 'Kies bestand' }).click(); + await page + .locator('input[type=file]') + .setInputFiles('./src/test/data/image.png'); + await page.getByLabel('Beschrijving').click(); + await page.getByLabel('Beschrijving').fill(dummyOrganizer.image.name); + await page.getByLabel('Copyright').click(); + await page.getByLabel('Copyright').fill(dummyOrganizer.image.copyright); + await page.getByRole('button', { name: 'Uploaden' }).click(); + await page.getByText(`© ${dummyOrganizer.image.copyright}`).click(); - await page.getByText('100/100').click(); + await page.getByRole('tab', { name: 'Adres' }).click(); + await page.getByLabel('Gemeente').click(); + await page + .getByLabel('Gemeente') + .fill(dummyOrganizer.location.municipality); + await page.getByLabel(dummyOrganizer.location.municipality).click(); + const streetField = await page.getByLabel('Straat en nummer').nth(0); + await streetField.click(); + await streetField.fill(dummyOrganizer.location.address); + await streetField.blur(); - await page.getByRole('button', { name: 'Klaar met bewerken' }).click(); + await page.getByText('100/100').click(); + + await page + .getByRole('button', { name: 'Klaar met bewerken' }) + .click({ force: true }); + + await page.waitForURL('**/preview**'); + organizerUrl = await page.url(); + }); + + console.log(organizerUrl); + await test.step('Step 2: can assign ownerships on organizer', async () => { + await page.goto(organizerUrl.replace('preview', 'ownerships')); + await page.getByLabel('Nieuwe beheerder toevoegen').isVisible(); + }); }); From cf18752895083bcce05ee2ba45111e43c2270a0f Mon Sep 17 00:00:00 2001 From: Emma Fabre Date: Wed, 20 Nov 2024 15:50:22 +0100 Subject: [PATCH 18/21] Work on requesting ownership --- src/test/e2e/create-organizer.spec.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/test/e2e/create-organizer.spec.ts b/src/test/e2e/create-organizer.spec.ts index ac57122dc..4369e9d3c 100644 --- a/src/test/e2e/create-organizer.spec.ts +++ b/src/test/e2e/create-organizer.spec.ts @@ -1,5 +1,5 @@ import { faker } from '@faker-js/faker'; -import { test } from '@playwright/test'; +import { test, expect } from '@playwright/test'; const dummyOrganizer = { name: faker.lorem.word(), @@ -86,6 +86,15 @@ test('create an organizer', async ({ baseURL, page }) => { console.log(organizerUrl); await test.step('Step 2: can assign ownerships on organizer', async () => { await page.goto(organizerUrl.replace('preview', 'ownerships')); - await page.getByLabel('Nieuwe beheerder toevoegen').isVisible(); + await page + .getByRole('button', { name: 'Nieuwe beheerder toevoegen' }) + .click(); + await page.getByLabel('E-mailadres').fill(process.env.E2E_TEST_EMAIL); + await page.getByRole('button', { name: 'Beheerder toevoegen' }).click(); + await page.getByRole('dialog').isHidden(); + await expect(page.getByRole('alert').nth(1).textContent()).toContain( + process.env.E2E_TEST_EMAIL, + ); + await page.getByText(process.env.E2E_TEST_EMAIL).isVisible(); }); }); From c9106ec7ab6fa3fc9039224ab4669029ed3b1b68 Mon Sep 17 00:00:00 2001 From: Emma Fabre Date: Wed, 20 Nov 2024 15:51:00 +0100 Subject: [PATCH 19/21] Use correct organizer name --- src/pages/organizers/[organizerId]/ownerships/index.page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx index cbd69848b..b2000e546 100644 --- a/src/pages/organizers/[organizerId]/ownerships/index.page.tsx +++ b/src/pages/organizers/[organizerId]/ownerships/index.page.tsx @@ -303,7 +303,7 @@ const Ownership = () => { variant={ModalVariants.QUESTION} size={ModalSizes.MD} title={t('organizers.ownerships.request_modal.title', { - name: organizer.name, + name: organizerName, })} confirmTitle={t( 'organizers.ownerships.request_modal.actions.confirm', From c6671f3596f7fe74e6b0c2bb1ad96bd1c3f589ea Mon Sep 17 00:00:00 2001 From: Emma Fabre Date: Thu, 21 Nov 2024 11:53:49 +0100 Subject: [PATCH 20/21] Add E2E test to add and remove ownership --- .../ownerships/OwnershipsTable.tsx | 2 ++ src/test/e2e/create-organizer.spec.ts | 21 ++++++++++++++----- src/ui/Alert.tsx | 1 + 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/pages/organizers/[organizerId]/ownerships/OwnershipsTable.tsx b/src/pages/organizers/[organizerId]/ownerships/OwnershipsTable.tsx index 3c05b8967..07e118ebf 100644 --- a/src/pages/organizers/[organizerId]/ownerships/OwnershipsTable.tsx +++ b/src/pages/organizers/[organizerId]/ownerships/OwnershipsTable.tsx @@ -19,6 +19,7 @@ export const OwnershipsTable = ({ requests, renderActions }: Props) => { const { t } = useTranslation(); return ( { {requests.map((request) => ( { organizerUrl = await page.url(); }); - console.log(organizerUrl); await test.step('Step 2: can assign ownerships on organizer', async () => { await page.goto(organizerUrl.replace('preview', 'ownerships')); + + // Add ownership await page .getByRole('button', { name: 'Nieuwe beheerder toevoegen' }) .click(); await page.getByLabel('E-mailadres').fill(process.env.E2E_TEST_EMAIL); await page.getByRole('button', { name: 'Beheerder toevoegen' }).click(); - await page.getByRole('dialog').isHidden(); - await expect(page.getByRole('alert').nth(1).textContent()).toContain( + await expect(page.getByRole('dialog')).toBeHidden(); + await expect(page.getByTestId('alert-success')).toContainText( process.env.E2E_TEST_EMAIL, ); - await page.getByText(process.env.E2E_TEST_EMAIL).isVisible(); + await expect( + page.getByRole('row').getByText(process.env.E2E_TEST_EMAIL), + ).toBeVisible(); + await page.getByRole('row').getByRole('button').click(); + + // Delete ownership + await page.getByRole('button', { name: 'Beheerder verwijderen' }).click(); + await expect(page.getByRole('dialog')).toBeHidden(); + await expect( + page.getByRole('row').getByText(process.env.E2E_TEST_EMAIL), + ).toBeHidden(); }); }); diff --git a/src/ui/Alert.tsx b/src/ui/Alert.tsx index 6f98b2dcd..572d3451a 100644 --- a/src/ui/Alert.tsx +++ b/src/ui/Alert.tsx @@ -139,6 +139,7 @@ const Alert = ({ return ( Date: Thu, 21 Nov 2024 11:56:03 +0100 Subject: [PATCH 21/21] No braces I know --- .../organizers/[organizerId]/ownerships/OwnershipsTable.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/organizers/[organizerId]/ownerships/OwnershipsTable.tsx b/src/pages/organizers/[organizerId]/ownerships/OwnershipsTable.tsx index 07e118ebf..d183e77d4 100644 --- a/src/pages/organizers/[organizerId]/ownerships/OwnershipsTable.tsx +++ b/src/pages/organizers/[organizerId]/ownerships/OwnershipsTable.tsx @@ -43,7 +43,7 @@ export const OwnershipsTable = ({ requests, renderActions }: Props) => { {requests.map((request) => (