fix(publishing): abandon challenge close and clean failed local posts

This commit is contained in:
plebeius
2026-03-05 19:30:50 +08:00
parent 980b5ca572
commit 59851a4b01
9 changed files with 156 additions and 40 deletions
@@ -18,6 +18,7 @@ const useParentAddress = (parentCid?: string) => {
interface ChallengeProps { interface ChallengeProps {
challenge: ChallengeType; challenge: ChallengeType;
closeModal: () => void; closeModal: () => void;
abandonModal: () => void;
} }
const TextChallenge = ({ challenge }: { challenge: string }) => <div className={styles.challengeMedia}>{challenge}</div>; const TextChallenge = ({ challenge }: { challenge: string }) => <div className={styles.challengeMedia}>{challenge}</div>;
@@ -29,12 +30,12 @@ interface IframeChallengeProps {
shortSubplebbitAddress?: string; shortSubplebbitAddress?: string;
subplebbitAddress?: string; subplebbitAddress?: string;
readableUrl: string; readableUrl: string;
closeModal: () => void; onCancel: () => void;
onDone: () => void; onDone: () => void;
publicationDetails: React.ReactNode; publicationDetails: React.ReactNode;
} }
const IframeChallenge = ({ challenge, shortSubplebbitAddress, subplebbitAddress, readableUrl, closeModal, onDone, publicationDetails }: IframeChallengeProps) => { const IframeChallenge = ({ challenge, shortSubplebbitAddress, subplebbitAddress, readableUrl, onCancel, onDone, publicationDetails }: IframeChallengeProps) => {
const account = useAccount(); const account = useAccount();
const [theme] = useTheme(); const [theme] = useTheme();
const [showIframeConfirmation, setShowIframeConfirmation] = useState(true); const [showIframeConfirmation, setShowIframeConfirmation] = useState(true);
@@ -71,9 +72,9 @@ const IframeChallenge = ({ challenge, shortSubplebbitAddress, subplebbitAddress,
} catch (error) { } catch (error) {
console.error('Invalid iframe challenge URL', { error }); console.error('Invalid iframe challenge URL', { error });
alert('Error: Invalid URL for authentication challenge'); alert('Error: Invalid URL for authentication challenge');
closeModal(); onCancel();
} }
}, [account, challenge, closeModal, theme]); }, [account, challenge, onCancel, theme]);
const sendThemeToIframe = useCallback(() => { const sendThemeToIframe = useCallback(() => {
if (!iframeRef.current || !iframeOrigin) return; if (!iframeRef.current || !iframeOrigin) return;
@@ -106,7 +107,7 @@ const IframeChallenge = ({ challenge, shortSubplebbitAddress, subplebbitAddress,
<div className={`${styles.challengeFooter} ${styles.iframeFooter}`}> <div className={`${styles.challengeFooter} ${styles.iframeFooter}`}>
<span className={styles.buttons}> <span className={styles.buttons}>
<button onClick={handleLoadIframe}>Open</button> <button onClick={handleLoadIframe}>Open</button>
<button onClick={closeModal}>Cancel</button> <button onClick={onCancel}>Cancel</button>
</span> </span>
</div> </div>
</> </>
@@ -134,7 +135,7 @@ const IframeChallenge = ({ challenge, shortSubplebbitAddress, subplebbitAddress,
); );
}; };
const Challenge = ({ challenge, closeModal }: ChallengeProps) => { const Challenge = ({ challenge, closeModal, abandonModal }: ChallengeProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
const challenges = challenge?.[0]?.challenges; const challenges = challenge?.[0]?.challenges;
@@ -207,7 +208,7 @@ const Challenge = ({ challenge, closeModal }: ChallengeProps) => {
closeModal(); closeModal();
}; };
const onIframeClose = useCallback(() => { const onIframeDone = useCallback(() => {
if (!publication) return; if (!publication) return;
publication.publishChallengeAnswers(['']); publication.publishChallengeAnswers(['']);
closeModal(); closeModal();
@@ -226,16 +227,12 @@ const Challenge = ({ challenge, closeModal }: ChallengeProps) => {
useEffect(() => { useEffect(() => {
const onEscapeKey = (e: KeyboardEvent) => { const onEscapeKey = (e: KeyboardEvent) => {
if (e.key === 'Escape') { if (e.key === 'Escape') {
if (isIframeChallenge) { abandonModal();
onIframeClose();
} else {
closeModal();
}
} }
}; };
document.addEventListener('keydown', onEscapeKey); document.addEventListener('keydown', onEscapeKey);
return () => document.removeEventListener('keydown', onEscapeKey); return () => document.removeEventListener('keydown', onEscapeKey);
}, [closeModal, isIframeChallenge, onIframeClose]); }, [abandonModal]);
const getChallengeUrl = useCallback(() => { const getChallengeUrl = useCallback(() => {
try { try {
@@ -314,7 +311,7 @@ const Challenge = ({ challenge, closeModal }: ChallengeProps) => {
> >
<div className={`challengeHandle ${styles.title}`} {...(!isMobile ? bind() : {})}> <div className={`challengeHandle ${styles.title}`} {...(!isMobile ? bind() : {})}>
Challenge for {publicationType} Challenge for {publicationType}
<button className={styles.closeIcon} onClick={closeModal} title='close' /> <button className={styles.closeIcon} onClick={abandonModal} title='close' />
</div> </div>
<div className={styles.publication}> <div className={styles.publication}>
{isIframeChallenge ? ( {isIframeChallenge ? (
@@ -324,8 +321,8 @@ const Challenge = ({ challenge, closeModal }: ChallengeProps) => {
shortSubplebbitAddress={shortSubplebbitAddress} shortSubplebbitAddress={shortSubplebbitAddress}
subplebbitAddress={subplebbitAddress} subplebbitAddress={subplebbitAddress}
readableUrl={readableUrl} readableUrl={readableUrl}
closeModal={closeModal} onCancel={abandonModal}
onDone={onIframeClose} onDone={onIframeDone}
publicationDetails={publicationDetails} publicationDetails={publicationDetails}
/> />
) : ( ) : (
@@ -357,7 +354,7 @@ const Challenge = ({ challenge, closeModal }: ChallengeProps) => {
{t('submit')} {t('submit')}
</button> </button>
)} )}
<button onClick={closeModal}>Cancel</button> <button onClick={abandonModal}>Cancel</button>
{challenges?.length > 1 && ( {challenges?.length > 1 && (
<button disabled={!challenges?.[currentChallengeIndex - 1]} onClick={() => setCurrentChallengeIndex((prev) => prev - 1)}> <button disabled={!challenges?.[currentChallengeIndex - 1]} onClick={() => setCurrentChallengeIndex((prev) => prev - 1)}>
{t('previous')} {t('previous')}
@@ -374,14 +371,17 @@ const Challenge = ({ challenge, closeModal }: ChallengeProps) => {
}; };
const ChallengeModal = () => { const ChallengeModal = () => {
const { challenges, removeChallenge } = useChallengesStore(); const { challenges, removeChallenge, abandonCurrentChallenge } = useChallengesStore();
const isOpen = !!challenges.length; const isOpen = !!challenges.length;
const closeModal = () => removeChallenge(); const closeModal = () => removeChallenge();
const abandonModal = () => {
void abandonCurrentChallenge();
};
const current = challenges[0]; const current = challenges[0];
const challenge = current?.challenge; const challenge = current?.challenge;
const challengeId = current?.id ?? 0; const challengeId = current?.id ?? 0;
return isOpen && challenge ? <Challenge key={challengeId} challenge={challenge} closeModal={closeModal} /> : null; return isOpen && challenge ? <Challenge key={challengeId} challenge={challenge} closeModal={closeModal} abandonModal={abandonModal} /> : null;
}; };
export default ChallengeModal; export default ChallengeModal;
+29 -1
View File
@@ -2,7 +2,7 @@ import { useEffect, useRef, useState, useCallback } from 'react';
import { Trans, useTranslation } from 'react-i18next'; import { Trans, useTranslation } from 'react-i18next';
import { Link, useLocation, useNavigationType, useParams } from 'react-router-dom'; import { Link, useLocation, useNavigationType, useParams } from 'react-router-dom';
import { Virtuoso, VirtuosoHandle, StateSnapshot } from 'react-virtuoso'; import { Virtuoso, VirtuosoHandle, StateSnapshot } from 'react-virtuoso';
import { Comment, useEditedComment, useReplies, useAccount, useAccountComment } from '@bitsocialhq/bitsocial-react-hooks'; import { Comment, deleteComment, useEditedComment, useReplies, useAccount, useAccountComment } from '@bitsocialhq/bitsocial-react-hooks';
import getShortAddress from '../../lib/get-short-address'; import getShortAddress from '../../lib/get-short-address';
import styles from '../../views/post/post.module.css'; import styles from '../../views/post/post.module.css';
import { CommentMediaInfo, getDisplayMediaInfoType, getHasThumbnail, getMediaDimensions } from '../../lib/utils/media-utils'; import { CommentMediaInfo, getDisplayMediaInfoType, getHasThumbnail, getMediaDimensions } from '../../lib/utils/media-utils';
@@ -98,6 +98,7 @@ const PostInfo = ({
const displayName = author?.displayName?.trim(); const displayName = author?.displayName?.trim();
const authorRole = roles?.[address]?.role?.replace('moderator', 'mod'); const authorRole = roles?.[address]?.role?.replace('moderator', 'mod');
const hasFailedState = state === 'failed'; const hasFailedState = state === 'failed';
const canDeleteFailedPost = hasFailedState && typeof post?.index === 'number';
const isReply = parentCid; const isReply = parentCid;
const { showOmittedReplies } = useShowOmittedReplies(); const { showOmittedReplies } = useShowOmittedReplies();
const directories = useDirectories(); const directories = useDirectories();
@@ -161,6 +162,7 @@ const PostInfo = ({
}); });
const [initiatedPendingAction, setInitiatedPendingAction] = useState<'approve' | 'reject' | null>(null); const [initiatedPendingAction, setInitiatedPendingAction] = useState<'approve' | 'reject' | null>(null);
const [isDeletingFailedPost, setIsDeletingFailedPost] = useState(false);
const handlePendingApprove = useCallback(async () => { const handlePendingApprove = useCallback(async () => {
const confirm = window.confirm(t('double_confirm')); const confirm = window.confirm(t('double_confirm'));
@@ -244,6 +246,23 @@ const PostInfo = ({
: openReplyModal && openReplyModal(cid, post?.number, postCid, threadNumber, subplebbitAddress); : openReplyModal && openReplyModal(cid, post?.number, postCid, threadNumber, subplebbitAddress);
}; };
const onDeleteFailedPost = () => {
if (isDeletingFailedPost || !canDeleteFailedPost) {
return;
}
setIsDeletingFailedPost(true);
deleteComment(post?.cid || post.index)
.then(() => {
setIsDeletingFailedPost(false);
})
.catch((error) => {
console.error('Failed to delete failed post:', error);
alert(`Failed to delete post: ${error instanceof Error ? error.message : 'Unknown error'}`);
setIsDeletingFailedPost(false);
});
};
return ( return (
<div className={styles.postInfo}> <div className={styles.postInfo}>
{isHidden ? parentCid && <span className={styles.hiddenReplyEditMenuSpacer} /> : <EditMenu post={post} />} {isHidden ? parentCid && <span className={styles.hiddenReplyEditMenuSpacer} /> : <EditMenu post={post} />}
@@ -452,6 +471,15 @@ const PostInfo = ({
)} )}
</span> </span>
)} )}
{canDeleteFailedPost && (
<span className={styles.failedPublishNotice}>
this post failed to publish, it's not visible to other users [{' '}
<button type='button' className={styles.failedDeletePostButton} disabled={isDeletingFailedPost} onClick={onDeleteFailedPost}>
Delete Post
</button>{' '}
]
</span>
)}
</span> </span>
{!(removed || deleted) && !isModQueue && <PostMenuDesktop postMenu={postMenuProps} />} {!(removed || deleted) && !isModQueue && <PostMenuDesktop postMenu={postMenuProps} />}
{cid && parentCid && <ReplyBacklinks post={post} quotedByMap={quotedByMap} directRepliesByParentCid={directRepliesByParentCid} />} {cid && parentCid && <ReplyBacklinks post={post} quotedByMap={quotedByMap} directRepliesByParentCid={directRepliesByParentCid} />}
+29 -1
View File
@@ -2,7 +2,7 @@ import { useEffect, useRef, useState, useCallback } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Link, useLocation, useNavigationType, useParams } from 'react-router-dom'; import { Link, useLocation, useNavigationType, useParams } from 'react-router-dom';
import { Virtuoso, VirtuosoHandle, StateSnapshot } from 'react-virtuoso'; import { Virtuoso, VirtuosoHandle, StateSnapshot } from 'react-virtuoso';
import { Comment, useEditedComment, useReplies, useAccount, usePublishCommentModeration, useAccountComment } from '@bitsocialhq/bitsocial-react-hooks'; import { Comment, deleteComment, useEditedComment, useReplies, useAccount, usePublishCommentModeration, useAccountComment } from '@bitsocialhq/bitsocial-react-hooks';
import getShortAddress from '../../lib/get-short-address'; import getShortAddress from '../../lib/get-short-address';
import styles from '../../views/post/post.module.css'; import styles from '../../views/post/post.module.css';
import { shouldShowSnow } from '../../lib/snow'; import { shouldShowSnow } from '../../lib/snow';
@@ -188,6 +188,7 @@ const PostInfoAndMedia = ({ post, postReplyCount = 0, roles, threadNumber }: Pos
const isOverThreshold = isAwaitingApproval && timeWaiting > alertThresholdSeconds; const isOverThreshold = isAwaitingApproval && timeWaiting > alertThresholdSeconds;
const hasFailedState = state === 'failed'; const hasFailedState = state === 'failed';
const canDeleteFailedPost = hasFailedState && typeof post?.index === 'number';
const postMenuProps = selectPostMenuProps(post); const postMenuProps = selectPostMenuProps(post);
const pseudonymityMode = useSubplebbitField(subplebbitAddress, (sub) => sub?.features?.pseudonymityMode); const pseudonymityMode = useSubplebbitField(subplebbitAddress, (sub) => sub?.features?.pseudonymityMode);
@@ -223,6 +224,24 @@ const PostInfoAndMedia = ({ post, postReplyCount = 0, roles, threadNumber }: Pos
: openReplyModal && openReplyModal(cid, post?.number, postCid, threadNumber, subplebbitAddress); : openReplyModal && openReplyModal(cid, post?.number, postCid, threadNumber, subplebbitAddress);
}; };
const [isDeletingFailedPost, setIsDeletingFailedPost] = useState(false);
const onDeleteFailedPost = () => {
if (isDeletingFailedPost || !canDeleteFailedPost) {
return;
}
setIsDeletingFailedPost(true);
deleteComment(post?.cid || post.index)
.then(() => {
setIsDeletingFailedPost(false);
})
.catch((error) => {
console.error('Failed to delete failed post:', error);
alert(`Failed to delete post: ${error instanceof Error ? error.message : 'Unknown error'}`);
setIsDeletingFailedPost(false);
});
};
return ( return (
<> <>
<div className={styles.postInfo}> <div className={styles.postInfo}>
@@ -393,6 +412,15 @@ const PostInfoAndMedia = ({ post, postReplyCount = 0, roles, threadNumber }: Pos
</div> </div>
)} )}
</span> </span>
{canDeleteFailedPost && (
<span className={styles.failedPublishNotice}>
this post failed to publish, it's not visible to other users [{' '}
<button type='button' className={styles.failedDeletePostButton} disabled={isDeletingFailedPost} onClick={onDeleteFailedPost}>
Delete Post
</button>{' '}
]
</span>
)}
</span> </span>
</div> </div>
{(hasThumbnail || link) && !(deleted || removed) && <PostMediaContent key={cid} post={post} link={link} />} {(hasThumbnail || link) && !(deleted || removed) && <PostMediaContent key={cid} post={post} link={link} />}
+18 -2
View File
@@ -1,6 +1,7 @@
import { useCallback } from 'react'; import { useCallback, useMemo, useRef } from 'react';
import { Comment, usePublishComment } from '@bitsocialhq/bitsocial-react-hooks'; import { Comment, usePublishComment } from '@bitsocialhq/bitsocial-react-hooks';
import usePublishPostStore from '../stores/use-publish-post-store'; import usePublishPostStore from '../stores/use-publish-post-store';
import useChallengesStore from '../stores/use-challenges-store';
const usePublishPost = ({ subplebbitAddress }: { subplebbitAddress?: string }) => { const usePublishPost = ({ subplebbitAddress }: { subplebbitAddress?: string }) => {
const { author, title, content, link, spoiler, publishCommentOptions } = usePublishPostStore((state) => ({ const { author, title, content, link, spoiler, publishCommentOptions } = usePublishPostStore((state) => ({
@@ -14,6 +15,8 @@ const usePublishPost = ({ subplebbitAddress }: { subplebbitAddress?: string }) =
const setPublishPostStore = usePublishPostStore((state) => state.setPublishPostStore); const setPublishPostStore = usePublishPostStore((state) => state.setPublishPostStore);
const resetPublishPostStore = usePublishPostStore((state) => state.resetPublishPostStore); const resetPublishPostStore = usePublishPostStore((state) => state.resetPublishPostStore);
const addChallenge = useChallengesStore((state) => state.addChallenge);
const abandonPublishRef = useRef<(() => Promise<void>) | undefined>();
const createBaseOptions = useCallback(() => { const createBaseOptions = useCallback(() => {
const baseOptions: Comment = { const baseOptions: Comment = {
@@ -51,7 +54,20 @@ const usePublishPost = ({ subplebbitAddress }: { subplebbitAddress?: string }) =
const resetPublishPostOptions = useCallback(() => resetPublishPostStore(), [resetPublishPostStore]); const resetPublishPostOptions = useCallback(() => resetPublishPostStore(), [resetPublishPostStore]);
const { index, publishComment } = usePublishComment(publishCommentOptions); const publishOptionsWithAbandon = useMemo(
() => ({
...publishCommentOptions,
onChallenge: async (...args: any[]) => {
addChallenge(args, async () => {
await abandonPublishRef.current?.();
});
},
}),
[addChallenge, publishCommentOptions],
);
const { index, publishComment, abandonPublish } = usePublishComment(publishOptionsWithAbandon);
abandonPublishRef.current = abandonPublish;
return { return {
setPublishPostOptions, setPublishPostOptions,
+18 -3
View File
@@ -1,8 +1,9 @@
import { useCallback, useMemo } from 'react'; import { useCallback, useMemo, useRef } from 'react';
import { Comment, usePublishComment } from '@bitsocialhq/bitsocial-react-hooks'; import { Comment, usePublishComment } from '@bitsocialhq/bitsocial-react-hooks';
import usePublishReplyStore from '../stores/use-publish-reply-store'; import usePublishReplyStore from '../stores/use-publish-reply-store';
import usePostNumberStore from '../stores/use-post-number-store'; import usePostNumberStore from '../stores/use-post-number-store';
import { getQuotedCidsFromContent, mergeQuotedCids } from '../lib/utils/reply-quote-utils'; import { getQuotedCidsFromContent, mergeQuotedCids } from '../lib/utils/reply-quote-utils';
import useChallengesStore from '../stores/use-challenges-store';
const usePublishReply = ({ cid, subplebbitAddress, postCid }: { cid: string; subplebbitAddress: string; postCid?: string }) => { const usePublishReply = ({ cid, subplebbitAddress, postCid }: { cid: string; subplebbitAddress: string; postCid?: string }) => {
const parentCid = cid; const parentCid = cid;
@@ -17,6 +18,8 @@ const usePublishReply = ({ cid, subplebbitAddress, postCid }: { cid: string; sub
const setPublishReplyStore = usePublishReplyStore((state) => state.setPublishReplyStore); const setPublishReplyStore = usePublishReplyStore((state) => state.setPublishReplyStore);
const resetPublishReplyStore = usePublishReplyStore((state) => state.resetPublishReplyStore); const resetPublishReplyStore = usePublishReplyStore((state) => state.resetPublishReplyStore);
const addChallenge = useChallengesStore((state) => state.addChallenge);
const abandonPublishRef = useRef<(() => Promise<void>) | undefined>();
const createBaseOptions = useCallback(() => { const createBaseOptions = useCallback(() => {
const baseOptions: Comment = { const baseOptions: Comment = {
@@ -58,9 +61,21 @@ const usePublishReply = ({ cid, subplebbitAddress, postCid }: { cid: string; sub
const scopedNumberToCid = usePostNumberStore((state) => (subplebbitAddress ? state.numberToCid[subplebbitAddress] : undefined)); const scopedNumberToCid = usePostNumberStore((state) => (subplebbitAddress ? state.numberToCid[subplebbitAddress] : undefined));
const quotedCids = useMemo(() => getQuotedCidsFromContent(content, scopedNumberToCid), [content, scopedNumberToCid]); const quotedCids = useMemo(() => getQuotedCidsFromContent(content, scopedNumberToCid), [content, scopedNumberToCid]);
const publishOptions = useMemo(() => mergeQuotedCids(publishCommentOptions, quotedCids), [publishCommentOptions, quotedCids]); const mergedPublishOptions = useMemo(() => mergeQuotedCids(publishCommentOptions, quotedCids), [publishCommentOptions, quotedCids]);
const publishOptionsWithAbandon = useMemo(
() => ({
...mergedPublishOptions,
onChallenge: async (...args: any[]) => {
addChallenge(args, async () => {
await abandonPublishRef.current?.();
});
},
}),
[addChallenge, mergedPublishOptions],
);
const { index, publishComment } = usePublishComment(publishOptions); const { index, publishComment, abandonPublish } = usePublishComment(publishOptionsWithAbandon);
abandonPublishRef.current = abandonPublish;
return { return {
setPublishReplyOptions, setPublishReplyOptions,
+16 -5
View File
@@ -4,16 +4,17 @@ import { Challenge } from '@bitsocialhq/bitsocial-react-hooks';
let nextChallengeId = 0; let nextChallengeId = 0;
interface State { interface State {
challenges: Array<{ challenge: Challenge; id: number }>; challenges: Array<{ challenge: Challenge; id: number; onAbandon?: () => Promise<void> | void }>;
addChallenge: (challenge: Challenge) => void; addChallenge: (challenge: Challenge, onAbandon?: () => Promise<void> | void) => void;
removeChallenge: () => void; removeChallenge: () => void;
abandonCurrentChallenge: () => Promise<void>;
} }
const useChallengesStore = create<State>((set) => ({ const useChallengesStore = create<State>((set, get) => ({
challenges: [], challenges: [],
addChallenge: (challenge: Challenge) => { addChallenge: (challenge: Challenge, onAbandon?: () => Promise<void> | void) => {
set((state) => ({ set((state) => ({
challenges: [...state.challenges, { challenge, id: nextChallengeId++ }], challenges: [...state.challenges, { challenge, id: nextChallengeId++, onAbandon }],
})); }));
}, },
removeChallenge: () => { removeChallenge: () => {
@@ -23,6 +24,16 @@ const useChallengesStore = create<State>((set) => ({
return { challenges }; return { challenges };
}); });
}, },
abandonCurrentChallenge: async () => {
const currentChallenge = get().challenges[0];
try {
await currentChallenge?.onAbandon?.();
} catch (error) {
console.error('Failed to abandon challenge publication:', error);
} finally {
get().removeChallenge();
}
},
})); }));
export default useChallengesStore; export default useChallengesStore;
-4
View File
@@ -1,7 +1,6 @@
import { ChallengeVerification, Comment, PublishCommentOptions } from '@bitsocialhq/bitsocial-react-hooks'; import { ChallengeVerification, Comment, PublishCommentOptions } from '@bitsocialhq/bitsocial-react-hooks';
import { create } from 'zustand'; import { create } from 'zustand';
import { alertChallengeVerificationFailed } from '../lib/utils/challenge-utils'; import { alertChallengeVerificationFailed } from '../lib/utils/challenge-utils';
import useChallengesStore from './use-challenges-store';
type SubmitState = { type SubmitState = {
author?: any | undefined; author?: any | undefined;
@@ -16,8 +15,6 @@ type SubmitState = {
resetPublishPostStore: () => void; resetPublishPostStore: () => void;
}; };
const { addChallenge } = useChallengesStore.getState();
const usePublishPostStore = create<SubmitState>((set) => ({ const usePublishPostStore = create<SubmitState>((set) => ({
author: undefined, author: undefined,
displayName: undefined, displayName: undefined,
@@ -44,7 +41,6 @@ const usePublishPostStore = create<SubmitState>((set) => ({
content, content,
link, link,
spoiler, spoiler,
onChallenge: (...args: any) => addChallenge(args),
onChallengeVerification: (challengeVerification: ChallengeVerification, comment: Comment) => { onChallengeVerification: (challengeVerification: ChallengeVerification, comment: Comment) => {
alertChallengeVerificationFailed(challengeVerification, comment); alertChallengeVerificationFailed(challengeVerification, comment);
}, },
-4
View File
@@ -1,7 +1,6 @@
import { ChallengeVerification, Comment, PublishCommentOptions } from '@bitsocialhq/bitsocial-react-hooks'; import { ChallengeVerification, Comment, PublishCommentOptions } from '@bitsocialhq/bitsocial-react-hooks';
import { create } from 'zustand'; import { create } from 'zustand';
import { alertChallengeVerificationFailed } from '../lib/utils/challenge-utils'; import { alertChallengeVerificationFailed } from '../lib/utils/challenge-utils';
import useChallengesStore from './use-challenges-store';
type ReplyState = { type ReplyState = {
author: { [parentCid: string]: any | undefined }; author: { [parentCid: string]: any | undefined };
@@ -14,8 +13,6 @@ type ReplyState = {
resetPublishReplyStore: (parentCid: string) => void; resetPublishReplyStore: (parentCid: string) => void;
}; };
const { addChallenge } = useChallengesStore.getState();
const usePublishReplyStore = create<ReplyState>((set) => ({ const usePublishReplyStore = create<ReplyState>((set) => ({
author: {}, author: {},
displayName: {}, displayName: {},
@@ -42,7 +39,6 @@ const usePublishReplyStore = create<ReplyState>((set) => ({
content, content,
link, link,
spoiler, spoiler,
onChallenge: (...args: any) => addChallenge(args),
onChallengeVerification: (challengeVerification: ChallengeVerification, comment: Comment) => { onChallengeVerification: (challengeVerification: ChallengeVerification, comment: Comment) => {
alertChallengeVerificationFailed(challengeVerification, comment); alertChallengeVerificationFailed(challengeVerification, comment);
}, },
+27 -1
View File
@@ -582,6 +582,32 @@
font-weight: 700; font-weight: 700;
} }
.failedPublishNotice {
display: block;
margin-top: 4px;
color: red;
font-weight: 700;
}
.failedDeletePostButton {
all: unset;
color: red;
cursor: pointer;
font-weight: 700;
text-decoration: underline;
text-transform: uppercase;
}
.failedDeletePostButton:hover:not(:disabled) {
color: #b30000;
}
.failedDeletePostButton:disabled {
cursor: wait;
opacity: 0.7;
text-decoration: none;
}
.grayEditMessage { .grayEditMessage {
color: var(--post-mobile-abbr-text-color); color: var(--post-mobile-abbr-text-color);
} }
@@ -709,4 +735,4 @@
0% { opacity: 1; } 0% { opacity: 1; }
50% { opacity: 0.5; } 50% { opacity: 0.5; }
100% { opacity: 1; } 100% { opacity: 1; }
} }