Nostr Zaps
This commit is contained in:
parent
e281fbade9
commit
9cad54c97c
5 changed files with 67 additions and 2 deletions
|
@ -78,6 +78,10 @@ const FAVOURITES_EXPAND_FAIL = 'FAVOURITES_EXPAND_FAIL';
|
|||
const REBLOGS_EXPAND_SUCCESS = 'REBLOGS_EXPAND_SUCCESS';
|
||||
const REBLOGS_EXPAND_FAIL = 'REBLOGS_EXPAND_FAIL';
|
||||
|
||||
const ZAP_REQUEST = 'ZAP_REQUEST';
|
||||
const ZAP_SUCCESS = 'ZAP_SUCCESS';
|
||||
const ZAP_FAIL = 'ZAP_FAIL';
|
||||
|
||||
const messages = defineMessages({
|
||||
bookmarkAdded: { id: 'status.bookmarked', defaultMessage: 'Bookmark added.' },
|
||||
bookmarkRemoved: { id: 'status.unbookmarked', defaultMessage: 'Bookmark removed.' },
|
||||
|
@ -306,6 +310,38 @@ const undislikeFail = (status: StatusEntity, error: unknown) => ({
|
|||
skipLoading: true,
|
||||
});
|
||||
|
||||
const zap = (status: StatusEntity, amount: number) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
if (!isLoggedIn(getState)) return;
|
||||
|
||||
dispatch(zapRequest(status));
|
||||
|
||||
api(getState).post(`/api/v1/statuses/${status.id}/zap`, { amount }).then(function(response) {
|
||||
dispatch(zapSuccess(status));
|
||||
}).catch(function(error) {
|
||||
dispatch(zapFail(status, error));
|
||||
});
|
||||
};
|
||||
|
||||
const zapRequest = (status: StatusEntity) => ({
|
||||
type: ZAP_REQUEST,
|
||||
status: status,
|
||||
skipLoading: true,
|
||||
});
|
||||
|
||||
const zapSuccess = (status: StatusEntity) => ({
|
||||
type: ZAP_SUCCESS,
|
||||
status: status,
|
||||
skipLoading: true,
|
||||
});
|
||||
|
||||
const zapFail = (status: StatusEntity, error: unknown) => ({
|
||||
type: ZAP_FAIL,
|
||||
status: status,
|
||||
error: error,
|
||||
skipLoading: true,
|
||||
});
|
||||
|
||||
const bookmark = (status: StatusEntity) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||
dispatch(bookmarkRequest(status));
|
||||
|
@ -801,4 +837,5 @@ export {
|
|||
remoteInteractionRequest,
|
||||
remoteInteractionSuccess,
|
||||
remoteInteractionFail,
|
||||
zap,
|
||||
};
|
||||
|
|
|
@ -6,7 +6,7 @@ import { blockAccount } from 'soapbox/actions/accounts';
|
|||
import { launchChat } from 'soapbox/actions/chats';
|
||||
import { directCompose, mentionCompose, quoteCompose, replyCompose } from 'soapbox/actions/compose';
|
||||
import { editEvent } from 'soapbox/actions/events';
|
||||
import { pinToGroup, toggleBookmark, toggleDislike, toggleFavourite, togglePin, toggleReblog, unpinFromGroup } from 'soapbox/actions/interactions';
|
||||
import { pinToGroup, toggleBookmark, toggleDislike, toggleFavourite, togglePin, toggleReblog, unpinFromGroup, zap } from 'soapbox/actions/interactions';
|
||||
import { openModal } from 'soapbox/actions/modals';
|
||||
import { deleteStatusModal, toggleStatusSensitivityModal } from 'soapbox/actions/moderation';
|
||||
import { initMuteModal } from 'soapbox/actions/mutes';
|
||||
|
@ -103,6 +103,7 @@ const messages = defineMessages({
|
|||
unmuteSuccess: { id: 'group.unmute.success', defaultMessage: 'Unmuted the group' },
|
||||
unpin: { id: 'status.unpin', defaultMessage: 'Unpin from profile' },
|
||||
unpinFromGroup: { id: 'status.unpin_to_group', defaultMessage: 'Unpin from Group' },
|
||||
zap: { id: 'status.zap', defaultMessage: 'Zap' },
|
||||
});
|
||||
|
||||
interface IStatusActionBar {
|
||||
|
@ -188,6 +189,14 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
|
|||
}
|
||||
};
|
||||
|
||||
const handleZapClick: React.EventHandler<React.MouseEvent> = (e) => {
|
||||
if (me) {
|
||||
dispatch(zap(status, 1337));
|
||||
} else {
|
||||
onOpenUnauthorizedModal('ZAP');
|
||||
}
|
||||
};
|
||||
|
||||
const handleBookmarkClick: React.EventHandler<React.MouseEvent> = (e) => {
|
||||
dispatch(toggleBookmark(status));
|
||||
};
|
||||
|
@ -694,6 +703,7 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
|
|||
}
|
||||
|
||||
const canShare = ('share' in navigator) && (status.visibility === 'public' || status.visibility === 'group');
|
||||
const acceptsZaps = status.account.ditto.accepts_zaps === true;
|
||||
|
||||
const spacing: {
|
||||
[key: string]: React.ComponentProps<typeof HStack>['space'];
|
||||
|
@ -781,6 +791,19 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
|
|||
/>
|
||||
)}
|
||||
|
||||
{acceptsZaps && (
|
||||
<StatusActionButton
|
||||
title={intl.formatMessage(messages.zap)}
|
||||
icon={require('@tabler/icons/bolt.svg')}
|
||||
color='accent'
|
||||
filled
|
||||
onClick={handleZapClick}
|
||||
active={status.zapped}
|
||||
text={withLabels ? intl.formatMessage(messages.zap) : undefined}
|
||||
theme={statusActionButtonTheme}
|
||||
/>
|
||||
)}
|
||||
|
||||
{canShare && (
|
||||
<StatusActionButton
|
||||
title={intl.formatMessage(messages.share)}
|
||||
|
|
|
@ -82,6 +82,7 @@ export const StatusRecord = ImmutableRecord({
|
|||
uri: '',
|
||||
url: '',
|
||||
visibility: 'public' as StatusVisibility,
|
||||
zapped: false,
|
||||
event: null as ReturnType<typeof EventRecord> | null,
|
||||
|
||||
// Internal fields
|
||||
|
|
|
@ -6,7 +6,7 @@ import { unescapeHTML } from 'soapbox/utils/html';
|
|||
|
||||
import { customEmojiSchema } from './custom-emoji';
|
||||
import { relationshipSchema } from './relationship';
|
||||
import { contentSchema, filteredArray, makeCustomEmojiMap } from './utils';
|
||||
import { coerceObject, contentSchema, filteredArray, makeCustomEmojiMap } from './utils';
|
||||
|
||||
import type { Resolve } from 'soapbox/utils/types';
|
||||
|
||||
|
@ -29,6 +29,9 @@ const baseAccountSchema = z.object({
|
|||
created_at: z.string().datetime().catch(new Date().toUTCString()),
|
||||
discoverable: z.boolean().catch(false),
|
||||
display_name: z.string().catch(''),
|
||||
ditto: coerceObject({
|
||||
accepts_zaps: z.boolean().catch(false),
|
||||
}),
|
||||
emojis: filteredArray(customEmojiSchema),
|
||||
fields: filteredArray(fieldSchema),
|
||||
followers_count: z.number().catch(0),
|
||||
|
|
|
@ -67,6 +67,7 @@ const baseStatusSchema = z.object({
|
|||
uri: z.string().url().catch(''),
|
||||
url: z.string().url().catch(''),
|
||||
visibility: z.string().catch('public'),
|
||||
zapped: z.coerce.boolean(),
|
||||
});
|
||||
|
||||
type BaseStatus = z.infer<typeof baseStatusSchema>;
|
||||
|
|
Loading…
Reference in a new issue