From def7cc4d14508f99c1195fe2cb9a1f493a14cf45 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sun, 9 Jun 2024 17:00:41 -0500 Subject: [PATCH] Support ditto:name_grant notification type --- src/features/edit-profile/index.tsx | 4 +- .../notifications/components/notification.tsx | 52 ++++++++++++++----- src/normalizers/notification.ts | 1 + src/schemas/notification.ts | 7 ++- src/utils/notification.ts | 1 + 5 files changed, 48 insertions(+), 17 deletions(-) diff --git a/src/features/edit-profile/index.tsx b/src/features/edit-profile/index.tsx index f185f9e63..971084931 100644 --- a/src/features/edit-profile/index.tsx +++ b/src/features/edit-profile/index.tsx @@ -129,8 +129,8 @@ interface AccountCredentials { birthday?: string; /** Nostr NIP-05 identifier. */ nip05?: string; - /** - * Lightning address. + /** + * Lightning address. * https://github.com/lnurl/luds/blob/luds/16.md */ lud16?: string; diff --git a/src/features/notifications/components/notification.tsx b/src/features/notifications/components/notification.tsx index 7a05a7d23..fca1e79e6 100644 --- a/src/features/notifications/components/notification.tsx +++ b/src/features/notifications/components/notification.tsx @@ -1,19 +1,21 @@ import React, { useCallback } from 'react'; -import { defineMessages, useIntl, FormattedMessage, IntlShape, MessageDescriptor, defineMessage } from 'react-intl'; +import { defineMessages, useIntl, IntlShape, MessageDescriptor, defineMessage, FormattedMessage } from 'react-intl'; import { Link, useHistory } from 'react-router-dom'; import { mentionCompose } from 'soapbox/actions/compose'; import { reblog, favourite, unreblog, unfavourite } from 'soapbox/actions/interactions'; +import { patchMe } from 'soapbox/actions/me'; import { openModal } from 'soapbox/actions/modals'; import { getSettings } from 'soapbox/actions/settings'; import { hideStatus, revealStatus } from 'soapbox/actions/statuses'; import Icon from 'soapbox/components/icon'; -import { HStack, Text, Emoji } from 'soapbox/components/ui'; +import { HStack, Text, Emoji, Button, Stack } from 'soapbox/components/ui'; import AccountContainer from 'soapbox/containers/account-container'; import StatusContainer from 'soapbox/containers/status-container'; import { HotKeys } from 'soapbox/features/ui/components/hotkeys'; import { useAppDispatch, useAppSelector, useInstance } from 'soapbox/hooks'; import { makeGetNotification } from 'soapbox/selectors'; +import toast from 'soapbox/toast'; import { NotificationType, validType } from 'soapbox/utils/notification'; import type { ScrollPosition } from 'soapbox/components/status'; @@ -56,6 +58,7 @@ const icons: Record = { 'pleroma:event_reminder': require('@tabler/icons/outline/calendar-time.svg'), 'pleroma:participation_request': require('@tabler/icons/outline/calendar-event.svg'), 'pleroma:participation_accepted': require('@tabler/icons/outline/calendar-event.svg'), + 'ditto:name_grant': require('@tabler/icons/outline/user-check.svg'), }; const nameMessage = defineMessage({ @@ -63,7 +66,7 @@ const nameMessage = defineMessage({ defaultMessage: '{link}{others}', }); -const messages: Record = defineMessages({ +const notificationMessages: Record = defineMessages({ follow: { id: 'notification.follow', defaultMessage: '{name} followed you', @@ -132,29 +135,32 @@ const messages: Record = defineMessages({ id: 'notification.pleroma:participation_accepted', defaultMessage: 'You were accepted to join the event', }, + 'ditto:name_grant': { + id: 'notification.ditto:name_grant', + defaultMessage: 'You were granted the name {acct}', + }, +}); + +const messages = defineMessages({ + updateNameSuccess: { id: 'notification.update_name_success', defaultMessage: 'Name updated successfully' }, }); const buildMessage = ( intl: IntlShape, type: NotificationType, account: AccountEntity, - totalCount: number | null, + acct: string | undefined, targetName: string, instanceTitle: string, ): React.ReactNode => { const link = buildLink(account); const name = intl.formatMessage(nameMessage, { link, - others: totalCount && totalCount > 0 ? ( - - ) : '', + others: '', }); - return intl.formatMessage(messages[type], { + return intl.formatMessage(notificationMessages[type], { + acct, name, targetName, instance: instanceTitle, @@ -274,6 +280,11 @@ const Notification: React.FC = (props) => { } }; + const updateName = async (name: string) => { + await dispatch(patchMe({ nip05: name })); + toast.success(messages.updateNameSuccess); + }; + const renderIcon = (): React.ReactNode => { if (type === 'pleroma:emoji_reaction' && notification.emoji) { return ( @@ -349,19 +360,32 @@ const Notification: React.FC = (props) => { showGroup={false} /> ) : null; + case 'ditto:name_grant': + return ( + + + + ); default: return null; } }; + const acct = notification.name; const targetName = notification.target && typeof notification.target === 'object' ? notification.target.acct : ''; - const message: React.ReactNode = validType(type) && account && typeof account === 'object' ? buildMessage(intl, type, account, notification.total_count, targetName, instance.title) : null; + const message: React.ReactNode = validType(type) && account && typeof account === 'object' ? buildMessage(intl, type, account, acct, targetName, instance.title) : null; const ariaLabel = validType(type) ? ( notificationForScreenReader( intl, - intl.formatMessage(messages[type], { + intl.formatMessage(notificationMessages[type], { + acct, name: account && typeof account === 'object' ? account.acct : '', targetName, }), diff --git a/src/normalizers/notification.ts b/src/normalizers/notification.ts index 45eb93fb3..1ee8f439a 100644 --- a/src/normalizers/notification.ts +++ b/src/normalizers/notification.ts @@ -19,6 +19,7 @@ export const NotificationRecord = ImmutableRecord({ emoji: null as string | null, // pleroma:emoji_reaction emoji_url: null as string | null, // pleroma:emoji_reaction id: '', + name: '', // ditto:name_grant status: null as EmbeddedEntity, target: null as EmbeddedEntity, // move type: '', diff --git a/src/schemas/notification.ts b/src/schemas/notification.ts index 3c77de6bf..e468c4e2b 100644 --- a/src/schemas/notification.ts +++ b/src/schemas/notification.ts @@ -10,7 +10,6 @@ const baseNotificationSchema = z.object({ created_at: z.string().datetime().catch(new Date().toUTCString()), id: z.string(), type: z.string(), - total_count: z.number().optional().catch(undefined), // TruthSocial }); const mentionNotificationSchema = baseNotificationSchema.extend({ @@ -82,6 +81,11 @@ const participationAcceptedNotificationSchema = baseNotificationSchema.extend({ status: statusSchema, }); +const nameGrantNotificationSchema = baseNotificationSchema.extend({ + type: z.literal('ditto:name_grant'), + name: z.string(), +}); + const notificationSchema = z.discriminatedUnion('type', [ mentionNotificationSchema, statusNotificationSchema, @@ -97,6 +101,7 @@ const notificationSchema = z.discriminatedUnion('type', [ eventReminderNotificationSchema, participationRequestNotificationSchema, participationAcceptedNotificationSchema, + nameGrantNotificationSchema, ]); type Notification = z.infer; diff --git a/src/utils/notification.ts b/src/utils/notification.ts index fdd8e25fe..d18e1d22a 100644 --- a/src/utils/notification.ts +++ b/src/utils/notification.ts @@ -17,6 +17,7 @@ const NOTIFICATION_TYPES = [ 'pleroma:event_reminder', 'pleroma:participation_request', 'pleroma:participation_accepted', + 'ditto:name_grant', ] as const; /** Notification types to exclude from the "All" filter by default. */