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

III-6365 - Add ownerships managements page #956

Open
wants to merge 38 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
0dcc64f
Add ownerships managements page
simon-debruijn Nov 20, 2024
40e82de
Add filtering on state
simon-debruijn Nov 20, 2024
eb35ba9
Fix css issue
simon-debruijn Nov 20, 2024
da74f7a
Change organizerId to itemId
simon-debruijn Nov 21, 2024
a24909a
Accept defaultValue for Input
simon-debruijn Nov 21, 2024
580450f
Add useShallowRouter hook
simon-debruijn Nov 21, 2024
1bc4b19
Add basic ownership overview search
simon-debruijn Nov 21, 2024
e410e71
Filter undefined values from cache key queries
simon-debruijn Nov 21, 2024
61b30bd
Add ownerships link to dashboard
simon-debruijn Nov 21, 2024
2260698
Refactor OwnershipsTable
simon-debruijn Nov 21, 2024
f1a6e09
Add shouldShowItemId
simon-debruijn Nov 21, 2024
8a4ba72
Fix styling table
simon-debruijn Nov 22, 2024
1f81c38
make prop optional
simon-debruijn Nov 22, 2024
340394a
Show ownerId
simon-debruijn Nov 22, 2024
2098daa
Add maxWidth
simon-debruijn Nov 22, 2024
4765374
Merge branch 'main' into III-6365-manage-ownerships
simon-debruijn Nov 22, 2024
d7609a3
Merge branch 'main' into III-6365-manage-ownerships
simon-debruijn Dec 9, 2024
11c99f9
Add GetOrganizersByQueryResponse type
simon-debruijn Dec 9, 2024
ea985a9
Conditionally show owner email
simon-debruijn Dec 9, 2024
b9f92ee
Add queries
simon-debruijn Dec 9, 2024
109b263
Add search on name and id
simon-debruijn Dec 9, 2024
1a37ce1
Add actions
simon-debruijn Dec 9, 2024
c467b7d
Add no results text
simon-debruijn Dec 9, 2024
1127897
Fix styling ownership table
simon-debruijn Dec 10, 2024
1068932
Only show owner id on manage page
simon-debruijn Dec 10, 2024
080761d
Add useOwnershipActions hook
simon-debruijn Dec 10, 2024
ecf0040
Add OwnershipActionsAlert
simon-debruijn Dec 10, 2024
f134bc7
Add triggerSuccess helper
simon-debruijn Dec 11, 2024
968b4be
Use the same constant
simon-debruijn Dec 11, 2024
1ac93c9
Fix dependency in use effect
simon-debruijn Dec 11, 2024
37c20a0
Use successfulAction
simon-debruijn Dec 11, 2024
253094b
Add translation for page
simon-debruijn Dec 11, 2024
c770e0c
Add type
simon-debruijn Dec 11, 2024
73b4b7a
Add translation to organizer picker
simon-debruijn Dec 11, 2024
ca54d9b
Add todo
simon-debruijn Dec 11, 2024
af0a970
Merge branch 'main' into III-6365-manage-ownerships
simon-debruijn Dec 11, 2024
ceb1c68
Add translations no results
simon-debruijn Dec 11, 2024
3387e43
Change icon to users
simon-debruijn Dec 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/constants/Regex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@ const URL_REGEX: RegExp =
/^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?!&\/=]*)$/;
const PHONE_REGEX: RegExp = /^[0-9\/\-_.+ ]{0,15}$/;

export { EMAIL_REGEX, PHONE_REGEX, URL_REGEX };
const UUID_V4_REGEX =
/^[A-F\d]{8}-[A-F\d]{4}-4[A-F\d]{3}-[89AB][A-F\d]{3}-[A-F\d]{12}$/i;

