import { importEntities } from 'soapbox/entity-store/actions'; import { Entities } from 'soapbox/entity-store/entities'; import { useTransaction } from 'soapbox/entity-store/hooks'; import { useAppDispatch, useLoggedIn } from 'soapbox/hooks'; import { useApi } from 'soapbox/hooks/useApi'; import { relationshipSchema } from 'soapbox/schemas'; interface FollowOpts { reblogs?: boolean notify?: boolean languages?: string[] } function useFollow() { const api = useApi(); const dispatch = useAppDispatch(); const { isLoggedIn } = useLoggedIn(); const { transaction } = useTransaction(); function followEffect(accountId: string) { transaction({ Accounts: { [accountId]: (account) => ({ ...account, followers_count: account.followers_count + 1, }), }, Relationships: { [accountId]: (relationship) => ({ ...relationship, following: true, }), }, }); } function unfollowEffect(accountId: string) { transaction({ Accounts: { [accountId]: (account) => ({ ...account, followers_count: Math.max(0, account.followers_count - 1), }), }, Relationships: { [accountId]: (relationship) => ({ ...relationship, following: false, }), }, }); } async function follow(accountId: string, options: FollowOpts = {}) { if (!isLoggedIn) return; followEffect(accountId); try { const response = await api.post(`/api/v1/accounts/${accountId}/follow`, options); const result = relationshipSchema.safeParse(response.data); if (result.success) { dispatch(importEntities([result.data], Entities.RELATIONSHIPS)); } } catch (e) { unfollowEffect(accountId); } } async function unfollow(accountId: string) { if (!isLoggedIn) return; unfollowEffect(accountId); try { await api.post(`/api/v1/accounts/${accountId}/unfollow`); } catch (e) { followEffect(accountId); } } return { follow, unfollow, followEffect, unfollowEffect, }; } export { useFollow };