Merge branch 'edit-group' into 'develop'

Edit group

See merge request soapbox-pub/soapbox!2357
develop^2
Alex Gleason 2023-03-20 18:41:52 +00:00
commit bc457b61d1
10 zmienionych plików z 38 dodań i 54 usunięć

Wyświetl plik

@ -1,5 +1,6 @@
import { defineMessages } from 'react-intl'; import { defineMessages } from 'react-intl';
import { deleteEntities } from 'soapbox/entity-store/actions';
import toast from 'soapbox/toast'; import toast from 'soapbox/toast';
import api, { getLinks } from '../api'; import api, { getLinks } from '../api';
@ -191,7 +192,7 @@ const updateGroupFail = (error: AxiosError) => ({
}); });
const deleteGroup = (id: string) => (dispatch: AppDispatch, getState: () => RootState) => { const deleteGroup = (id: string) => (dispatch: AppDispatch, getState: () => RootState) => {
dispatch(deleteGroupRequest(id)); dispatch(deleteEntities([id], 'Group'));
return api(getState).delete(`/api/v1/groups/${id}`) return api(getState).delete(`/api/v1/groups/${id}`)
.then(() => dispatch(deleteGroupSuccess(id))) .then(() => dispatch(deleteGroupSuccess(id)))

Wyświetl plik

@ -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 { getSettings } from '../settings';
import type { AppDispatch, RootState } from 'soapbox/store'; import type { AppDispatch, RootState } from 'soapbox/store';
@ -18,11 +23,11 @@ const importAccount = (account: APIEntity) =>
const importAccounts = (accounts: APIEntity[]) => const importAccounts = (accounts: APIEntity[]) =>
({ type: ACCOUNTS_IMPORT, accounts }); ({ type: ACCOUNTS_IMPORT, accounts });
const importGroup = (group: APIEntity) => const importGroup = (group: Group) =>
({ type: GROUP_IMPORT, group }); importEntities([group], Entities.GROUPS);
const importGroups = (groups: APIEntity[]) => const importGroups = (groups: Group[]) =>
({ type: GROUPS_IMPORT, groups }); importEntities(groups, Entities.GROUPS);
const importStatus = (status: APIEntity, idempotencyKey?: string) => const importStatus = (status: APIEntity, idempotencyKey?: string) =>
(dispatch: AppDispatch, getState: () => RootState) => { (dispatch: AppDispatch, getState: () => RootState) => {
@ -69,17 +74,8 @@ const importFetchedGroup = (group: APIEntity) =>
importFetchedGroups([group]); importFetchedGroups([group]);
const importFetchedGroups = (groups: APIEntity[]) => { const importFetchedGroups = (groups: APIEntity[]) => {
const normalGroups: APIEntity[] = []; const entities = filteredArray(groupSchema).catch([]).parse(groups);
return importGroups(entities);
const processGroup = (group: APIEntity) => {
if (!group.id) return;
normalGroups.push(group);
};
groups.forEach(processGroup);
return importGroups(normalGroups);
}; };
const importFetchedStatus = (status: APIEntity, idempotencyKey?: string) => const importFetchedStatus = (status: APIEntity, idempotencyKey?: string) =>

Wyświetl plik

@ -2,6 +2,4 @@ export enum Entities {
GROUPS = 'Groups', GROUPS = 'Groups',
GROUP_RELATIONSHIPS = 'GroupRelationships', GROUP_RELATIONSHIPS = 'GroupRelationships',
GROUP_MEMBERSHIPS = 'GroupMemberships', GROUP_MEMBERSHIPS = 'GroupMemberships',
POPULAR_GROUPS = 'PopularGroups',
SUGGESTED_GROUPS = 'SuggestedGroups',
} }

Wyświetl plik

@ -98,7 +98,7 @@ describe('<GroupActionButton />', () => {
relationship: buildGroupRelationship({ relationship: buildGroupRelationship({
requested: false, requested: false,
member: true, member: true,
role: 'admin', role: 'owner',
}), }),
}); });
}); });

Wyświetl plik

