sforkowany z mirror/soapbox
Merge branch 'edit-group' into 'develop'
Edit group See merge request soapbox-pub/soapbox!2357develop^2
commit
bc457b61d1
|
@ -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)))
|
||||||
|
|
|
@ -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) =>
|
||||||
|
|
|
@ -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',
|
|
||||||
}
|
}
|
|
@ -98,7 +98,7 @@ describe('<GroupActionButton />', () => {
|
||||||
relationship: buildGroupRelationship({
|
relationship: buildGroupRelationship({
|
||||||
requested: false,
|
requested: false,
|
||||||
member: true,
|
member: true,
|
||||||
role: 'admin',
|
role: 'owner',
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 />);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 />);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Ładowanie…
Reference in New Issue