Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added suggested organizers to dashboard #965

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from
31 changes: 30 additions & 1 deletion src/hooks/api/organizers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,11 @@ const useGetOrganizersByQueryQuery = (
req,
queryClient,
name,
q,
paginationOptions = { start: 0, limit: 10 },
}: AuthenticatedQueryOptions<{ name?: string } & PaginationOptions> = {},
}: AuthenticatedQueryOptions<
{ name?: string; q?: string } & PaginationOptions
> = {},
configuration: UseQueryOptions = {},
) =>
useAuthenticatedQuery<{ member: Organizer[] }>({
Expand All @@ -44,6 +47,7 @@ const useGetOrganizersByQueryQuery = (
queryFn: getOrganizers,
queryArguments: {
embed: true,
q,
name,
start: paginationOptions.start,
limit: paginationOptions.limit,
Expand All @@ -57,6 +61,7 @@ type GetOrganizersArguments = {
embed?: string;
website?: string;
name?: string;
q?: string;
limit?: string;
start?: string;
};
Expand All @@ -65,6 +70,7 @@ const getOrganizers = async ({
headers,
website,
name,
q,
embed,
limit,
start,
Expand All @@ -73,6 +79,7 @@ const getOrganizers = async ({
path: '/organizers',
searchParams: {
embed: `${embed}`,
...(q && { q }),
...(website && { website }),
...(name && { name }),
...(limit && { limit }),
Expand Down Expand Up @@ -197,6 +204,27 @@ const useGetOrganizerPermissions = (
...configuration,
});

const getSuggestedOrganizersQuery = async ({ headers }) => {
const res = await fetchFromApi({
path: '/ownerships/suggestions',
options: { headers },
searchParams: { itemType: 'organizer' },
});

return handleErrorObject(res);
};

const useGetSuggestedOrganizersQuery = (
{},
configuration: UseQueryOptions = {},
) =>
useAuthenticatedQuery({
queryKey: ['ownership-suggestions'],
queryFn: getSuggestedOrganizersQuery,
refetchOnWindowFocus: false,
...configuration,
});

const deleteOrganizerById = async ({ headers, id }) =>
fetchFromApi({
path: `/organizers/${id}`,
Expand Down Expand Up @@ -393,6 +421,7 @@ export {
useGetOrganizersByCreatorQuery,
useGetOrganizersByQueryQuery,
useGetOrganizersByWebsiteQuery,
useGetSuggestedOrganizersQuery,
useUpdateOrganizerEducationalDescriptionMutation,
useUpdateOrganizerMutation,
};
4 changes: 4 additions & 0 deletions src/i18n/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,10 @@
"organizers": "Mijn organisaties",
"places": "Mijn locaties"
},
"suggestions": {
"title": "Organisaties waarvoor je eerder al invoerde",
"description": "Voor deze organisaties voerde je eerder al evenementen in, maar je bent nog geen beheerder van deze organisaties. Ben je betrokken bij het bestuur van deze organisaties en wil je de organisatiepagina en evenementen ervan beheren? Start hier je aanvraag om beheerder te worden. Zodra een huidige beheerder je aanvraag goedkeurt, krijg je toegang en ontvang je een bevestiging via e-mail."
},
"welcome": "Welkom"
},
"description": "UiTdatabank levert informatie aan meer dan 1.000 agenda's, waaronder UiTinvlaanderen, websites van steden en gemeenten, thema-agenda's, gedrukte bladen en mobiele apps. Ook jouw activiteit kan verschijnen op vele agenda's.",
Expand Down
117 changes: 89 additions & 28 deletions src/pages/dashboard/index.page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { format, isAfter, isFuture } from 'date-fns';
import getConfig from 'next/config';
import { useRouter } from 'next/router';
import { useMemo, useState } from 'react';
import React, { ComponentType, useMemo, useState } from 'react';
import { Trans, useTranslation } from 'react-i18next';
import { useQueryClient } from 'react-query';
import { useQueryClient, UseQueryResult } from 'react-query';
import { dehydrate } from 'react-query/hydration';

import { CalendarType } from '@/constants/CalendarType';
Expand All @@ -16,6 +16,8 @@ import {
import {
useDeleteOrganizerByIdMutation,
useGetOrganizersByCreatorQuery,
useGetOrganizersByQueryQuery,
useGetSuggestedOrganizersQuery,
} from '@/hooks/api/organizers';
import {
useDeletePlaceByIdMutation,
Expand All @@ -27,6 +29,7 @@ import {
useGetUserQueryServerSide,
User,
} from '@/hooks/api/user';
import { SupportedLanguage } from '@/i18n/index';
import { PermissionTypes } from '@/layouts/Sidebar';
import { Footer } from '@/pages/Footer';
import type { Event } from '@/types/Event';
Expand All @@ -53,7 +56,9 @@ import { Stack } from '@/ui/Stack';
import { Tabs } from '@/ui/Tabs';
import { Text, TextVariants } from '@/ui/Text';
import { colors, getValueFromTheme } from '@/ui/theme';
import { Title } from '@/ui/Title';
import { getApplicationServerSideProps } from '@/utils/getApplicationServerSideProps';
import { getLanguageObjectOrFallback } from '@/utils/getLanguageObjectOrFallback';
import { parseOfferId } from '@/utils/parseOfferId';
import { parseOfferType } from '@/utils/parseOfferType';

Expand Down Expand Up @@ -313,11 +318,13 @@ const OfferRow = ({ item: offer, onDelete, ...props }: OfferRowProps) => {
type OrganizerRowProps = InlineProps & {
item: Organizer;
onDelete: (item: Organizer) => void;
actions?: React.ReactNode[];
};

const OrganizerRow = ({
item: organizer,
onDelete,
actions,
...props
}: OrganizerRowProps) => {
const { t, i18n } = useTranslation();
Expand All @@ -343,28 +350,36 @@ const OrganizerRow = ({

return (
<DashboardRow
title={
organizer.name[i18n.language] ?? organizer.name[organizer.mainLanguage]
}
title={getLanguageObjectOrFallback(
organizer.name,
i18n.language as SupportedLanguage,
organizer.mainLanguage as SupportedLanguage,
)}
url={previewUrl}
imageUrl={imageUrl}
score={score}
scope={ScopeTypes.ORGANIZERS}
isImageUploading={isImageUploading}
onModalOpen={() => setIsPictureUploadModalVisible(true)}
actions={[
<Link href={editUrl} variant={LinkVariants.BUTTON_SECONDARY} key="edit">
{t('dashboard.actions.edit')}
</Link>,
<Dropdown.Item href={previewUrl} key="preview">
{t('dashboard.actions.preview')}
</Dropdown.Item>,
permissions?.includes(PermissionTypes.ORGANISATIES_BEHEREN) && (
<Dropdown.Item onClick={() => onDelete(organizer)} key="delete">
{t('dashboard.actions.delete')}
</Dropdown.Item>
),
]}
actions={
actions || [
<Link
href={editUrl}
variant={LinkVariants.BUTTON_SECONDARY}
key="edit"
>
{t('dashboard.actions.edit')}
</Link>,
<Dropdown.Item href={previewUrl} key="preview">
{t('dashboard.actions.preview')}
</Dropdown.Item>,
permissions?.includes(PermissionTypes.ORGANISATIES_BEHEREN) && (
<Dropdown.Item onClick={() => onDelete(organizer)} key="delete">
{t('dashboard.actions.delete')}
</Dropdown.Item>
),
]
}
status={{
isExternalCreator,
}}
Expand All @@ -383,16 +398,33 @@ const OrganizerRow = ({
);
};

const SuggestedOrganizerRow = (props) => (
<OrganizerRow {...props} actions={[]} />
);

type TabContentProps = {
tab: string;
status: string;
items: Item[];
totalItems: number;
page: number;
Row: ComponentType<any>;
actions?: React.ReactNode[];
onChangePage: (page: number) => void;
onDelete: (item: Item) => void;
};

const TabContent = ({
tab,
items,
status,
Row,
page,
actions,
totalItems,
onDelete,
onChangePage,
}) => {
}: TabContentProps) => {
const { t } = useTranslation();

const hasMoreThanOnePage = Math.ceil(totalItems / itemsPerPage) > 1;
Expand All @@ -411,7 +443,7 @@ const TabContent = ({
);
}

if (items.length === 0) {
if (!items?.length) {
return (
<Panel
css={`
Expand All @@ -438,7 +470,7 @@ const TabContent = ({
`}
>
<List>
{items.map((item, index) => (
{items.map((item) => (
<List.Item
key={item['@id']}
backgroundColor={getValue('listItem.backgroundColor')}
Expand Down Expand Up @@ -543,7 +575,24 @@ const Dashboard = (): any => {
);
};

const UseGetItemsByCreatorQuery = useGetItemsByCreator({
// @ts-expect-error
const suggestedOrganizerIds: UseQueryResult<{ member: { '@id': string }[] }> =
useGetSuggestedOrganizersQuery({}, { enabled: tab === 'organizers' });

// @ts-expect-error
const suggestedOrganizers: UseQueryResult<{ member: Organizer[] }> =
useGetOrganizersByQueryQuery(
{
q: suggestedOrganizerIds.data?.member
.map((result) => `id:${parseOfferId(result['@id'])}`)
.join(' OR '),
},
{
enabled: suggestedOrganizerIds.data?.member?.length > 0,
},
);

const getItemsByCreatorQuery = useGetItemsByCreator({
creator: user,
sortOptions: { field: sortingField, order: sortingOrder },
paginationOptions: {
Expand All @@ -552,19 +601,19 @@ const Dashboard = (): any => {
},
});

const UseDeleteItemByIdMutation = useDeleteItemById({
const deleteItemByIdMutation = useDeleteItemById({
onSuccess: async () => {
await queryClient.invalidateQueries(tab);
},
});

const items = UseGetItemsByCreatorQuery.data?.member ?? [];
const items = getItemsByCreatorQuery.data?.member ?? [];

const sharedTableContentProps = {
tab,
status: UseGetItemsByCreatorQuery.status,
status: getItemsByCreatorQuery.status,
items,
totalItems: UseGetItemsByCreatorQuery.data?.totalItems ?? 0,
totalItems: getItemsByCreatorQuery.data?.totalItems ?? 0,
page,
onChangePage: async (page: number) => {
await router.push({ pathname, query: { ...query, page } }, undefined, {
Expand Down Expand Up @@ -688,7 +737,19 @@ const Dashboard = (): any => {
title={t('dashboard.tabs.organizers')}
>
{tab === 'organizers' && (
<TabContent {...sharedTableContentProps} Row={OrganizerRow} />
<>
<TabContent {...sharedTableContentProps} Row={OrganizerRow} />
<Title>{t('dashboard.suggestions.title')}</Title>
<Alert variant={AlertVariants.PRIMARY} marginY={4}>
{t('dashboard.suggestions.description')}
</Alert>
<TabContent
{...sharedTableContentProps}
Row={SuggestedOrganizerRow}
items={suggestedOrganizers.data?.member}
status={suggestedOrganizers.status}
/>
</>
)}
</Tabs.Tab>
</Tabs>
Expand All @@ -702,7 +763,7 @@ const Dashboard = (): any => {
variant={ModalVariants.QUESTION}
visible={isModalVisible}
onConfirm={async () => {
UseDeleteItemByIdMutation.mutate({
deleteItemByIdMutation.mutate({
id: parseOfferId(toBeDeletedItem['@id']),
});
setIsModalVisible(false);
Expand Down
Loading