diff --git a/app/soapbox/entity-store/hooks/useEntityActions.ts b/app/soapbox/entity-store/hooks/useEntityActions.ts index ff27af340..c7e2e431d 100644 --- a/app/soapbox/entity-store/hooks/useEntityActions.ts +++ b/app/soapbox/entity-store/hooks/useEntityActions.ts @@ -31,10 +31,14 @@ function useEntityActions( const { createEntity, isSubmitting: createSubmitting } = useCreateEntity(path, (data) => api.post(endpoints.post!, data), opts); + const { createEntity: updateEntity, isSubmitting: updateSubmitting } = + useCreateEntity(path, (data) => api.patch(endpoints.patch!, data), opts); + return { createEntity, deleteEntity, - isSubmitting: createSubmitting || deleteSubmitting, + updateEntity, + isSubmitting: createSubmitting || deleteSubmitting || updateSubmitting, }; } diff --git a/app/soapbox/features/group/components/group-tag-list-item.tsx b/app/soapbox/features/group/components/group-tag-list-item.tsx index 7792b3e81..47f9f1ef6 100644 --- a/app/soapbox/features/group/components/group-tag-list-item.tsx +++ b/app/soapbox/features/group/components/group-tag-list-item.tsx @@ -3,7 +3,11 @@ import { defineMessages, useIntl } from 'react-intl'; import { Link } from 'react-router-dom'; import { HStack, IconButton, Stack, Text, Tooltip } from 'soapbox/components/ui'; +import { importEntities } from 'soapbox/entity-store/actions'; +import { Entities } from 'soapbox/entity-store/entities'; +import { useAppDispatch } from 'soapbox/hooks'; import { useUpdateGroupTag } from 'soapbox/hooks/api'; +import { GroupRoles } from 'soapbox/schemas/group-member'; import toast from 'soapbox/toast'; import { shortNumberFormat } from 'soapbox/utils/numbers'; @@ -29,15 +33,26 @@ interface IGroupMemberListItem { const GroupTagListItem = (props: IGroupMemberListItem) => { const { group, tag, isPinnable } = props; + const dispatch = useAppDispatch(); const intl = useIntl(); - const updateGroupTag = useUpdateGroupTag(group.id, tag.id); + const { updateGroupTag } = useUpdateGroupTag(group.id, tag.id); + + const isOwner = group.relationship?.role === GroupRoles.OWNER; + const isAdmin = group.relationship?.role === GroupRoles.ADMIN; + const canEdit = isOwner || isAdmin; const toggleVisibility = () => { updateGroupTag({ - pinned: !tag.visible, + group_tag_type: tag.visible ? 'hidden' : 'normal', }, { - onSuccess(entity: GroupTag) { + onSuccess() { + const entity = { + ...tag, + visible: !tag.visible, + }; + dispatch(importEntities([entity], Entities.GROUP_TAGS)); + toast.success( entity.visible ? intl.formatMessage(messages.visibleSuccess) : @@ -49,9 +64,15 @@ const GroupTagListItem = (props: IGroupMemberListItem) => { const togglePin = () => { updateGroupTag({ - pinned: !tag.pinned, + group_tag_type: tag.pinned ? 'normal' : 'pinned', }, { - onSuccess(entity: GroupTag) { + onSuccess() { + const entity = { + ...tag, + pinned: !tag.pinned, + }; + dispatch(importEntities([entity], Entities.GROUP_TAGS)); + toast.success( entity.pinned ? intl.formatMessage(messages.pinSuccess) : @@ -73,7 +94,7 @@ const GroupTagListItem = (props: IGroupMemberListItem) => { > { @@ -106,12 +127,12 @@ const GroupTagListItem = (props: IGroupMemberListItem) => { #{tag.name} - + {intl.formatMessage(messages.total)}: {' '} @@ -121,30 +142,32 @@ const GroupTagListItem = (props: IGroupMemberListItem) => { - - {tag.visible ? ( - renderPinIcon() - ) : null} + {canEdit ? ( + + {tag.visible ? ( + renderPinIcon() + ) : null} - - - - + > + + + + ) : null} ); }; diff --git a/app/soapbox/features/group/group-tags.tsx b/app/soapbox/features/group/group-tags.tsx index dc4c7d088..d0b371d8b 100644 --- a/app/soapbox/features/group/group-tags.tsx +++ b/app/soapbox/features/group/group-tags.tsx @@ -1,6 +1,8 @@ import React from 'react'; +import { FormattedMessage } from 'react-intl'; import ScrollableList from 'soapbox/components/scrollable-list'; +import { Icon, Stack, Text } from 'soapbox/components/ui'; import { useGroupTags } from 'soapbox/hooks/api'; import { useGroup } from 'soapbox/queries/groups'; @@ -26,28 +28,41 @@ const GroupTopics: React.FC = (props) => { const isPinnable = pinnedTags.length < 3; return ( - <> - - {tags.map((tag) => ( - - ))} - - + +
+ +
+ + + + + + } + emptyMessageCard={false} + > + {tags.map((tag) => ( + + ))} +
); }; diff --git a/app/soapbox/hooks/api/groups/useGroupTags.ts b/app/soapbox/hooks/api/groups/useGroupTags.ts index 4b724352e..42d81688f 100644 --- a/app/soapbox/hooks/api/groups/useGroupTags.ts +++ b/app/soapbox/hooks/api/groups/useGroupTags.ts @@ -1,13 +1,16 @@ import { Entities } from 'soapbox/entity-store/entities'; import { useEntities } from 'soapbox/entity-store/hooks'; +import { useApi } from 'soapbox/hooks/useApi'; import { groupTagSchema } from 'soapbox/schemas'; import type { GroupTag } from 'soapbox/schemas'; function useGroupTags(groupId: string) { + const api = useApi(); + const { entities, ...result } = useEntities( [Entities.GROUP_TAGS, groupId], - '/api/mock/groups/tags', // `api/v1/groups/${groupId}/tags` + () => api.get(`api/v1/truth/trends/groups/${groupId}/tags`), { schema: groupTagSchema }, ); diff --git a/app/soapbox/hooks/api/groups/useUpdateGroupTag.ts b/app/soapbox/hooks/api/groups/useUpdateGroupTag.ts index 2d4d61f69..1c68c714d 100644 --- a/app/soapbox/hooks/api/groups/useUpdateGroupTag.ts +++ b/app/soapbox/hooks/api/groups/useUpdateGroupTag.ts @@ -1,17 +1,18 @@ import { Entities } from 'soapbox/entity-store/entities'; import { useEntityActions } from 'soapbox/entity-store/hooks'; -import { groupTagSchema } from 'soapbox/schemas'; import type { GroupTag } from 'soapbox/schemas'; function useUpdateGroupTag(groupId: string, tagId: string) { - const { updateEntity } = useEntityActions( + const { updateEntity, ...rest } = useEntityActions( [Entities.GROUP_TAGS, groupId, tagId], - { patch: `/api/mock/truth/groups/${groupId}/tags/${tagId}` }, - { schema: groupTagSchema }, + { patch: `/api/v1/groups/${groupId}/tags/${tagId}` }, ); - return updateEntity; + return { + updateGroupTag: updateEntity, + ...rest, + }; } export { useUpdateGroupTag }; \ No newline at end of file