Files
docmost/apps/client/src/features/space/queries/space-query.ts
Philip Okugbe b81c9ee10c feat: cloud and ee (#805)
* stripe init
git submodules for enterprise modules

* * Cloud billing UI - WIP
* Proxy websockets in dev mode
* Separate workspace login and creation for cloud
* Other fixes

* feat: billing (cloud)

* * add domain service
* prepare links from workspace hostname

* WIP

* Add exchange token generation
* Validate JWT token type during verification

* domain service

* add SkipTransform decorator

* * updates (server)
* add new packages
* new sso migration file

* WIP

* Fix hostname generation

* WIP

* WIP

* Reduce input error font-size
* set max password length

* jwt package

* license page - WIP

* * License management UI
* Move license key store to db

* add reflector

* SSO enforcement

* * Add default plan
* Add usePlan hook

* * Fix auth container margin in mobile
* Redirect login and home to select page in cloud

* update .gitignore

* Default to yearly

* * Trial messaging
* Handle ended trials

* Don't set to readonly on collab disconnect (Cloud)

* Refine trial (UI)
* Fix bug caused by using jotai optics atom in AppHeader component

* configurable database maximum pool

* Close SSO form on save

* wip

* sync

* Only show sign-in in cloud

* exclude base api part from workspaceId check

* close db connection beforeApplicationShutdown

* Add health/live endpoint

* clear cookie on hostname change

* reset currentUser atom

* Change text

* return 401 if workspace does not match

* feat: show user workspace list in cloud login page

* sync

* Add home path

* Prefetch to speed up queries

* * Add robots.txt
* Disallow login and forgot password routes

* wildcard user-agent

* Fix space query cache

* fix

* fix

* use space uuid for recent pages

* prefetch billing plans

* enhance license page

* sync
2025-03-06 13:38:37 +00:00

231 lines
6.5 KiB
TypeScript

import {
keepPreviousData,
useMutation,
useQuery,
useQueryClient,
UseQueryResult,
} from "@tanstack/react-query";
import {
IAddSpaceMember,
IChangeSpaceMemberRole,
IRemoveSpaceMember,
ISpace,
ISpaceMember,
} from "@/features/space/types/space.types";
import {
addSpaceMember,
changeMemberRole,
getSpaceById,
getSpaceMembers,
getSpaces,
removeSpaceMember,
createSpace,
updateSpace,
deleteSpace,
} from "@/features/space/services/space-service.ts";
import { notifications } from "@mantine/notifications";
import { IPagination, QueryParams } from "@/lib/types.ts";
import { queryClient } from "@/main.tsx";
import { getRecentChanges } from "@/features/page/services/page-service.ts";
import { useEffect } from "react";
import { validate as isValidUuid } from "uuid";
export function useGetSpacesQuery(
params?: QueryParams,
): UseQueryResult<IPagination<ISpace>, Error> {
return useQuery({
queryKey: ["spaces", params],
queryFn: () => getSpaces(params),
placeholderData: keepPreviousData,
});
}
export function useSpaceQuery(spaceId: string): UseQueryResult<ISpace, Error> {
const query = useQuery({
queryKey: ["space", spaceId],
queryFn: () => getSpaceById(spaceId),
enabled: !!spaceId,
});
useEffect(() => {
if (query.data) {
if (isValidUuid(spaceId)) {
queryClient.setQueryData(["space", query.data.slug], query.data);
} else {
queryClient.setQueryData(["space", query.data.id], query.data);
}
}
}, [query.data]);
return query;
}
export const prefetchSpace = (spaceSlug: string, spaceId?: string) => {
queryClient.prefetchQuery({
queryKey: ["space", spaceSlug],
queryFn: () => getSpaceById(spaceSlug),
});
if (spaceId) {
// this endpoint only accepts uuid for now
queryClient.prefetchQuery({
queryKey: ["recent-changes", spaceId],
queryFn: () => getRecentChanges(spaceId),
});
}
};
export function useCreateSpaceMutation() {
const queryClient = useQueryClient();
return useMutation<ISpace, Error, Partial<ISpace>>({
mutationFn: (data) => createSpace(data),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["spaces"],
});
notifications.show({ message: "Space created successfully" });
},
onError: (error) => {
const errorMessage = error["response"]?.data?.message;
notifications.show({ message: errorMessage, color: "red" });
},
});
}
export function useGetSpaceBySlugQuery(
spaceId: string,
): UseQueryResult<ISpace, Error> {
return useQuery({
queryKey: ["space", spaceId],
queryFn: () => getSpaceById(spaceId),
enabled: !!spaceId,
staleTime: 5 * 60 * 1000,
});
}
export function useUpdateSpaceMutation() {
const queryClient = useQueryClient();
return useMutation<ISpace, Error, Partial<ISpace>>({
mutationFn: (data) => updateSpace(data),
onSuccess: (data, variables) => {
notifications.show({ message: "Space updated successfully" });
const space = queryClient.getQueryData([
"space",
variables.spaceId,
]) as ISpace;
if (space) {
const updatedSpace = { ...space, ...data };
queryClient.setQueryData(["space", variables.spaceId], updatedSpace);
queryClient.setQueryData(["space", data.slug], updatedSpace);
}
queryClient.invalidateQueries({
queryKey: ["spaces"],
});
},
onError: (error) => {
const errorMessage = error["response"]?.data?.message;
notifications.show({ message: errorMessage, color: "red" });
},
});
}
export function useDeleteSpaceMutation() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: Partial<ISpace>) => deleteSpace(data.id),
onSuccess: (data, variables) => {
notifications.show({ message: "Space deleted successfully" });
if (variables.slug) {
queryClient.removeQueries({
queryKey: ["space", variables.slug],
exact: true,
});
}
const spaces = queryClient.getQueryData(["spaces"]) as any;
if (spaces) {
spaces.items = spaces.items?.filter(
(space: ISpace) => space.id !== variables.id,
);
queryClient.setQueryData(["spaces"], spaces);
}
},
onError: (error) => {
const errorMessage = error["response"]?.data?.message;
notifications.show({ message: errorMessage, color: "red" });
},
});
}
export function useSpaceMembersQuery(
spaceId: string,
params?: QueryParams,
): UseQueryResult<IPagination<ISpaceMember>, Error> {
return useQuery({
queryKey: ["spaceMembers", spaceId, params],
queryFn: () => getSpaceMembers(spaceId, params),
enabled: !!spaceId,
placeholderData: keepPreviousData,
});
}
export function useAddSpaceMemberMutation() {
const queryClient = useQueryClient();
return useMutation<void, Error, IAddSpaceMember>({
mutationFn: (data) => addSpaceMember(data),
onSuccess: (data, variables) => {
notifications.show({ message: "Members added successfully" });
queryClient.invalidateQueries({
queryKey: ["spaceMembers", variables.spaceId],
});
},
onError: (error) => {
const errorMessage = error["response"]?.data?.message;
notifications.show({ message: errorMessage, color: "red" });
},
});
}
export function useRemoveSpaceMemberMutation() {
const queryClient = useQueryClient();
return useMutation<void, Error, IRemoveSpaceMember>({
mutationFn: (data) => removeSpaceMember(data),
onSuccess: (data, variables) => {
notifications.show({ message: "Removed successfully" });
queryClient.invalidateQueries({
queryKey: ["spaceMembers", variables.spaceId],
});
},
onError: (error) => {
const errorMessage = error["response"]?.data?.message;
notifications.show({ message: errorMessage, color: "red" });
},
});
}
export function useChangeSpaceMemberRoleMutation() {
const queryClient = useQueryClient();
return useMutation<void, Error, IChangeSpaceMemberRole>({
mutationFn: (data) => changeMemberRole(data),
onSuccess: (data, variables) => {
notifications.show({ message: "Member role updated successfully" });
// due to pagination levels, change in cache instead
queryClient.refetchQueries({
queryKey: ["spaceMembers", variables.spaceId],
});
},
onError: (error) => {
const errorMessage = error["response"]?.data?.message;
notifications.show({ message: errorMessage, color: "red" });
},
});
}