diff --git a/app/soapbox/actions/groups.ts b/app/soapbox/actions/groups.ts index b97d52f20..d78e7f5d8 100644 --- a/app/soapbox/actions/groups.ts +++ b/app/soapbox/actions/groups.ts @@ -1,5 +1,6 @@ import { defineMessages } from 'react-intl'; +import { deleteEntities } from 'soapbox/entity-store/actions'; import toast from 'soapbox/toast'; import api, { getLinks } from '../api'; @@ -191,7 +192,7 @@ const updateGroupFail = (error: AxiosError) => ({ }); const deleteGroup = (id: string) => (dispatch: AppDispatch, getState: () => RootState) => { - dispatch(deleteGroupRequest(id)); + dispatch(deleteEntities([id], 'Group')); return api(getState).delete(`/api/v1/groups/${id}`) .then(() => dispatch(deleteGroupSuccess(id))) diff --git a/app/soapbox/actions/importer/index.ts b/app/soapbox/actions/importer/index.ts index 8750a5d61..ec0ec3121 100644 --- a/app/soapbox/actions/importer/index.ts +++ b/app/soapbox/actions/importer/index.ts @@ -1,3 +1,8 @@ +import { importEntities } from 'soapbox/entity-store/actions'; +import { Entities } from 'soapbox/entity-store/entities'; +import { Group, groupSchema } from 'soapbox/schemas'; +import { filteredArray } from 'soapbox/schemas/utils'; + import { getSettings } from '../settings'; import type { AppDispatch, RootState } from 'soapbox/store'; @@ -18,11 +23,11 @@ const importAccount = (account: APIEntity) => const importAccounts = (accounts: APIEntity[]) => ({ type: ACCOUNTS_IMPORT, accounts }); -const importGroup = (group: APIEntity) => - ({ type: GROUP_IMPORT, group }); +const importGroup = (group: Group) => + importEntities([group], Entities.GROUPS); -const importGroups = (groups: APIEntity[]) => - ({ type: GROUPS_IMPORT, groups }); +const importGroups = (groups: Group[]) => + importEntities(groups, Entities.GROUPS); const importStatus = (status: APIEntity, idempotencyKey?: string) => (dispatch: AppDispatch, getState: () => RootState) => { @@ -69,17 +74,8 @@ const importFetchedGroup = (group: APIEntity) => importFetchedGroups([group]); const importFetchedGroups = (groups: APIEntity[]) => { - const normalGroups: APIEntity[] = []; - - const processGroup = (group: APIEntity) => { - if (!group.id) return; - - normalGroups.push(group); - }; - - groups.forEach(processGroup); - - return importGroups(normalGroups); + const entities = filteredArray(groupSchema).catch([]).parse(groups); + return importGroups(entities); }; const importFetchedStatus = (status: APIEntity, idempotencyKey?: string) => diff --git a/app/soapbox/entity-store/entities.ts b/app/soapbox/entity-store/entities.ts index 05d7b60d9..30220eed6 100644 --- a/app/soapbox/entity-store/entities.ts +++ b/app/soapbox/entity-store/entities.ts @@ -2,6 +2,4 @@ export enum Entities { GROUPS = 'Groups', GROUP_RELATIONSHIPS = 'GroupRelationships', GROUP_MEMBERSHIPS = 'GroupMemberships', - POPULAR_GROUPS = 'PopularGroups', - SUGGESTED_GROUPS = 'SuggestedGroups', } \ No newline at end of file diff --git a/app/soapbox/features/group/components/__tests__/group-action-button.test.tsx b/app/soapbox/features/group/components/__tests__/group-action-button.test.tsx index 03f80fd9c..6809ea009 100644 --- a/app/soapbox/features/group/components/__tests__/group-action-button.test.tsx +++ b/app/soapbox/features/group/components/__tests__/group-action-button.test.tsx @@ -98,7 +98,7 @@ describe('', () => { relationship: buildGroupRelationship({ requested: false, member: true, - role: 'admin', + role: 'owner', }), }); }); diff --git a/app/soapbox/features/group/components/group-action-button.tsx b/app/soapbox/features/group/components/group-action-button.tsx index 32ff557af..64824866a 100644 --- a/app/soapbox/features/group/components/group-action-button.tsx +++ b/app/soapbox/features/group/components/group-action-button.tsx @@ -27,7 +27,7 @@ const GroupActionButton = ({ group }: IGroupActionButton) => { const isRequested = group.relationship?.requested; const isNonMember = !group.relationship?.member && !isRequested; - const isAdmin = group.relationship?.role === 'admin'; + const isAdmin = group.relationship?.role === 'owner'; const isBlocked = group.relationship?.blocked_by; const onJoinGroup = () => joinGroup.mutate(group); diff --git a/app/soapbox/features/group/group-blocked-members.tsx b/app/soapbox/features/group/group-blocked-members.tsx index 7af25f99c..9c197da62 100644 --- a/app/soapbox/features/group/group-blocked-members.tsx +++ b/app/soapbox/features/group/group-blocked-members.tsx @@ -1,12 +1,12 @@ import React, { useCallback, useEffect } from 'react'; import { FormattedMessage, defineMessages, useIntl } from 'react-intl'; -import { fetchGroup, fetchGroupBlocks, groupUnblock } from 'soapbox/actions/groups'; +import { fetchGroupBlocks, groupUnblock } from 'soapbox/actions/groups'; import Account from 'soapbox/components/account'; import ScrollableList from 'soapbox/components/scrollable-list'; import { Button, Column, HStack, Spinner } from 'soapbox/components/ui'; -import { useAppDispatch, useAppSelector } from 'soapbox/hooks'; -import { makeGetAccount, makeGetGroup } from 'soapbox/selectors'; +import { useAppDispatch, useAppSelector, useGroup } from 'soapbox/hooks'; +import { makeGetAccount } from 'soapbox/selectors'; import toast from 'soapbox/toast'; import ColumnForbidden from '../ui/components/column-forbidden'; @@ -62,14 +62,12 @@ const GroupBlockedMembers: React.FC = ({ params }) => { const intl = useIntl(); const dispatch = useAppDispatch(); - const id = params?.id || ''; + const id = params?.id; - const getGroup = useCallback(makeGetGroup(), []); - const group = useAppSelector(state => getGroup(state, id)); + const { group } = useGroup(id); const accountIds = useAppSelector((state) => state.user_lists.group_blocks.get(id)?.items); useEffect(() => { - if (!group) dispatch(fetchGroup(id)); dispatch(fetchGroupBlocks(id)); }, [id]); @@ -81,7 +79,7 @@ const GroupBlockedMembers: React.FC = ({ params }) => { ); } - if (!group.relationship.role || !['admin', 'moderator'].includes(group.relationship.role)) { + if (!group.relationship.role || !['owner', 'admin', 'moderator'].includes(group.relationship.role)) { return (); } diff --git a/app/soapbox/features/group/group-membership-requests.tsx b/app/soapbox/features/group/group-membership-requests.tsx index 8cf0fdfd7..fd33f3947 100644 --- a/app/soapbox/features/group/group-membership-requests.tsx +++ b/app/soapbox/features/group/group-membership-requests.tsx @@ -1,12 +1,12 @@ import React, { useCallback, useEffect } from 'react'; import { FormattedMessage, defineMessages, useIntl } from 'react-intl'; -import { authorizeGroupMembershipRequest, fetchGroup, fetchGroupMembershipRequests, rejectGroupMembershipRequest } from 'soapbox/actions/groups'; +import { authorizeGroupMembershipRequest, fetchGroupMembershipRequests, rejectGroupMembershipRequest } from 'soapbox/actions/groups'; import Account from 'soapbox/components/account'; import ScrollableList from 'soapbox/components/scrollable-list'; import { Button, Column, HStack, Spinner } from 'soapbox/components/ui'; -import { useAppDispatch, useAppSelector } from 'soapbox/hooks'; -import { makeGetAccount, makeGetGroup } from 'soapbox/selectors'; +import { useAppDispatch, useAppSelector, useGroup } from 'soapbox/hooks'; +import { makeGetAccount } from 'soapbox/selectors'; import toast from 'soapbox/toast'; import ColumnForbidden from '../ui/components/column-forbidden'; @@ -77,14 +77,12 @@ const GroupMembershipRequests: React.FC = ({ params }) const intl = useIntl(); const dispatch = useAppDispatch(); - const id = params?.id || ''; + const id = params?.id; - const getGroup = useCallback(makeGetGroup(), []); - const group = useAppSelector(state => getGroup(state, id)); + const { group } = useGroup(id); const accountIds = useAppSelector((state) => state.user_lists.membership_requests.get(id)?.items); useEffect(() => { - if (!group) dispatch(fetchGroup(id)); dispatch(fetchGroupMembershipRequests(id)); }, [id]); @@ -96,7 +94,7 @@ const GroupMembershipRequests: React.FC = ({ params }) ); } - if (!group.relationship.role || !['admin', 'moderator'].includes(group.relationship.role)) { + if (!group.relationship.role || !['owner', 'admin', 'moderator'].includes(group.relationship.role)) { return (); } diff --git a/app/soapbox/features/group/manage-group.tsx b/app/soapbox/features/group/manage-group.tsx index 918aea874..e7dea7f20 100644 --- a/app/soapbox/features/group/manage-group.tsx +++ b/app/soapbox/features/group/manage-group.tsx @@ -1,13 +1,12 @@ -import React, { useCallback, useEffect } from 'react'; +import React from 'react'; import { defineMessages, useIntl } from 'react-intl'; import { useHistory } from 'react-router-dom'; -import { deleteGroup, editGroup, fetchGroup } from 'soapbox/actions/groups'; +import { deleteGroup, editGroup } from 'soapbox/actions/groups'; import { openModal } from 'soapbox/actions/modals'; import List, { ListItem } from 'soapbox/components/list'; import { CardBody, Column, Spinner } from 'soapbox/components/ui'; -import { useAppDispatch, useAppSelector } from 'soapbox/hooks'; -import { makeGetGroup } from 'soapbox/selectors'; +import { useAppDispatch, useGroup } from 'soapbox/hooks'; import ColumnForbidden from '../ui/components/column-forbidden'; @@ -29,18 +28,12 @@ interface IManageGroup { } const ManageGroup: React.FC = ({ params }) => { - const history = useHistory(); + const { id } = params; const intl = useIntl(); + const history = useHistory(); const dispatch = useAppDispatch(); - const id = params?.id || ''; - - const getGroup = useCallback(makeGetGroup(), []); - const group = useAppSelector(state => getGroup(state, id)); - - useEffect(() => { - if (!group) dispatch(fetchGroup(id)); - }, [id]); + const { group } = useGroup(id); if (!group || !group.relationship) { return ( @@ -50,7 +43,7 @@ const ManageGroup: React.FC = ({ params }) => { ); } - if (!group.relationship.role || !['admin', 'moderator'].includes(group.relationship.role)) { + if (!group.relationship.role || !['owner', 'admin', 'moderator'].includes(group.relationship.role)) { return (); } @@ -72,7 +65,7 @@ const ManageGroup: React.FC = ({ params }) => { return ( - {group.relationship.role === 'admin' && ( + {group.relationship.role === 'owner' && ( @@ -83,7 +76,7 @@ const ManageGroup: React.FC = ({ params }) => { - {group.relationship.role === 'admin' && ( + {group.relationship.role === 'owner' && ( diff --git a/app/soapbox/hooks/api/usePopularGroups.ts b/app/soapbox/hooks/api/usePopularGroups.ts index e856270a5..88ae48c9d 100644 --- a/app/soapbox/hooks/api/usePopularGroups.ts +++ b/app/soapbox/hooks/api/usePopularGroups.ts @@ -9,7 +9,7 @@ function usePopularGroups() { const features = useFeatures(); const { entities, ...result } = useEntities( - [Entities.POPULAR_GROUPS, ''], + [Entities.GROUPS, 'popular'], '/api/mock/groups', // '/api/v1/truth/trends/groups' { schema: groupSchema, diff --git a/app/soapbox/hooks/api/useSuggestedGroups.ts b/app/soapbox/hooks/api/useSuggestedGroups.ts index 54477c249..c1b85805c 100644 --- a/app/soapbox/hooks/api/useSuggestedGroups.ts +++ b/app/soapbox/hooks/api/useSuggestedGroups.ts @@ -9,7 +9,7 @@ function useSuggestedGroups() { const features = useFeatures(); const { entities, ...result } = useEntities( - [Entities.SUGGESTED_GROUPS, ''], + [Entities.GROUPS, 'suggested'], '/api/mock/groups', // '/api/v1/truth/suggestions/groups' { schema: groupSchema,