@ -27,7 +27,7 @@ const GroupActionButton = ({ group }: IGroupActionButton) => {
const isRequested = group.relationship?.requested; const isRequested = group.relationship?.requested;
const isNonMember = !group.relationship?.member && !isRequested; 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 isBlocked = group.relationship?.blocked_by;
const onJoinGroup = () => joinGroup.mutate(group); const onJoinGroup = () => joinGroup.mutate(group);

Wyświetl plik

@ -1,12 +1,12 @@
import React, { useCallback, useEffect } from 'react'; import React, { useCallback, useEffect } from 'react';
import { FormattedMessage, defineMessages, useIntl } from 'react-intl'; 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 Account from 'soapbox/components/account';
import ScrollableList from 'soapbox/components/scrollable-list'; import ScrollableList from 'soapbox/components/scrollable-list';
import { Button, Column, HStack, Spinner } from 'soapbox/components/ui'; import { Button, Column, HStack, Spinner } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks'; import { useAppDispatch, useAppSelector, useGroup } from 'soapbox/hooks';
import { makeGetAccount, makeGetGroup } from 'soapbox/selectors'; import { makeGetAccount } from 'soapbox/selectors';
import toast from 'soapbox/toast'; import toast from 'soapbox/toast';
import ColumnForbidden from '../ui/components/column-forbidden'; import ColumnForbidden from '../ui/components/column-forbidden';
@ -62,14 +62,12 @@ const GroupBlockedMembers: React.FC<IGroupBlockedMembers> = ({ params }) => {
const intl = useIntl(); const intl = useIntl();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const id = params?.id || ''; const id = params?.id;
const getGroup = useCallback(makeGetGroup(), []); const { group } = useGroup(id);
const group = useAppSelector(state => getGroup(state, id));
const accountIds = useAppSelector((state) => state.user_lists.group_blocks.get(id)?.items); const accountIds = useAppSelector((state) => state.user_lists.group_blocks.get(id)?.items);
useEffect(() => { useEffect(() => {
if (!group) dispatch(fetchGroup(id));
dispatch(fetchGroupBlocks(id)); dispatch(fetchGroupBlocks(id));
}, [id]); }, [id]);
@ -81,7 +79,7 @@ const GroupBlockedMembers: React.FC<IGroupBlockedMembers> = ({ params }) => {
); );
} }
if (!group.relationship.role || !['admin', 'moderator'].includes(group.relationship.role)) { if (!group.relationship.role || !['owner', 'admin', 'moderator'].includes(group.relationship.role)) {
return (<ColumnForbidden />); return (<ColumnForbidden />);
} }

Wyświetl plik

@ -1,12 +1,12 @@
import React, { useCallback, useEffect } from 'react'; import React, { useCallback, useEffect } from 'react';
import { FormattedMessage, defineMessages, useIntl } from 'react-intl'; 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 Account from 'soapbox/components/account';
import ScrollableList from 'soapbox/components/scrollable-list'; import ScrollableList from 'soapbox/components/scrollable-list';
import { Button, Column, HStack, Spinner } from 'soapbox/components/ui'; import { Button, Column, HStack, Spinner } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks'; import { useAppDispatch, useAppSelector, useGroup } from 'soapbox/hooks';
import { makeGetAccount, makeGetGroup } from 'soapbox/selectors'; import { makeGetAccount } from 'soapbox/selectors';
import toast from 'soapbox/toast'; import toast from 'soapbox/toast';
import ColumnForbidden from '../ui/components/column-forbidden'; import ColumnForbidden from '../ui/components/column-forbidden';
@ -77,14 +77,12 @@ const GroupMembershipRequests: React.FC<IGroupMembershipRequests> = ({ params })
const intl = useIntl(); const intl = useIntl();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const id = params?.id || ''; const id = params?.id;
const getGroup = useCallback(makeGetGroup(), []); const { group } = useGroup(id);
const group = useAppSelector(state => getGroup(state, id));
const accountIds = useAppSelector((state) => state.user_lists.membership_requests.get(id)?.items); const accountIds = useAppSelector((state) => state.user_lists.membership_requests.get(id)?.items);
useEffect(() => { useEffect(() => {
if (!group) dispatch(fetchGroup(id));
dispatch(fetchGroupMembershipRequests(id)); dispatch(fetchGroupMembershipRequests(id));
}, [id]); }, [id]);
@ -96,7 +94,7 @@ const GroupMembershipRequests: React.FC<IGroupMembershipRequests> = ({ params })
); );
} }
if (!group.relationship.role || !['admin', 'moderator'].includes(group.relationship.role)) { if (!group.relationship.role || !['owner', 'admin', 'moderator'].includes(group.relationship.role)) {
return (<ColumnForbidden />); return (<ColumnForbidden />);
} }

Wyświetl plik

