diff --git a/frontend/src/hooks/api/incidentContacts/index.tsx b/frontend/src/hooks/api/incidentContacts/index.tsx new file mode 100644 index 000000000..6c53db28e --- /dev/null +++ b/frontend/src/hooks/api/incidentContacts/index.tsx @@ -0,0 +1,5 @@ +export { + useAddIncidentContact, + useDeleteIncidentContact, + useGetOrgIncidentContact +} from './queries'; diff --git a/frontend/src/hooks/api/incidentContacts/queries.tsx b/frontend/src/hooks/api/incidentContacts/queries.tsx new file mode 100644 index 000000000..4f028f16d --- /dev/null +++ b/frontend/src/hooks/api/incidentContacts/queries.tsx @@ -0,0 +1,57 @@ +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; + +import { apiRequest } from '@app/config/request'; + +import { AddIncidentContactDTO, DeleteIncidentContactDTO, IncidentContact } from './types'; + +const incidentContactKeys = { + getAllContact: (orgId: string) => ['org-incident-contacts', { orgId }] as const +}; + +const fetchOrgIncidentContacts = async (orgId: string) => { + const { data } = await apiRequest.get<{ incidentContactsOrg: IncidentContact[] }>( + `/api/v1/organization/${orgId}/incidentContactOrg` + ); + + return data.incidentContactsOrg; +}; + +export const useGetOrgIncidentContact = (orgId: string) => + useQuery({ + queryKey: incidentContactKeys.getAllContact(orgId), + queryFn: () => fetchOrgIncidentContacts(orgId), + enabled: Boolean(orgId) + }); + +// mutation +export const useAddIncidentContact = () => { + const queryClient = useQueryClient(); + + return useMutation<{}, {}, AddIncidentContactDTO>({ + mutationFn: async ({ orgId, email }) => { + const { data } = await apiRequest.post(`/api/v1/organization/${orgId}/incidentContactOrg`, { + email + }); + return data; + }, + onSuccess: (_, { orgId }) => { + queryClient.invalidateQueries(incidentContactKeys.getAllContact(orgId)); + } + }); +}; + +export const useDeleteIncidentContact = () => { + const queryClient = useQueryClient(); + + return useMutation<{}, {}, DeleteIncidentContactDTO>({ + mutationFn: async ({ orgId, email }) => { + const { data } = await apiRequest.delete(`/api/v1/organization/${orgId}/incidentContactOrg`, { + data: { email } + }); + return data; + }, + onSuccess: (_, { orgId }) => { + queryClient.invalidateQueries(incidentContactKeys.getAllContact(orgId)); + } + }); +}; diff --git a/frontend/src/hooks/api/incidentContacts/types.ts b/frontend/src/hooks/api/incidentContacts/types.ts new file mode 100644 index 000000000..a1ef8ab95 --- /dev/null +++ b/frontend/src/hooks/api/incidentContacts/types.ts @@ -0,0 +1,18 @@ +export type IncidentContact = { + _id: string; + email: string; + organization: string; + __v: number; + createdAt: Date; + updatedAt: Date; +}; + +export type DeleteIncidentContactDTO = { + orgId: string; + email: string; +}; + +export type AddIncidentContactDTO = { + orgId: string; + email: string; +}; diff --git a/frontend/src/hooks/api/index.tsx b/frontend/src/hooks/api/index.tsx index ad9acf0c3..c2035bbba 100644 --- a/frontend/src/hooks/api/index.tsx +++ b/frontend/src/hooks/api/index.tsx @@ -1,4 +1,5 @@ export * from './auth'; +export * from './incidentContacts'; export * from './keys'; export * from './organization'; export * from './serviceTokens'; diff --git a/frontend/src/hooks/api/organization/index.ts b/frontend/src/hooks/api/organization/index.ts index 4d9dd04f8..a11a7dd74 100644 --- a/frontend/src/hooks/api/organization/index.ts +++ b/frontend/src/hooks/api/organization/index.ts @@ -1 +1 @@ -export { useGetOrganization } from './queries'; +export { useGetOrganization, useRenameOrg } from './queries'; diff --git a/frontend/src/hooks/api/organization/queries.tsx b/frontend/src/hooks/api/organization/queries.tsx index b2f9c7ce6..0770fc413 100644 --- a/frontend/src/hooks/api/organization/queries.tsx +++ b/frontend/src/hooks/api/organization/queries.tsx @@ -1,8 +1,8 @@ -import { useQuery } from '@tanstack/react-query'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { apiRequest } from '@app/config/request'; -import { Organization } from './types'; +import { Organization, RenameOrgDTO } from './types'; const organizationKeys = { getUserOrganization: ['organization'] as const @@ -16,3 +16,16 @@ const fetchUserOrganization = async () => { export const useGetOrganization = () => useQuery({ queryKey: organizationKeys.getUserOrganization, queryFn: fetchUserOrganization }); + +// mutation +export const useRenameOrg = () => { + const queryClient = useQueryClient(); + + return useMutation<{}, {}, RenameOrgDTO>({ + mutationFn: ({ newOrgName, orgId }) => + apiRequest.patch(`/api/v1/organization/${orgId}/name`, { name: newOrgName }), + onSuccess: () => { + queryClient.invalidateQueries(organizationKeys.getUserOrganization); + } + }); +}; diff --git a/frontend/src/hooks/api/organization/types.ts b/frontend/src/hooks/api/organization/types.ts index 74720320b..92a5c5f1d 100644 --- a/frontend/src/hooks/api/organization/types.ts +++ b/frontend/src/hooks/api/organization/types.ts @@ -4,3 +4,8 @@ export type Organization = { createAt: string; updatedAt: string; }; + +export type RenameOrgDTO = { + orgId: string; + newOrgName: string; +}; diff --git a/frontend/src/hooks/api/types.ts b/frontend/src/hooks/api/types.ts index 699e9a81d..a8821e5a5 100644 --- a/frontend/src/hooks/api/types.ts +++ b/frontend/src/hooks/api/types.ts @@ -1,14 +1,17 @@ export type { GetAuthTokenAPI } from './auth/types'; +export type { IncidentContact } from './incidentContacts/types'; export type { UserWsKeyPair } from './keys/types'; export type { Organization } from './organization/types'; export type { CreateServiceTokenDTO, ServiceToken } from './serviceTokens/types'; export type { GetSubscriptionPlan, SubscriptionPlan } from './subscriptions/types'; -export type { User } from './users/types'; +export type { AddUserToWsDTO, AddUserToWsRes, OrgUser, User } from './users/types'; export type { CreateEnvironmentDTO, + CreateWorkspaceDTO, DeleteEnvironmentDTO, DeleteWorkspaceDTO, RenameWorkspaceDTO, + ToggleAutoCapitalizationDTO, UpdateEnvironmentDTO, Workspace, WorkspaceEnv, diff --git a/frontend/src/hooks/api/users/index.tsx b/frontend/src/hooks/api/users/index.tsx index 69c0fc98a..0980d4108 100644 --- a/frontend/src/hooks/api/users/index.tsx +++ b/frontend/src/hooks/api/users/index.tsx @@ -1,7 +1,10 @@ export { fetchOrgUsers, + useAddUserToOrg, useAddUserToWs, + useDeleteOrgMembership, useGetOrgUsers, useGetUser, - useLogoutUser + useLogoutUser, + useUpdateOrgUserRole } from './queries'; diff --git a/frontend/src/hooks/api/users/queries.tsx b/frontend/src/hooks/api/users/queries.tsx index 1ddcf3809..b73ac8495 100644 --- a/frontend/src/hooks/api/users/queries.tsx +++ b/frontend/src/hooks/api/users/queries.tsx @@ -1,4 +1,4 @@ -import { useMutation, useQuery } from '@tanstack/react-query'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { decryptAssymmetric, @@ -8,7 +8,15 @@ import { apiRequest } from '@app/config/request'; import { setAuthToken } from '@app/reactQuery'; import { useUploadWsKey } from '../keys/queries'; -import { AddUserToWsDTO, AddUserToWsRes, OrgUser, User } from './types'; +import { + AddUserToOrgDTO, + AddUserToWsDTO, + AddUserToWsRes, + DeletOrgMembershipDTO, + OrgUser, + UpdateOrgUserRoleDTO, + User +} from './types'; const userKeys = { getUser: ['user'] as const, @@ -32,7 +40,11 @@ export const fetchOrgUsers = async (orgId: string) => { }; export const useGetOrgUsers = (orgId: string) => - useQuery(userKeys.getOrgUsers(orgId), () => fetchOrgUsers(orgId)); + useQuery({ + queryKey: userKeys.getOrgUsers(orgId), + queryFn: () => fetchOrgUsers(orgId), + enabled: Boolean(orgId) + }); // mutation export const useAddUserToWs = () => { @@ -69,6 +81,46 @@ export const useAddUserToWs = () => { }); }; +export const useAddUserToOrg = () => { + const queryClient = useQueryClient(); + + return useMutation<{}, {}, AddUserToOrgDTO>({ + mutationFn: (dto) => apiRequest.post(`/api/v1/invite-org/signup`, dto), + onSuccess: (_, { organizationId }) => { + queryClient.invalidateQueries(userKeys.getOrgUsers(organizationId)); + } + }); +}; + +export const useDeleteOrgMembership = () => { + const queryClient = useQueryClient(); + + return useMutation<{}, {}, DeletOrgMembershipDTO>({ + mutationFn: ({ membershipId }) => apiRequest.delete(`/api/v1/membership-org/${membershipId}`), + onSuccess: (_, { orgId }) => { + queryClient.invalidateQueries(userKeys.getOrgUsers(orgId)); + } + }); +}; + +export const useUpdateOrgUserRole = () => { + const queryClient = useQueryClient(); + + return useMutation<{}, {}, UpdateOrgUserRoleDTO>({ + mutationFn: ({ organizationId, membershipId, role }) => + apiRequest.patch(`/api/v2/organizations/${organizationId}/memberships/${membershipId}`, { + role + }), + onSuccess: (_, { organizationId }) => { + queryClient.invalidateQueries(userKeys.getOrgUsers(organizationId)); + }, + // to remove old states + onError: (_, { organizationId }) => { + queryClient.invalidateQueries(userKeys.getOrgUsers(organizationId)); + } + }); +}; + export const useLogoutUser = () => useMutation({ mutationFn: () => apiRequest.post('/api/v1/auth/logout'), diff --git a/frontend/src/hooks/api/users/types.ts b/frontend/src/hooks/api/users/types.ts index 1b17cd023..b3fb5cf6b 100644 --- a/frontend/src/hooks/api/users/types.ts +++ b/frontend/src/hooks/api/users/types.ts @@ -32,7 +32,7 @@ export type OrgUser = { inviteEmail: string; organization: string; role: 'owner' | 'admin' | 'member'; - status: 'invited' | 'accepted'; + status: 'invited' | 'accepted' | 'verified' | 'completed'; deniedPermissions: any[]; }; @@ -45,3 +45,19 @@ export type AddUserToWsRes = { invitee: OrgUser['user']; latestKey: UserWsKeyPair; }; + +export type UpdateOrgUserRoleDTO = { + organizationId: string; + membershipId: string; + role: string; +}; + +export type DeletOrgMembershipDTO = { + membershipId: string; + orgId: string; +}; + +export type AddUserToOrgDTO = { + inviteeEmail: string; + organizationId: string; +}; diff --git a/frontend/src/hooks/api/workspace/index.tsx b/frontend/src/hooks/api/workspace/index.tsx index 52a01029e..cab8617bd 100644 --- a/frontend/src/hooks/api/workspace/index.tsx +++ b/frontend/src/hooks/api/workspace/index.tsx @@ -3,9 +3,9 @@ export { useCreateWsEnvironment, useDeleteWorkspace, useDeleteWsEnvironment, + useGetUserWorkspaceMemberships, useGetUserWorkspaces, useGetWorkspaceById, useRenameWorkspace, useToggleAutoCapitalization, useUpdateWsEnvironment} from './queries'; - \ No newline at end of file diff --git a/frontend/src/hooks/api/workspace/queries.tsx b/frontend/src/hooks/api/workspace/queries.tsx index 0c4ba970b..2bca2e9a5 100644 --- a/frontend/src/hooks/api/workspace/queries.tsx +++ b/frontend/src/hooks/api/workspace/queries.tsx @@ -13,16 +13,18 @@ import { Workspace } from './types'; - const workspaceKeys = { getWorkspaceById: (workspaceId: string) => [{ workspaceId }, 'workspace'] as const, + getWorkspaceMemberships: (orgId: string) => [{ orgId }, 'workspace-memberships'], getAllUserWorkspace: ['workspaces'] as const }; const fetchWorkspaceById = async (workspaceId: string) => { - const { data } = await apiRequest.get<{ workspace: Workspace }>(`/api/v1/workspace/${workspaceId}`); - return data.workspace; -} + const { data } = await apiRequest.get<{ workspace: Workspace }>( + `/api/v1/workspace/${workspaceId}` + ); + return data.workspace; +}; const fetchUserWorkspaces = async () => { const { data } = await apiRequest.get<{ workspaces: Workspace[] }>('/api/v1/workspace'); @@ -40,6 +42,21 @@ export const useGetWorkspaceById = (workspaceId: string) => { export const useGetUserWorkspaces = () => useQuery(workspaceKeys.getAllUserWorkspace, fetchUserWorkspaces); +const fetchUserWorkspaceMemberships = async (orgId: string) => { + const { data } = await apiRequest.get>( + `/api/v1/organization/${orgId}/workspace-memberships` + ); + return data; +}; + +// to get all userids in an org with the workspace they are part of +export const useGetUserWorkspaceMemberships = (orgId: string) => + useQuery({ + queryKey: workspaceKeys.getWorkspaceMemberships(orgId), + queryFn: () => fetchUserWorkspaceMemberships(orgId), + enabled: Boolean(orgId) + }); + // mutation export const useCreateWorkspace = () => { const queryClient = useQueryClient(); @@ -70,7 +87,9 @@ export const useToggleAutoCapitalization = () => { return useMutation<{}, {}, ToggleAutoCapitalizationDTO>({ mutationFn: ({ workspaceID, state }) => - apiRequest.patch(`/api/v2/workspace/${workspaceID}/auto-capitalization`, { autoCapitalization: state }), + apiRequest.patch(`/api/v2/workspace/${workspaceID}/auto-capitalization`, { + autoCapitalization: state + }), onSuccess: () => { queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace); }