import { InfiniteData, useMutation, useQueryClient } from '@tanstack/react-query' import { merge } from 'lodash' import { getRequestQueryKey, useApiClient } from '../../../hooks' import { useSuspenseGet, useSuspensePaginator } from '../../../hooks' import { ApiCollection, ApiResource } from '../../../types' import { GroupMembership, GroupResourceWithMembership } from '../../../types/resources' import { updateRecordInPagesData } from '../../../utils' import { throwResponseError } from '../../../utils/response_error' export const getGroupsRequestArgs = () => ({ url: '/me/groups', data: { perPage: 100, include: ['my_group_membership'], filter: 'user_settable_notification_level', fields: { Group: [], GroupMembership: [ 'notification_level', 'notification_level_description', 'notification_level_options', ], }, order: 'name', }, }) export const getGroupRequestArgs = ({ groupId }: { groupId: number | string }) => ({ url: `/me/groups/${groupId}`, data: { include: ['my_group_membership'], fields: { Group: ['name', 'source_app_name', 'source_type', 'my_group_membership'], GroupMembership: [ 'notification_level', 'notification_level_description', 'notification_level_options', ], }, }, }) export const useGroups = () => { const args = getGroupsRequestArgs() return useSuspensePaginator(args) } export const useGroup = ({ groupId }: { groupId: number | string }) => { const args = getGroupRequestArgs({ groupId }) return useSuspenseGet(args, { refetchOnMount: false }) } type GroupsQueryData = InfiniteData> export const useGroupMembershipUpdate = ({ groupId }: { groupId: number | string }) => { const apiClient = useApiClient() const queryClient = useQueryClient() const groupRequestArgs = getGroupRequestArgs({ groupId }) const groupsRequestArgs = getGroupsRequestArgs() const groupQueryKey = getRequestQueryKey(groupRequestArgs) const enrichGroupMembership = ( membership: Partial ): Partial => { const cachedGroup = queryClient.getQueryData>(groupQueryKey) const currentOptions = cachedGroup?.data.myGroupMembership?.notificationLevelOptions ?? [] const { notificationLevel } = membership const selectedOption = notificationLevel ? currentOptions.find(o => o.value === notificationLevel) : undefined const notificationLevelDescription = membership.notificationLevelDescription ?? selectedOption?.description return { ...membership, notificationLevelDescription, ...(notificationLevel && { notificationLevelOptions: currentOptions.map(o => ({ ...o, enabled: o.value === notificationLevel, })), }), } } const updateGroupsMembershipCache = (membership: Partial) => { queryClient.setQueryData(getRequestQueryKey(groupsRequestArgs), prev => updateRecordInPagesData({ data: prev, record: { id: groupId } as GroupResourceWithMembership, processRecord: (_record, current) => merge({}, current, { myGroupMembership: membership }), }) ) } const updateGroupMembershipCache = (membership: Partial) => { queryClient.setQueryData>(groupQueryKey, groupData => { if (!groupData?.data.myGroupMembership) return groupData return merge({}, groupData, { data: { myGroupMembership: membership } }) }) } return useMutation({ throwOnError: true, onMutate: membership => { const enriched = enrichGroupMembership(membership) updateGroupsMembershipCache(enriched) updateGroupMembershipCache(enriched) }, onSuccess: response => { const enriched = enrichGroupMembership(response.data) updateGroupsMembershipCache(enriched) updateGroupMembershipCache(enriched) // Updating conversations without access to the current filters // is a hard itch to scratch so we just need to refetch. queryClient.invalidateQueries({ queryKey: ['/me/conversations'] }) }, mutationFn: (membership: Partial) => { return apiClient.chat .patch>({ url: `/me/groups/${groupId}/my_group_membership`, data: { data: { type: 'GroupMembership', attributes: { ...(membership.notificationLevel !== undefined && { notification_level: membership.notificationLevel, }), }, }, }, }) .catch(throwResponseError) }, }) }