@ -1,13 +1,12 @@
import React, { useCallback, useEffect } from 'react'; import React from 'react';
import { defineMessages, useIntl } from 'react-intl'; import { defineMessages, useIntl } from 'react-intl';
import { useHistory } from 'react-router-dom'; 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 { openModal } from 'soapbox/actions/modals';
import List, { ListItem } from 'soapbox/components/list'; import List, { ListItem } from 'soapbox/components/list';
import { CardBody, Column, Spinner } from 'soapbox/components/ui'; import { CardBody, Column, Spinner } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks'; import { useAppDispatch, useGroup } from 'soapbox/hooks';
import { makeGetGroup } from 'soapbox/selectors';
import ColumnForbidden from '../ui/components/column-forbidden'; import ColumnForbidden from '../ui/components/column-forbidden';
@ -29,18 +28,12 @@ interface IManageGroup {
} }
const ManageGroup: React.FC<IManageGroup> = ({ params }) => { const ManageGroup: React.FC<IManageGroup> = ({ params }) => {
const history = useHistory(); const { id } = params;
const intl = useIntl(); const intl = useIntl();
const history = useHistory();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const id = params?.id || ''; const { group } = useGroup(id);
const getGroup = useCallback(makeGetGroup(), []);
const group = useAppSelector(state => getGroup(state, id));
useEffect(() => {
if (!group) dispatch(fetchGroup(id));
}, [id]);
if (!group || !group.relationship) { if (!group || !group.relationship) {
return ( return (
@ -50,7 +43,7 @@ const ManageGroup: React.FC<IManageGroup> = ({ params }) => {
); );
} }
if (!group.relationship.role || !['admin', 'moderator'].includes(group.relationship.role)) { if (!group.relationship.role || !['owner', 'admin', 'moderator'].includes(group.relationship.role)) {
return (<ColumnForbidden />); return (<ColumnForbidden />);
} }
@ -72,7 +65,7 @@ const ManageGroup: React.FC<IManageGroup> = ({ params }) => {
return ( return (
<Column label={intl.formatMessage(messages.heading)} backHref={`/groups/${id}`}> <Column label={intl.formatMessage(messages.heading)} backHref={`/groups/${id}`}>
<CardBody className='space-y-4'> <CardBody className='space-y-4'>
{group.relationship.role === 'admin' && ( {group.relationship.role === 'owner' && (
<List> <List>
<ListItem label={intl.formatMessage(messages.editGroup)} onClick={onEditGroup}> <ListItem label={intl.formatMessage(messages.editGroup)} onClick={onEditGroup}>
<span dangerouslySetInnerHTML={{ __html: group.display_name_html }} /> <span dangerouslySetInnerHTML={{ __html: group.display_name_html }} />
@ -83,7 +76,7 @@ const ManageGroup: React.FC<IManageGroup> = ({ params }) => {
<ListItem label={intl.formatMessage(messages.pendingRequests)} onClick={navigateToPending} /> <ListItem label={intl.formatMessage(messages.pendingRequests)} onClick={navigateToPending} />
<ListItem label={intl.formatMessage(messages.blockedMembers)} onClick={navigateToBlocks} /> <ListItem label={intl.formatMessage(messages.blockedMembers)} onClick={navigateToBlocks} />
</List> </List>
{group.relationship.role === 'admin' && ( {group.relationship.role === 'owner' && (
<List> <List>
<ListItem label={intl.formatMessage(messages.deleteGroup)} onClick={onDeleteGroup} /> <ListItem label={intl.formatMessage(messages.deleteGroup)} onClick={onDeleteGroup} />
</List> </List>

Wyświetl plik

@ -9,7 +9,7 @@ function usePopularGroups() {
const features = useFeatures(); const features = useFeatures();
const { entities, ...result } = useEntities<Group>( const { entities, ...result } = useEntities<Group>(
[Entities.POPULAR_GROUPS, ''], [Entities.GROUPS, 'popular'],
'/api/mock/groups', // '/api/v1/truth/trends/groups' '/api/mock/groups', // '/api/v1/truth/trends/groups'
{ {
schema: groupSchema, schema: groupSchema,

Wyświetl plik

@ -9,7 +9,7 @@ function useSuggestedGroups() {
const features = useFeatures(); const features = useFeatures();
const { entities, ...result } = useEntities<Group>( const { entities, ...result } = useEntities<Group>(
[Entities.SUGGESTED_GROUPS, ''], [Entities.GROUPS, 'suggested'],
'/api/mock/groups', // '/api/v1/truth/suggestions/groups' '/api/mock/groups', // '/api/v1/truth/suggestions/groups'
{ {
schema: groupSchema, schema: groupSchema,