Skip to content

Commit

Permalink
Merge pull request #938 from cultuurnet/feature/III-6358
Browse files Browse the repository at this point in the history
  • Loading branch information
Anahkiasen authored Nov 28, 2024
2 parents bb3dda5 + 65464b2 commit d9487c2
Show file tree
Hide file tree
Showing 9 changed files with 237 additions and 72 deletions.
22 changes: 22 additions & 0 deletions src/hooks/api/ownerships.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,27 @@ export const RequestState = {

type RequestState = Values<typeof RequestState>;

const requestOwnership = async ({ headers, itemId, itemType, ownerEmail }) =>
fetchFromApi({
path: `/ownerships`,
options: {
method: 'POST',
headers,
body: JSON.stringify({
ownerEmail,
itemId,
itemType,
}),
},
});

const useRequestOwnershipMutation = (configuration: UseQueryOptions = {}) =>
useAuthenticatedMutation({
mutationFn: requestOwnership,
mutationKey: 'ownerships-request-ownership',
...configuration,
});

const getOwnershipRequests = async ({ headers, organizerId }) => {
const res = await fetchFromApi({
path: '/ownerships/',
Expand Down Expand Up @@ -151,4 +172,5 @@ export {
useGetOwnershipCreatorQuery,
useGetOwnershipRequestsQuery,
useRejectOwnershipRequestMutation,
useRequestOwnershipMutation,
};
10 changes: 10 additions & 0 deletions src/i18n/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -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? <br/><br/> Sobald Sie den Antrag genehmigen, kann {{ownerEmail}} die Organisationsseite und die Veranstaltungen von {{organizerName}} bearbeiten.",
Expand Down
10 changes: 10 additions & 0 deletions src/i18n/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -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}} ? <br/><br/> Une fois approuvée, {{ownerEmail}} pourra modifier la page de l'organisation et les événements de {{organizerName}}.",
Expand Down
10 changes: 10 additions & 0 deletions src/i18n/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -1034,6 +1034,16 @@
},
"pending": "Openstaande aanvragen tot beheer",
"close": "Sluiten",
"request_modal": {
"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"
}
},
"confirm_modal": {
"title": "Aanvraag tot beheer goedkeuren",
"body": "Ben je zeker dat je de aanvraag van {{ownerEmail}} wilt goedkeuren? <br/><br/> Van zodra je de aanvraag goedkeurt zal {{ownerEmail}} de organisatiepagina en de evenementen van {{organizerName}} kunnen bewerken.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const OwnershipsTable = ({
const { t } = useTranslation();
return (
<Stack
role="table"
flex={1}
padding={4}
marginBottom={5}
Expand All @@ -48,6 +49,7 @@ export const OwnershipsTable = ({
{requests.map((request) => (
<Inline
key={request.id}
role="row"
justifyContent="space-between"
alignItems="center"
css={`
Expand Down
113 changes: 90 additions & 23 deletions src/pages/organizers/[organizerId]/ownerships/index.page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import groupBy from 'lodash/groupBy';
import { useRouter } from 'next/router';
import { useMemo, useState } from 'react';
import { useForm } from 'react-hook-form';
import { Trans, useTranslation } from 'react-i18next';
import { dehydrate, useQueryClient } from 'react-query';

Expand All @@ -13,26 +14,31 @@ import {
useGetOwnershipCreatorQuery,
useGetOwnershipRequestsQuery,
useRejectOwnershipRequestMutation,
useRequestOwnershipMutation,
} from '@/hooks/api/ownerships';
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 { Icon } from '@/ui/Icon';
import { FormElement } from '@/ui/FormElement';
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 { ErrorBody, FetchError } from '@/utils/fetchFromApi';
import { getApplicationServerSideProps } from '@/utils/getApplicationServerSideProps';
import { parseOfferId } from '@/utils/parseOfferId';

import { OwnershipsTable } from './OwnershipsTable';

const ActionType = {
APPROVE: 'approve',
APPROVE: 'confirm',
REJECT: 'reject',
REQUEST: 'request',
} as const;

type ActionType = Values<typeof ActionType>;
Expand All @@ -41,24 +47,25 @@ const Ownership = () => {
const router = useRouter();
const { t, i18n } = useTranslation();
const queryClient = useQueryClient();
const [selectedRequest, setSelectedRequest] = useState<OwnershipRequest>();
const [requestToBeDeleted, setRequestToBeDeleted] =
useState<OwnershipRequest>();
const [isQuestionModalVisible, setIsQuestionModalVisible] = useState(false);
const [actionType, setActionType] = useState<ActionType>();
const [isOpen, setIsOpen] = useState(false);
const [isQuestionModalVisible, setIsQuestionModalVisible] = useState(false);
const [isSuccessAlertVisible, setIsSuccessAlertVisible] = useState(false);
const isApproveAction = actionType === ActionType.APPROVE;
const translationsPath = `organizers.ownerships.${
isApproveAction ? 'confirm' : 'reject'
}_modal`;
const [requestToBeDeleted, setRequestToBeDeleted] =
useState<OwnershipRequest>();
const [selectedRequest, setSelectedRequest] = useState<OwnershipRequest>();
const translationsPath = `organizers.ownerships.${actionType}_modal`;
const { register, formState, getValues, setError } = useForm();

const organizerId = useMemo(
() => router.query.organizerId as string,
[router.query.organizerId],
);

const getOrganizerByIdQuery = useGetOrganizerByIdQuery({
id: organizerId,
});

// @ts-expect-error
const organizer: Organizer = getOrganizerByIdQuery?.data;
const organizerName =
Expand All @@ -67,7 +74,7 @@ const Ownership = () => {
organizer?.name;

const getOwnershipRequestsQuery = useGetOwnershipRequestsQuery({
organizerId: organizerId,
organizerId,
});

const getOwnershipCreatorQuery = useGetOwnershipCreatorQuery({
Expand Down Expand Up @@ -99,6 +106,25 @@ const Ownership = () => {
},
});

const approveRequestedOwnership = async (ownershipId: string) => {
setIsSuccessAlertVisible(true);
setIsOpen(false);

return approveOwnershipRequestMutation.mutateAsync({ ownershipId });
};

const requestOwnership = useRequestOwnershipMutation({
onError: async (error: FetchError<ErrorBody>) => {
if (error.body.status === 409) {
const ownershipId = error.body.detail.split('with id ')[1];
await approveRequestedOwnership(ownershipId);
} else {
setError('email', { message: error.body.detail || error.title });
}
},
onSuccess: (data: { id: string }) => approveRequestedOwnership(data.id),
});

const rejectOwnershipRequestMutation = useRejectOwnershipRequestMutation({
onSuccess: async () => {
await queryClient.invalidateQueries('ownership-requests');
Expand All @@ -115,14 +141,21 @@ 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:
return requestOwnership.mutate({
ownerEmail: getValues('email'),
itemType: 'organizer',
itemId: parseOfferId(organizer['@id']),
});
}
};

Expand Down Expand Up @@ -153,8 +186,9 @@ const Ownership = () => {
<Trans
i18nKey={`${translationsPath}.success`}
values={{
ownerEmail: selectedRequest?.ownerEmail,
organizerName: organizerName,
ownerEmail:
selectedRequest?.ownerEmail ?? getValues('email'),
organizerName,
}}
/>
</Alert>
Expand Down Expand Up @@ -247,7 +281,7 @@ const Ownership = () => {
i18nKey={`${translationsPath}.body`}
values={{
ownerEmail: selectedRequest?.ownerEmail,
organizerName: organizerName,
organizerName,
}}
/>
</Box>
Expand All @@ -256,7 +290,14 @@ const Ownership = () => {
)}
</Stack>
<Stack spacing={3.5} flex={1}>
<Button variant={ButtonVariants.PRIMARY}>
<Button
variant={ButtonVariants.PRIMARY}
onClick={() => {
setIsSuccessAlertVisible(false);
setActionType(ActionType.REQUEST);
setIsOpen(true);
}}
>
{t('organizers.ownerships.actions.add')}
</Button>
<Button
Expand All @@ -269,6 +310,32 @@ const Ownership = () => {
</Button>
</Stack>
</Inline>
<Modal
visible={isOpen}
variant={ModalVariants.QUESTION}
size={ModalSizes.MD}
title={t('organizers.ownerships.request_modal.title', {
name: organizerName,
})}
confirmTitle={t(
'organizers.ownerships.request_modal.actions.confirm',
)}
cancelTitle={t('organizers.ownerships.request_modal.actions.cancel')}
onConfirm={handleConfirm}
onClose={() => setIsOpen(false)}
>
<Stack padding={4}>
<FormElement
id={'email'}
Component={<Input type={'email'} {...register('email')} />}
label={t('organizers.ownerships.request_modal.email')}
error={
formState.errors.email &&
t(`organizers.ownerships.request_modal.email_error`)
}
/>
</Stack>
</Modal>
</Page.Content>
</Page>
);
Expand Down
Loading

0 comments on commit d9487c2

Please sign in to comment.