export { EMAIL_REGEX, PHONE_REGEX, URL_REGEX, UUID_V4_REGEX };
14 changes: 10 additions & 4 deletions src/hooks/api/authenticated-query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,16 @@ const QueryStatus = {

const prepareKey = ({ queryKey, queryArguments }) => {
const key = Array.isArray(queryKey) ? queryKey : [queryKey];
return [
...flatten(key),
Object.keys(queryArguments ?? {}).length > 0 ? queryArguments : undefined,
].filter((key) => key !== undefined);
const args = Object.entries(queryArguments ?? {}).filter(
([_, value]) => typeof value !== 'undefined',
);
const preparedKey = flatten(key);

if (args.length > 0) {
preparedKey.push(Object.fromEntries(args));
}

return preparedKey;
};

const prepareArguments = ({
Expand Down
19 changes: 9 additions & 10 deletions src/hooks/api/organizers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,7 @@ type HeadersAndQueryData = {
headers: Headers;
} & { [x: string]: string };

type GetOrganizersArgumentsByQuery = {
headers: Headers;
embed: string;
q: string;
};
export type GetOrganizersByQueryResponse = { member: Organizer[] };

const useGetOrganizersByQueryQuery = (
{
Expand All @@ -37,7 +33,7 @@ const useGetOrganizersByQueryQuery = (
}: AuthenticatedQueryOptions<{ name?: string } & PaginationOptions> = {},
configuration: UseQueryOptions = {},
) =>
useAuthenticatedQuery<{ member: Organizer[] }>({
useAuthenticatedQuery<GetOrganizersByQueryResponse>({
req,
queryClient,
queryKey: ['organizers'],
Expand All @@ -48,8 +44,8 @@ const useGetOrganizersByQueryQuery = (
start: paginationOptions.start,
limit: paginationOptions.limit,
},
enabled: !!name,
...configuration,
enabled: !!name && configuration.enabled === true,
});

type GetOrganizersArguments = {
Expand Down Expand Up @@ -115,6 +111,8 @@ type GetOrganizerByIdArguments = {
id: string;
};

export type GetOrganizerByIdResponse = Organizer | undefined;

const getOrganizerById = async ({ headers, id }: GetOrganizerByIdArguments) => {
const res = await fetchFromApi({
path: `/organizers/${id.toString()}`,
Expand All @@ -130,11 +128,12 @@ const getOrganizerById = async ({ headers, id }: GetOrganizerByIdArguments) => {
};

const useGetOrganizerByIdQuery = (
{ id, ...options },
{ id, req, queryClient }: { id: string } & ServerSideQueryOptions,
configuration: UseQueryOptions = {},
) =>
useAuthenticatedQuery({
...options,
useAuthenticatedQuery<GetOrganizerByIdResponse>({
req,
queryClient,
queryKey: ['organizers'],
queryFn: getOrganizerById,
queryArguments: { id },
Expand Down
118 changes: 94 additions & 24 deletions src/hooks/api/ownerships.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { UseQueryOptions } from 'react-query';
import { UseMutationResult, UseQueryOptions } from 'react-query';

import { Values } from '@/types/Values';
import { fetchFromApi, isErrorObject } from '@/utils/fetchFromApi';

import {
PaginationOptions,
ServerSideQueryOptions,
useAuthenticatedMutation,
useAuthenticatedQuery,
Expand All @@ -15,22 +16,35 @@ export type OwnershipRequest = {
ownerId: string;
ownerEmail: string;
requesterId: string;
state: RequestState;
state: OwnershipState;
};

export type OwnershipCreator = {
userId: string;
email: string;
};

export const RequestState = {
APPROVED: 'approved',
export const OwnershipState = {
REQUESTED: 'requested',
APPROVED: 'approved',
REJECTED: 'rejected',
DELETED: 'deleted',
} as const;

type RequestState = Values<typeof RequestState>;
export type OwnershipState = Values<typeof OwnershipState>;

type RequestOwnershipArguments = {
itemId: string;
ownerEmail?: string;
ownerId?: string;
};

const requestOwnership = async ({ headers, itemId, ownerEmail, ownerId }) =>
const requestOwnership = async ({
headers,
itemId,
ownerEmail,
ownerId,
}: { headers: Headers } & RequestOwnershipArguments) =>
fetchFromApi({
path: `/ownerships`,
options: {
Expand All @@ -50,15 +64,37 @@ const useRequestOwnershipMutation = (configuration: UseQueryOptions = {}) =>
mutationFn: requestOwnership,
mutationKey: 'ownerships-request-ownership',
...configuration,
});

const getOwnershipRequests = async ({ headers, organizerId, ownerId }) => {
}) as UseMutationResult<void, Error, RequestOwnershipArguments>;

const getOwnershipRequests = async ({
headers,
itemId,
ownerId,
state,
paginationOptions,
}: {
headers: Headers;
itemId?: string;
ownerId?: string;
state?: OwnershipState;
} & PaginationOptions) => {
const searchParams = new URLSearchParams();
if (paginationOptions) {
searchParams.set('limit', `${paginationOptions.limit}`);
searchParams.set('offset', `${paginationOptions.start}`);
}
if (itemId) {
searchParams.set('itemId', itemId);
}
if (ownerId) {
searchParams.set('ownerId', ownerId);
}
if (state) {
searchParams.set('state', state);
}
const res = await fetchFromApi({
path: '/ownerships/',
searchParams: {
itemId: organizerId,
...(ownerId && { ownerId }),
},
searchParams,
options: {
headers,
},
Expand All @@ -71,25 +107,47 @@ const getOwnershipRequests = async ({ headers, organizerId, ownerId }) => {
};

type UseGetOwnershipRequestsArguments = ServerSideQueryOptions & {
organizerId: string;
itemId?: string;
ownerId?: string;
state?: OwnershipState;
} & PaginationOptions;

export type GetOwnershipRequestsResponse = {
'@context': string;
'@type': string;
itemsPerPage: number;
totalItems: number;
member: OwnershipRequest[];
};

const useGetOwnershipRequestsQuery = (
{ req, queryClient, organizerId, ownerId }: UseGetOwnershipRequestsArguments,
{
req,
queryClient,
itemId,
ownerId,
state,
paginationOptions,
}: UseGetOwnershipRequestsArguments,
configuration: UseQueryOptions = {},
) =>
useAuthenticatedQuery<OwnershipRequest[]>({
useAuthenticatedQuery<GetOwnershipRequestsResponse>({
req,
queryClient,
queryKey: ['ownership-requests'],
queryFn: getOwnershipRequests,
queryArguments: { organizerId, ...(ownerId && { ownerId }) },
queryArguments: { itemId, ownerId, state, paginationOptions },
refetchOnWindowFocus: false,
...configuration,
});

const approveOwnershipRequest = async ({ headers, ownershipId }) =>
type ApproveOwnershipArguments = { ownershipId: string };

const approveOwnershipRequest = async ({
headers,
ownershipId,
}: {
headers: Headers;
} & ApproveOwnershipArguments) =>
fetchFromApi({
path: `/ownerships/${ownershipId}/approve`,
options: {
Expand All @@ -103,9 +161,16 @@ const useApproveOwnershipRequestMutation = (configuration = {}) =>
mutationFn: approveOwnershipRequest,
mutationKey: 'approve-ownership-request',
...configuration,
});
}) as UseMutationResult<void, Error, ApproveOwnershipArguments>;

type RejectOwnershipArguments = { ownershipId: string };

const rejectOwnershipRequest = async ({ headers, ownershipId }) =>
const rejectOwnershipRequest = async ({
headers,
ownershipId,
}: {
headers: Headers;
} & RejectOwnershipArguments) =>
fetchFromApi({
path: `/ownerships/${ownershipId}/reject`,
options: {
Expand All @@ -119,9 +184,14 @@ const useRejectOwnershipRequestMutation = (configuration = {}) =>
mutationFn: rejectOwnershipRequest,
mutationKey: 'reject-ownership-request',
...configuration,
});
}) as UseMutationResult<void, Error, RejectOwnershipArguments>;

type DeleteOwnershipArguments = { ownershipId: string };

const deleteOwnershipRequest = async ({ headers, ownershipId }) =>
const deleteOwnershipRequest = async ({
headers,
ownershipId,
}: { headers: Headers } & DeleteOwnershipArguments) =>
fetchFromApi({
path: `/ownerships/${ownershipId}`,
options: {
Expand All @@ -135,7 +205,7 @@ const useDeleteOwnershipRequestMutation = (configuration = {}) =>
mutationFn: deleteOwnershipRequest,
mutationKey: 'delete-ownership-request',
...configuration,
});
}) as UseMutationResult<void, Error, DeleteOwnershipArguments>;

const getOwnershipCreator = async ({ headers, organizerId }) => {
const res = await fetchFromApi({
Expand Down
Loading
Loading