Skip to content

Commit

Permalink
adding hooks for memberships
Browse files Browse the repository at this point in the history
  • Loading branch information
littlelazer committed Oct 15, 2024
1 parent 8aeb8e7 commit 765ea64
Show file tree
Hide file tree
Showing 13 changed files with 235 additions and 88 deletions.
66 changes: 40 additions & 26 deletions src/factories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { DEPARTMENT_SEALS } from './utils/departmentSeals'
import { UsersIndex } from './network/useUsers'
import { UserShow } from './network/useUser'
import { GroupsIndex, GroupShow } from './network/groups'
import { MembershipsIndex } from './network/memberships'

export const randomObject = () => {
return { [faker.lorem.word()]: faker.lorem.words(3) }
Expand Down Expand Up @@ -140,59 +139,74 @@ export const buildEmailTemplateIndex = (
}
}

export const buildUserIndex = (options?: Partial<UsersIndex>): UsersIndex => {
const buildUser = (): UserShow => ({
id: uniqueId(),
email: faker.internet.email(),
role: 'member',
})

export const buildUserShow = (options?: Partial<UserShow>): UserShow => {
const user = buildUser()
return {
id: uniqueId(),
email: faker.internet.email(),
role: 'member',
...user,
...options,
}
}

export const buildUserShow = (options?: Partial<UserShow>): UserShow => {
export const buildUserIndex = (options?: Partial<UsersIndex>): UsersIndex => {
const user = buildUser()
return {
id: uniqueId(),
email: faker.internet.email(),
role: 'member',
...user,
...options,
}
}

export const buildGroupIndex = (options?: Partial<GroupsIndex>): GroupsIndex => {
export const buildUserMembershipIndex = (options?: Partial<UsersIndex>): UsersIndex => {
const user = buildUser()
return {
id: uniqueId(),
name: faker.lorem.words(3),
description: faker.lorem.paragraph(),
...user,
...options,
}
}

interface Membership {
id: string
userId: string
groupId: string
}
const buildGroup = (): GroupsIndex => ({
id: uniqueId(),
name: faker.lorem.words(3),
description: faker.lorem.paragraph(),
})

export const buildMembershipShow = (options?: Partial<Membership>): Membership => {
export const buildGroupIndex = (options?: Partial<GroupsIndex>): GroupsIndex => {
const group = buildGroup()
return {
id: uniqueId(),
groupId: uniqueId(),
userId: uniqueId(),
...group,
...options,
}
}

export const buildGroupShow = (options?: Partial<GroupShow>): GroupShow => {
const group = buildGroup()
return {
id: uniqueId(),
name: faker.lorem.words(3),
description: faker.lorem.paragraph(),
...group,
users: [],
...options,
}
}

export const buildMembershipIndex = (options?: Partial<MembershipsIndex>): MembershipsIndex => {
export const buildGroupMembershipIndex = (options?: Partial<GroupsIndex>): GroupsIndex => {
const group = buildGroup()
return {
...group,
...options,
}
}

interface Membership {
id: string
userId: string
groupId: string
}

export const buildMembershipShow = (options?: Partial<Membership>): Membership => {
return {
id: uniqueId(),
groupId: uniqueId(),
Expand Down
10 changes: 3 additions & 7 deletions src/network/memberships/__tests__/useCreateMembership.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import { asMock, buildMembershipShow, userIsSignedIn } from 'src/testHelpers'
import { AuthedFetch, useAuthedFetch } from '../../useAuthedFetch'
import { useCreateMembership } from '../useCreateMembership'
import { randomUUID } from 'crypto'
import { buildUseGroupQueryKey } from 'src/network/groups'
import { buildUseUserQueryKey } from 'src/network/useUser'
import { buildUseMembershipQueryKey } from '../useMembership'

jest.mock('../../useAuthedFetch')

Expand Down Expand Up @@ -54,7 +53,7 @@ describe('useCreateMembership', () => {
expect(result.current.data).toEqual({ membership: { id: 'saved id', userId, groupId } })
})

it('invalidates the useGroup and useUser queries', async () => {
it('invalidates the useMembership queries', async () => {
const client = new QueryClient()
const membership = buildMembershipShow()
asMock(mockAuthedFetch).mockResolvedValue({
Expand All @@ -77,10 +76,7 @@ describe('useCreateMembership', () => {
await result.current.mutateAsync({ groupId, userId })
await waitFor(() => expect(result.current.isSuccess).toEqual(true))
expect(client.invalidateQueries).toHaveBeenCalledWith({
queryKey: [buildUseUserQueryKey(membership.userId)],
})
expect(client.invalidateQueries).toHaveBeenCalledWith({
queryKey: [buildUseGroupQueryKey(membership.groupId)],
queryKey: [buildUseMembershipQueryKey(membership.id)],
})
})
})
10 changes: 7 additions & 3 deletions src/network/memberships/__tests__/useDestroyMembership.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import { AuthProvider } from 'src/utils/AuthContext'
import { asMock, buildMembershipShow, userIsSignedIn } from 'src/testHelpers'
import { AuthedFetch, useAuthedFetch } from '../../useAuthedFetch'
import { useDestroyMembership } from '../useDestroyMembership'
import { buildUseUserQueryKey } from 'src/network/useUser'
import { buildUseMembershipQueryKey } from 'src/network/memberships'
import { buildUseGroupQueryKey } from 'src/network/groups'
import { buildUseUserQueryKey } from 'src/network/useUser'

jest.mock('../../useAuthedFetch')

Expand Down Expand Up @@ -46,7 +47,7 @@ describe('useDestroyMembership', () => {
expect(result.current.data).toEqual({ membership: { id: membership.id } })
})

it('invalidates the useGroup and useUser queries', async () => {
it('invalidates the useMembership, useGroup, and useUser queries', async () => {
const client = new QueryClient()
const membership = buildMembershipShow()
asMock(mockAuthedFetch).mockResolvedValue({
Expand All @@ -69,10 +70,13 @@ describe('useDestroyMembership', () => {
await result.current.mutateAsync(membership)
await waitFor(() => expect(result.current.isSuccess).toEqual(true))
expect(client.invalidateQueries).toHaveBeenCalledWith({
queryKey: [buildUseUserQueryKey(membership.userId)],
queryKey: [buildUseMembershipQueryKey(membership.id)],
})
expect(client.invalidateQueries).toHaveBeenCalledWith({
queryKey: [buildUseGroupQueryKey(membership.groupId)],
})
expect(client.invalidateQueries).toHaveBeenCalledWith({
queryKey: [buildUseUserQueryKey(membership.userId)],
})
})
})
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from 'react'
import { renderHook, waitFor } from '@testing-library/react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { useMemberships } from '../useMemberships'
import { useGroupMemberships } from '../useGroupMemberships'
import { AuthProvider } from 'src/utils/AuthContext'
import { asMock, buildMembershipIndex, userIsSignedIn } from 'src/testHelpers'
import { asMock, buildGroupMembershipIndex, buildUserShow, userIsSignedIn } from 'src/testHelpers'
import { AuthedFetch, useAuthedFetch } from '../../useAuthedFetch'

jest.mock('../../useAuthedFetch')
Expand All @@ -19,10 +19,11 @@ describe('useMemberships', () => {

it('queries for memberships', async () => {
const client = new QueryClient()
const memberships = [buildMembershipIndex(), buildMembershipIndex()]
asMock(mockAuthedFetch).mockResolvedValue({ statusCode: 200, json: { memberships } })
const user = buildUserShow()
const groups = [buildGroupMembershipIndex(), buildGroupMembershipIndex()]
asMock(mockAuthedFetch).mockResolvedValue({ statusCode: 200, json: { groups } })

const { result } = renderHook(() => useMemberships(), {
const { result } = renderHook(() => useGroupMemberships(user.id), {
wrapper: ({ children }) => {
return (
<QueryClientProvider client={client}>
Expand All @@ -34,9 +35,9 @@ describe('useMemberships', () => {

await waitFor(() => expect(result.current.isSuccess).toEqual(true))
expect(mockAuthedFetch).toHaveBeenCalledWith({
path: '/memberships',
path: `/users/${user.id}/memberships`,
method: 'GET',
})
expect(result.current.data).toEqual(memberships)
expect(result.current.data).toEqual(groups)
})
})
42 changes: 42 additions & 0 deletions src/network/memberships/__tests__/useMembership.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React from 'react'
import { renderHook, waitFor } from '@testing-library/react'
import { MembershipShow, useMembership } from '../useMembership'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { AuthProvider } from 'src/utils/AuthContext'
import { asMock, buildMembershipShow, userIsSignedIn } from 'src/testHelpers'
import { AuthedFetch, useAuthedFetch } from '../../useAuthedFetch'

jest.mock('../../useAuthedFetch')

describe('useMembership', () => {
let mockAuthedFetch: AuthedFetch

beforeEach(() => {
userIsSignedIn()
mockAuthedFetch = jest.fn()
asMock(useAuthedFetch).mockReturnValue(mockAuthedFetch)
})

it('queries for the group with the given id', async () => {
const client = new QueryClient()
const membership: MembershipShow = buildMembershipShow()
asMock(mockAuthedFetch).mockResolvedValue({ statusCode: 200, json: { membership } })

const { result } = renderHook(() => useMembership(membership.id), {
wrapper: ({ children }) => {
return (
<QueryClientProvider client={client}>
<AuthProvider>{children}</AuthProvider>
</QueryClientProvider>
)
},
})

await waitFor(() => expect(result.current.isSuccess).toEqual(true))
expect(mockAuthedFetch).toHaveBeenCalledWith({
path: `/membership/${membership.id}`,
method: 'GET',
})
expect(result.current.data).toEqual(membership)
})
})
48 changes: 48 additions & 0 deletions src/network/memberships/__tests__/useUserMemberships.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React from 'react'
import { renderHook, waitFor } from '@testing-library/react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { useUserMemberships } from '../useUserMemberships'
import { AuthProvider } from 'src/utils/AuthContext'
import {
asMock,
buildMembershipShow,
buildUserMembershipIndex,
userIsSignedIn,
} from 'src/testHelpers'
import { AuthedFetch, useAuthedFetch } from '../../useAuthedFetch'

jest.mock('../../useAuthedFetch')

describe('useMemberships', () => {
let mockAuthedFetch: AuthedFetch

beforeEach(() => {
userIsSignedIn()
mockAuthedFetch = jest.fn()
asMock(useAuthedFetch).mockReturnValue(mockAuthedFetch)
})

it('queries for user memberships', async () => {
const client = new QueryClient()
const membership = buildMembershipShow()
const users = [buildUserMembershipIndex(), buildUserMembershipIndex()]
asMock(mockAuthedFetch).mockResolvedValue({ statusCode: 200, json: { users } })

const { result } = renderHook(() => useUserMemberships(membership.id), {
wrapper: ({ children }) => {
return (
<QueryClientProvider client={client}>
<AuthProvider>{children}</AuthProvider>
</QueryClientProvider>
)
},
})

await waitFor(() => expect(result.current.isSuccess).toEqual(true))
expect(mockAuthedFetch).toHaveBeenCalledWith({
path: `/groups/${membership.id}/memberships`,
method: 'GET',
})
expect(result.current.data).toEqual(users)
})
})
4 changes: 3 additions & 1 deletion src/network/memberships/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export * from './useMemberships'
export * from './useMembership'
export * from './useGroupMemberships'
export * from './useUserMemberships'
export * from './useCreateMembership'
export * from './useDestroyMembership'
26 changes: 10 additions & 16 deletions src/network/memberships/useCreateMembership.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { useAuthedFetch } from '../useAuthedFetch'
import { buildUseUserQueryKey } from '../useUser'
import { buildUseGroupQueryKey } from '../groups'
import { buildUseMembershipQueryKey, MembershipShow } from '../memberships'

export interface MembershipShow {
id: string
groupId: string
userId: string
}

interface CreateGroupSuccessfulResponse {
interface CreateMembershipSuccessfulResponse {
membership: MembershipShow
}

export interface CreateGroupErrorResponse {
errors: { name: string; description?: string }
export interface CreateMembershipErrorResponse {
errors: { user: string; group?: string }
}

type CreateGroupResponse = CreateGroupSuccessfulResponse | CreateGroupErrorResponse
type CreateMembershipResponse = CreateMembershipSuccessfulResponse | CreateMembershipErrorResponse

export const useCreateMembership = () => {
const client = useQueryClient()
Expand All @@ -27,8 +20,8 @@ export const useCreateMembership = () => {
mutationFn: async (membership: {
userId: string
groupId: string
}): Promise<CreateGroupResponse> => {
const result = await authedFetch<CreateGroupResponse>({
}): Promise<CreateMembershipResponse> => {
const result = await authedFetch<CreateMembershipResponse>({
body: { membership },
method: 'POST',
path: '/memberships',
Expand All @@ -38,8 +31,9 @@ export const useCreateMembership = () => {
onSuccess: (result) => {
if ('membership' in result) {
const { membership } = result
client.invalidateQueries({ queryKey: [buildUseUserQueryKey(membership.userId)] })
client.invalidateQueries({ queryKey: [buildUseGroupQueryKey(membership.groupId)] })
client.invalidateQueries({
queryKey: [buildUseMembershipQueryKey(membership.id)],
})
}
},
})
Expand Down
12 changes: 9 additions & 3 deletions src/network/memberships/useDestroyMembership.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { useAuthedFetch } from '../useAuthedFetch'
import { MembershipShow } from './useCreateMembership'
import { MembershipShow } from './useMembership'
import { useRef } from 'react'
import { buildUseUserQueryKey } from '../useUser'
import { buildUseMembershipQueryKey } from '../memberships'
import { buildUseGroupQueryKey } from '../groups'
import { buildUseUserQueryKey } from '../useUser'

export const useDestroyMembership = () => {
const client = useQueryClient()
Expand All @@ -21,10 +22,15 @@ export const useDestroyMembership = () => {
},
onSuccess: () => {
if (membershipRef.current) {
client.invalidateQueries({ queryKey: [buildUseUserQueryKey(membershipRef.current.userId)] })
client.invalidateQueries({
queryKey: [buildUseMembershipQueryKey(membershipRef.current.id)],
})
client.invalidateQueries({
queryKey: [buildUseGroupQueryKey(membershipRef.current.groupId)],
})
client.invalidateQueries({
queryKey: [buildUseUserQueryKey(membershipRef.current.userId)],
})
}
},
})
Expand Down
Loading

0 comments on commit 765ea64

Please sign in to comment.