+
-
+
,
document.body,
)}
diff --git a/app/soapbox/features/emoji/index.ts b/app/soapbox/features/emoji/index.ts
index 8fa279dad..61a957e9e 100644
--- a/app/soapbox/features/emoji/index.ts
+++ b/app/soapbox/features/emoji/index.ts
@@ -28,7 +28,7 @@ export interface CustomEmoji {
export interface NativeEmoji {
id: string
colons: string
- custom?: boolean
+ custom?: false
unified: string
native: string
}
diff --git a/app/soapbox/features/emoji/search.ts b/app/soapbox/features/emoji/search.ts
index 119636a29..dbcb29756 100644
--- a/app/soapbox/features/emoji/search.ts
+++ b/app/soapbox/features/emoji/search.ts
@@ -1,11 +1,10 @@
-import { Index } from 'flexsearch';
+import { Index } from 'flexsearch-ts';
+import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
import data from './data';
import type { Emoji } from './index';
-// import type { Emoji as EmojiMart, CustomEmoji } from 'emoji-mart';
-// @ts-ignore
const index = new Index({
tokenize: 'full',
optimize: true,
@@ -37,29 +36,39 @@ export const addCustomToPool = (customEmojis: any[]) => {
};
// we can share an index by prefixing custom emojis with 'c' and native with 'n'
-const search = (str: string, { maxResults = 5, custom }: searchOptions = {}, custom_emojis?: any): Emoji[] => {
+const search = (
+ str: string, { maxResults = 5 }: searchOptions = {},
+ custom_emojis?: ImmutableList
>,
+): Emoji[] => {
return index.search(str, maxResults)
- .flatMap((id: string) => {
- if (id[0] === 'c') {
- const { shortcode, static_url } = custom_emojis.get((id as string).slice(1)).toJS();
+ .flatMap((id) => {
+ if (typeof id !== 'string') return;
- return {
- id: shortcode,
- colons: ':' + shortcode + ':',
- custom: true,
- imageUrl: static_url,
- };
+ if (id[0] === 'c' && custom_emojis) {
+ const index = Number(id.slice(1));
+ const custom = custom_emojis.get(index);
+
+ if (custom) {
+ return {
+ id: custom.get('shortcode', ''),
+ colons: ':' + custom.get('shortcode', '') + ':',
+ custom: true,
+ imageUrl: custom.get('static_url', ''),
+ };
+ }
}
- const { skins } = data.emojis[(id as string).slice(1)];
+ const skins = data.emojis[id.slice(1)]?.skins;
- return {
- id: (id as string).slice(1),
- colons: ':' + id.slice(1) + ':',
- unified: skins[0].unified,
- native: skins[0].native,
- };
- });
+ if (skins) {
+ return {
+ id: id.slice(1),
+ colons: ':' + id.slice(1) + ':',
+ unified: skins[0].unified,
+ native: skins[0].native,
+ };
+ }
+ }).filter(Boolean) as Emoji[];
};
export default search;
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..8c8a36db7 100644
--- a/app/soapbox/features/group/components/group-action-button.tsx
+++ b/app/soapbox/features/group/components/group-action-button.tsx
@@ -3,49 +3,84 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { openModal } from 'soapbox/actions/modals';
import { Button } from 'soapbox/components/ui';
+import { deleteEntities } from 'soapbox/entity-store/actions';
+import { Entities } from 'soapbox/entity-store/entities';
import { useAppDispatch } from 'soapbox/hooks';
-import { useCancelMembershipRequest, useJoinGroup, useLeaveGroup } from 'soapbox/queries/groups';
-import { Group } from 'soapbox/types/entities';
+import { useCancelMembershipRequest, useJoinGroup, useLeaveGroup } from 'soapbox/hooks/api';
+import { GroupRoles } from 'soapbox/schemas/group-member';
+import toast from 'soapbox/toast';
+
+import type { Group } from 'soapbox/types/entities';
interface IGroupActionButton {
group: Group
}
const messages = defineMessages({
+ confirmationConfirm: { id: 'confirmations.leave_group.confirm', defaultMessage: 'Leave' },
confirmationHeading: { id: 'confirmations.leave_group.heading', defaultMessage: 'Leave group' },
confirmationMessage: { id: 'confirmations.leave_group.message', defaultMessage: 'You are about to leave the group. Do you want to continue?' },
- confirmationConfirm: { id: 'confirmations.leave_group.confirm', defaultMessage: 'Leave' },
+ joinRequestSuccess: { id: 'group.join.request_success', defaultMessage: 'Requested to join the group' },
+ joinSuccess: { id: 'group.join.success', defaultMessage: 'Group joined successfully!' },
+ leaveSuccess: { id: 'group.leave.success', defaultMessage: 'Left the group' },
});
const GroupActionButton = ({ group }: IGroupActionButton) => {
const dispatch = useAppDispatch();
const intl = useIntl();
- const joinGroup = useJoinGroup();
- const leaveGroup = useLeaveGroup();
- const cancelRequest = useCancelMembershipRequest();
+ const joinGroup = useJoinGroup(group);
+ const leaveGroup = useLeaveGroup(group);
+ const cancelRequest = useCancelMembershipRequest(group);
const isRequested = group.relationship?.requested;
const isNonMember = !group.relationship?.member && !isRequested;
- const isAdmin = group.relationship?.role === 'admin';
+ const isOwner = group.relationship?.role === GroupRoles.OWNER;
const isBlocked = group.relationship?.blocked_by;
- const onJoinGroup = () => joinGroup.mutate(group);
+ const onJoinGroup = () => joinGroup.mutate({}, {
+ onSuccess() {
+ toast.success(
+ group.locked
+ ? intl.formatMessage(messages.joinRequestSuccess)
+ : intl.formatMessage(messages.joinSuccess),
+ );
+ },
+ });
const onLeaveGroup = () =>
dispatch(openModal('CONFIRM', {
heading: intl.formatMessage(messages.confirmationHeading),
message: intl.formatMessage(messages.confirmationMessage),
confirm: intl.formatMessage(messages.confirmationConfirm),
- onConfirm: () => leaveGroup.mutate(group),
+ onConfirm: () => leaveGroup.mutate({}, {
+ onSuccess() {
+ toast.success(intl.formatMessage(messages.leaveSuccess));
+ },
+ }),
}));
- const onCancelRequest = () => cancelRequest.mutate(group);
+ const onCancelRequest = () => cancelRequest.mutate({}, {
+ onSuccess() {
+ dispatch(deleteEntities([group.id], Entities.GROUP_RELATIONSHIPS));
+ },
+ });
if (isBlocked) {
return null;
}
+ if (isOwner) {
+ return (
+
+ );
+ }
+
if (isNonMember) {
return (