chore: convert forum actions into a class

This commit is contained in:
Danish Arora 2025-09-01 16:31:57 +05:30
parent 34279ff8b1
commit 635e3eb80a
No known key found for this signature in database
GPG Key ID: 1C6EF37CDAE1426E
9 changed files with 559 additions and 561 deletions

View File

@ -20,7 +20,7 @@ import {
} from '@/components/ui/select';
import { CypherImage } from './ui/CypherImage';
import { RelevanceIndicator } from './ui/relevance-indicator';
import { sortCells, SortOption } from '@/lib/forum/sorting';
import { sortCells, SortOption } from '@/lib/utils/sorting';
const CellList = () => {
const { cells, isInitialLoading, posts, refreshData, isRefreshing } =

View File

@ -9,15 +9,7 @@ import { Cell, Post, Comment, OpchanMessage } from '@/types/forum';
import { User, EVerificationStatus, DisplayPreference } from '@/types/identity';
import { useToast } from '@/components/ui/use-toast';
import { useAuth } from '@/contexts/useAuth';
import {
createPost,
createComment,
vote,
createCell,
moderatePost,
moderateComment,
moderateUser,
} from '@/lib/forum/actions';
import { ForumActions } from '@/lib/forum/ForumActions';
import {
setupPeriodicQueries,
monitorNetworkHealth,
@ -25,7 +17,7 @@ import {
} from '@/lib/waku/network';
import messageManager from '@/lib/waku';
import { getDataFromCache } from '@/lib/forum/transformers';
import { RelevanceCalculator } from '@/lib/forum/relevance';
import { RelevanceCalculator } from '@/lib/forum/RelevanceCalculator';
import { UserVerificationStatus } from '@/types/forum';
import { CryptoService } from '@/lib/services';
import { getEnsName } from '@wagmi/core';
@ -107,6 +99,10 @@ export function ForumProvider({ children }: { children: React.ReactNode }) {
const { currentUser, isAuthenticated } = useAuth();
const cryptoService = useMemo(() => new CryptoService(), []);
const forumActions = useMemo(
() => new ForumActions(cryptoService),
[cryptoService]
);
// Transform message cache data to the expected types
const updateStateFromCache = useCallback(() => {
@ -289,7 +285,7 @@ export function ForumProvider({ children }: { children: React.ReactNode }) {
description: 'Sending your post to the network...',
});
const result = await createPost(
const result = await forumActions.createPost(
{ cellId, title, content, currentUser, isAuthenticated },
updateStateFromCache
);
@ -322,11 +318,8 @@ export function ForumProvider({ children }: { children: React.ReactNode }) {
description: 'Sending your comment to the network...',
});
const result = await createComment(
postId,
content,
currentUser,
isAuthenticated,
const result = await forumActions.createComment(
{ postId, content, currentUser, isAuthenticated },
updateStateFromCache
);
@ -359,11 +352,8 @@ export function ForumProvider({ children }: { children: React.ReactNode }) {
description: 'Recording your vote on the network...',
});
const result = await vote(
postId,
isUpvote,
currentUser,
isAuthenticated,
const result = await forumActions.vote(
{ targetId: postId, isUpvote, currentUser, isAuthenticated },
updateStateFromCache
);
@ -397,11 +387,8 @@ export function ForumProvider({ children }: { children: React.ReactNode }) {
description: 'Recording your vote on the network...',
});
const result = await vote(
commentId,
isUpvote,
currentUser,
isAuthenticated,
const result = await forumActions.vote(
{ targetId: commentId, isUpvote, currentUser, isAuthenticated },
updateStateFromCache
);
@ -435,12 +422,8 @@ export function ForumProvider({ children }: { children: React.ReactNode }) {
description: 'Sending your cell to the network...',
});
const result = await createCell(
name,
description,
icon,
currentUser,
isAuthenticated,
const result = await forumActions.createCell(
{ name, description, icon, currentUser, isAuthenticated },
updateStateFromCache
);
@ -473,13 +456,8 @@ export function ForumProvider({ children }: { children: React.ReactNode }) {
description: 'Sending moderation message to the network...',
});
const result = await moderatePost(
cellId,
postId,
reason,
currentUser,
isAuthenticated,
cellOwner,
const result = await forumActions.moderatePost(
{ cellId, postId, reason, currentUser, isAuthenticated, cellOwner },
updateStateFromCache
);
@ -511,13 +489,8 @@ export function ForumProvider({ children }: { children: React.ReactNode }) {
description: 'Sending moderation message to the network...',
});
const result = await moderateComment(
cellId,
commentId,
reason,
currentUser,
isAuthenticated,
cellOwner,
const result = await forumActions.moderateComment(
{ cellId, commentId, reason, currentUser, isAuthenticated, cellOwner },
updateStateFromCache
);
@ -544,13 +517,8 @@ export function ForumProvider({ children }: { children: React.ReactNode }) {
reason: string | undefined,
cellOwner: string
) => {
const result = await moderateUser(
cellId,
userAddress,
reason,
currentUser,
isAuthenticated,
cellOwner,
const result = await forumActions.moderateUser(
{ cellId, userAddress, reason, currentUser, isAuthenticated, cellOwner },
updateStateFromCache
);

View File

@ -0,0 +1,534 @@
import { v4 as uuidv4 } from 'uuid';
import {
MessageType,
UnsignedCellMessage,
UnsignedCommentMessage,
UnsignedPostMessage,
UnsignedVoteMessage,
UnsignedModerateMessage,
CellMessage,
CommentMessage,
PostMessage,
} from '@/types/waku';
import { Cell, Comment, Post } from '@/types/forum';
import { EVerificationStatus, User } from '@/types/identity';
import { transformCell, transformComment, transformPost } from './transformers';
import { MessageService, CryptoService } from '@/lib/services';
type ActionResult<T> = {
success: boolean;
data?: T;
error?: string;
};
export class ForumActions {
private cryptoService: CryptoService;
private messageService: MessageService;
constructor(cryptoService?: CryptoService) {
this.cryptoService = cryptoService || new CryptoService();
this.messageService = new MessageService(this.cryptoService);
}
/* ------------------------------------------------------------------
POST / COMMENT / CELL CREATION
-------------------------------------------------------------------*/
async createPost(
params: PostCreationParams,
updateStateFromCache: () => void
): Promise<ActionResult<Post>> {
const { cellId, title, content, currentUser, isAuthenticated } = params;
if (!isAuthenticated || !currentUser) {
return {
success: false,
error:
'Authentication required. You need to connect your wallet to post.',
};
}
// Check if user has basic verification or better, or owns ENS/Ordinal
const hasENSOrOrdinal = !!(
currentUser.ensDetails || currentUser.ordinalDetails
);
const isVerified =
currentUser.verificationStatus === EVerificationStatus.VERIFIED_OWNER ||
currentUser.verificationStatus === EVerificationStatus.VERIFIED_BASIC ||
hasENSOrOrdinal;
if (
!isVerified &&
(currentUser.verificationStatus === EVerificationStatus.UNVERIFIED ||
currentUser.verificationStatus === EVerificationStatus.VERIFYING)
) {
return {
success: false,
error:
'Verification required. Please complete wallet verification to post.',
};
}
try {
const postId = uuidv4();
const postMessage: UnsignedPostMessage = {
type: MessageType.POST,
id: postId,
cellId,
title,
content,
timestamp: Date.now(),
author: currentUser.address,
};
const result = await this.messageService.sendMessage(postMessage);
if (!result.success) {
return {
success: false,
error: result.error || 'Failed to create post. Please try again.',
};
}
updateStateFromCache();
const transformedPost = transformPost(result.message! as PostMessage);
if (!transformedPost) {
return {
success: false,
error: 'Failed to transform post data.',
};
}
return {
success: true,
data: transformedPost,
};
} catch (error) {
console.error('Error creating post:', error);
return {
success: false,
error: 'Failed to create post. Please try again.',
};
}
}
async createComment(
params: CommentCreationParams,
updateStateFromCache: () => void
): Promise<ActionResult<Comment>> {
const { postId, content, currentUser, isAuthenticated } = params;
if (!isAuthenticated || !currentUser) {
return {
success: false,
error:
'Authentication required. You need to connect your wallet to comment.',
};
}
// Check if user has basic verification or better, or owns ENS/Ordinal
const hasENSOrOrdinal = !!(
currentUser.ensDetails || currentUser.ordinalDetails
);
const isVerified =
currentUser.verificationStatus === EVerificationStatus.VERIFIED_OWNER ||
currentUser.verificationStatus === EVerificationStatus.VERIFIED_BASIC ||
hasENSOrOrdinal;
if (
!isVerified &&
(currentUser.verificationStatus === EVerificationStatus.UNVERIFIED ||
currentUser.verificationStatus === EVerificationStatus.VERIFYING)
) {
return {
success: false,
error:
'Verification required. Please complete wallet verification to comment.',
};
}
try {
const commentId = uuidv4();
const commentMessage: UnsignedCommentMessage = {
type: MessageType.COMMENT,
id: commentId,
postId,
content,
timestamp: Date.now(),
author: currentUser.address,
};
const result = await this.messageService.sendMessage(commentMessage);
if (!result.success) {
return {
success: false,
error: result.error || 'Failed to add comment. Please try again.',
};
}
updateStateFromCache();
const transformedComment = transformComment(
result.message! as CommentMessage
);
if (!transformedComment) {
return {
success: false,
error: 'Failed to transform comment data.',
};
}
return {
success: true,
data: transformedComment,
};
} catch (error) {
console.error('Error creating comment:', error);
return {
success: false,
error: 'Failed to add comment. Please try again.',
};
}
}
async createCell(
params: CellCreationParams,
updateStateFromCache: () => void
): Promise<ActionResult<Cell>> {
const { name, description, icon, currentUser, isAuthenticated } = params;
if (!isAuthenticated || !currentUser) {
return {
success: false,
error:
'Authentication required. You need to verify Ordinal ownership to create a cell.',
};
}
try {
const cellId = uuidv4();
const cellMessage: UnsignedCellMessage = {
type: MessageType.CELL,
id: cellId,
name,
description,
...(icon && { icon }),
timestamp: Date.now(),
author: currentUser.address,
};
const result = await this.messageService.sendMessage(cellMessage);
if (!result.success) {
return {
success: false,
error: result.error || 'Failed to create cell. Please try again.',
};
}
updateStateFromCache();
const transformedCell = transformCell(result.message! as CellMessage);
if (!transformedCell) {
return {
success: false,
error: 'Failed to transform cell data.',
};
}
return {
success: true,
data: transformedCell,
};
} catch (error) {
console.error('Error creating cell:', error);
return {
success: false,
error: 'Failed to create cell. Please try again.',
};
}
}
/* ------------------------------------------------------------------
VOTING
-------------------------------------------------------------------*/
async vote(
params: VoteParams,
updateStateFromCache: () => void
): Promise<ActionResult<boolean>> {
const { targetId, isUpvote, currentUser, isAuthenticated } = params;
if (!isAuthenticated || !currentUser) {
return {
success: false,
error:
'Authentication required. You need to connect your wallet to vote.',
};
}
// Check if user has basic verification or better, or owns ENS/Ordinal
const hasENSOrOrdinal = !!(
currentUser.ensDetails || currentUser.ordinalDetails
);
const isVerified =
currentUser.verificationStatus === EVerificationStatus.VERIFIED_OWNER ||
currentUser.verificationStatus === EVerificationStatus.VERIFIED_BASIC ||
hasENSOrOrdinal;
if (
!isVerified &&
(currentUser.verificationStatus === EVerificationStatus.UNVERIFIED ||
currentUser.verificationStatus === EVerificationStatus.VERIFYING)
) {
return {
success: false,
error:
'Verification required. Please complete wallet verification to vote.',
};
}
try {
const voteId = uuidv4();
const voteMessage: UnsignedVoteMessage = {
type: MessageType.VOTE,
id: voteId,
targetId,
value: isUpvote ? 1 : -1,
timestamp: Date.now(),
author: currentUser.address,
};
const result = await this.messageService.sendMessage(voteMessage);
if (!result.success) {
return {
success: false,
error:
result.error || 'Failed to register your vote. Please try again.',
};
}
updateStateFromCache();
return {
success: true,
data: true,
};
} catch (error) {
console.error('Error voting:', error);
return {
success: false,
error: 'Failed to register your vote. Please try again.',
};
}
}
/* ------------------------------------------------------------------
MODERATION
-------------------------------------------------------------------*/
async moderatePost(
params: PostModerationParams,
updateStateFromCache: () => void
): Promise<ActionResult<boolean>> {
const { cellId, postId, reason, currentUser, isAuthenticated, cellOwner } = params;
if (!isAuthenticated || !currentUser) {
return {
success: false,
error:
'Authentication required. You need to verify Ordinal ownership to moderate posts.',
};
}
if (currentUser.address !== cellOwner) {
return {
success: false,
error: 'Not authorized. Only the cell admin can moderate posts.',
};
}
try {
const modMsg: UnsignedModerateMessage = {
type: MessageType.MODERATE,
id: uuidv4(),
cellId,
targetType: 'post',
targetId: postId,
reason,
timestamp: Date.now(),
author: currentUser.address,
};
const result = await this.messageService.sendMessage(modMsg);
if (!result.success) {
return {
success: false,
error: result.error || 'Failed to moderate post. Please try again.',
};
}
updateStateFromCache();
return {
success: true,
data: true,
};
} catch (error) {
console.error('Error moderating post:', error);
return {
success: false,
error: 'Failed to moderate post. Please try again.',
};
}
}
async moderateComment(
params: CommentModerationParams,
updateStateFromCache: () => void
): Promise<ActionResult<boolean>> {
const { cellId, commentId, reason, currentUser, isAuthenticated, cellOwner } = params;
if (!isAuthenticated || !currentUser) {
return {
success: false,
error:
'Authentication required. You need to verify Ordinal ownership to moderate comments.',
};
}
if (currentUser.address !== cellOwner) {
return {
success: false,
error: 'Not authorized. Only the cell admin can moderate comments.',
};
}
try {
const modMsg: UnsignedModerateMessage = {
type: MessageType.MODERATE,
id: uuidv4(),
cellId,
targetType: 'comment',
targetId: commentId,
reason,
timestamp: Date.now(),
author: currentUser.address,
};
const result = await this.messageService.sendMessage(modMsg);
if (!result.success) {
return {
success: false,
error:
result.error || 'Failed to moderate comment. Please try again.',
};
}
updateStateFromCache();
return {
success: true,
data: true,
};
} catch (error) {
console.error('Error moderating comment:', error);
return {
success: false,
error: 'Failed to moderate comment. Please try again.',
};
}
}
async moderateUser(
params: UserModerationParams,
updateStateFromCache: () => void
): Promise<ActionResult<boolean>> {
const { cellId, userAddress, reason, currentUser, isAuthenticated, cellOwner } = params;
if (!isAuthenticated || !currentUser) {
return {
success: false,
error:
'Authentication required. You need to verify Ordinal ownership to moderate users.',
};
}
if (currentUser.address !== cellOwner) {
return {
success: false,
error: 'Not authorized. Only the cell admin can moderate users.',
};
}
try {
const modMsg: UnsignedModerateMessage = {
type: MessageType.MODERATE,
id: uuidv4(),
cellId,
targetType: 'user',
targetId: userAddress,
reason,
author: currentUser.address,
timestamp: Date.now(),
};
const result = await this.messageService.sendMessage(modMsg);
if (!result.success) {
return {
success: false,
error: result.error || 'Failed to moderate user. Please try again.',
};
}
updateStateFromCache();
return {
success: true,
data: true,
};
} catch (error) {
console.error('Error moderating user:', error);
return {
success: false,
error: 'Failed to moderate user. Please try again.',
};
}
}
}
// Base interface for all actions that require user authentication
interface BaseActionParams {
currentUser: User | null;
isAuthenticated: boolean;
}
// Parameter interfaces for all action methods
interface PostCreationParams extends BaseActionParams {
cellId: string;
title: string;
content: string;
}
interface CommentCreationParams extends BaseActionParams {
postId: string;
content: string;
}
interface CellCreationParams extends BaseActionParams {
name: string;
description: string;
icon?: string;
}
interface VoteParams extends BaseActionParams {
targetId: string;
isUpvote: boolean;
}
interface PostModerationParams extends BaseActionParams {
cellId: string;
postId: string;
reason?: string;
cellOwner: string;
}
interface CommentModerationParams extends BaseActionParams {
cellId: string;
commentId: string;
reason?: string;
cellOwner: string;
}
interface UserModerationParams extends BaseActionParams {
cellId: string;
userAddress: string;
reason?: string;
cellOwner: string;
}

View File

@ -1,4 +1,4 @@
import { RelevanceCalculator } from '../relevance';
import { RelevanceCalculator } from '../RelevanceCalculator';
import { Post, Comment, UserVerificationStatus } from '@/types/forum';
import { User, EVerificationStatus, DisplayPreference } from '@/types/identity';
import { VoteMessage, MessageType } from '@/types/waku';

View File

@ -1,504 +0,0 @@
import { v4 as uuidv4 } from 'uuid';
import {
MessageType,
UnsignedCellMessage,
UnsignedCommentMessage,
UnsignedPostMessage,
UnsignedVoteMessage,
UnsignedModerateMessage,
CellMessage,
CommentMessage,
PostMessage,
} from '@/types/waku';
import { Cell, Comment, Post } from '@/types/forum';
import { EVerificationStatus, User } from '@/types/identity';
import { transformCell, transformComment, transformPost } from './transformers';
import { MessageService, CryptoService } from '@/lib/services';
// Result types for action functions
type ActionResult<T> = {
success: boolean;
data?: T;
error?: string;
};
/* ------------------------------------------------------------------
POST / COMMENT / CELL CREATION
-------------------------------------------------------------------*/
interface PostCreationParams {
cellId: string;
title: string;
content: string;
currentUser: User | null;
isAuthenticated: boolean;
}
export const createPost = async (
{ cellId, title, content, currentUser, isAuthenticated }: PostCreationParams,
updateStateFromCache: () => void
): Promise<ActionResult<Post>> => {
if (!isAuthenticated || !currentUser) {
return {
success: false,
error:
'Authentication required. You need to connect your wallet to post.',
};
}
// Check if user has basic verification or better, or owns ENS/Ordinal
const hasENSOrOrdinal = !!(
currentUser.ensDetails || currentUser.ordinalDetails
);
const isVerified =
currentUser.verificationStatus === EVerificationStatus.VERIFIED_OWNER ||
currentUser.verificationStatus === EVerificationStatus.VERIFIED_BASIC ||
hasENSOrOrdinal;
if (
!isVerified &&
(currentUser.verificationStatus === EVerificationStatus.UNVERIFIED ||
currentUser.verificationStatus === EVerificationStatus.VERIFYING)
) {
return {
success: false,
error:
'Verification required. Please complete wallet verification to post.',
};
}
try {
const postId = uuidv4();
const postMessage: UnsignedPostMessage = {
type: MessageType.POST,
id: postId,
cellId,
title,
content,
timestamp: Date.now(),
author: currentUser.address,
};
const cryptoService = new CryptoService();
const messageService = new MessageService(cryptoService);
const result = await messageService.sendMessage(postMessage);
if (!result.success) {
return {
success: false,
error: result.error || 'Failed to create post. Please try again.',
};
}
updateStateFromCache();
const transformedPost = transformPost(result.message! as PostMessage);
if (!transformedPost) {
return {
success: false,
error: 'Failed to transform post data.',
};
}
return {
success: true,
data: transformedPost,
};
} catch (error) {
console.error('Error creating post:', error);
return {
success: false,
error: 'Failed to create post. Please try again.',
};
}
};
export const createComment = async (
postId: string,
content: string,
currentUser: User | null,
isAuthenticated: boolean,
updateStateFromCache: () => void
): Promise<ActionResult<Comment>> => {
if (!isAuthenticated || !currentUser) {
return {
success: false,
error:
'Authentication required. You need to connect your wallet to comment.',
};
}
// Check if user has basic verification or better, or owns ENS/Ordinal
const hasENSOrOrdinal = !!(
currentUser.ensDetails || currentUser.ordinalDetails
);
const isVerified =
currentUser.verificationStatus === EVerificationStatus.VERIFIED_OWNER ||
currentUser.verificationStatus === EVerificationStatus.VERIFIED_BASIC ||
hasENSOrOrdinal;
if (
!isVerified &&
(currentUser.verificationStatus === EVerificationStatus.UNVERIFIED ||
currentUser.verificationStatus === EVerificationStatus.VERIFYING)
) {
return {
success: false,
error:
'Verification required. Please complete wallet verification to comment.',
};
}
try {
const commentId = uuidv4();
const commentMessage: UnsignedCommentMessage = {
type: MessageType.COMMENT,
id: commentId,
postId,
content,
timestamp: Date.now(),
author: currentUser.address,
};
const cryptoService = new CryptoService();
const messageService = new MessageService(cryptoService);
const result = await messageService.sendMessage(commentMessage);
if (!result.success) {
return {
success: false,
error: result.error || 'Failed to add comment. Please try again.',
};
}
updateStateFromCache();
const transformedComment = transformComment(
result.message! as CommentMessage
);
if (!transformedComment) {
return {
success: false,
error: 'Failed to transform comment data.',
};
}
return {
success: true,
data: transformedComment,
};
} catch (error) {
console.error('Error creating comment:', error);
return {
success: false,
error: 'Failed to add comment. Please try again.',
};
}
};
export const createCell = async (
name: string,
description: string,
icon: string | undefined,
currentUser: User | null,
isAuthenticated: boolean,
updateStateFromCache: () => void
): Promise<ActionResult<Cell>> => {
if (!isAuthenticated || !currentUser) {
return {
success: false,
error:
'Authentication required. You need to verify Ordinal ownership to create a cell.',
};
}
try {
const cellId = uuidv4();
const cellMessage: UnsignedCellMessage = {
type: MessageType.CELL,
id: cellId,
name,
description,
...(icon && { icon }),
timestamp: Date.now(),
author: currentUser.address,
};
const cryptoService = new CryptoService();
const messageService = new MessageService(cryptoService);
const result = await messageService.sendMessage(cellMessage);
if (!result.success) {
return {
success: false,
error: result.error || 'Failed to create cell. Please try again.',
};
}
updateStateFromCache();
const transformedCell = transformCell(result.message! as CellMessage);
if (!transformedCell) {
return {
success: false,
error: 'Failed to transform cell data.',
};
}
return {
success: true,
data: transformedCell,
};
} catch (error) {
console.error('Error creating cell:', error);
return {
success: false,
error: 'Failed to create cell. Please try again.',
};
}
};
/* ------------------------------------------------------------------
VOTING
-------------------------------------------------------------------*/
export const vote = async (
targetId: string,
isUpvote: boolean,
currentUser: User | null,
isAuthenticated: boolean,
updateStateFromCache: () => void
): Promise<ActionResult<boolean>> => {
if (!isAuthenticated || !currentUser) {
return {
success: false,
error:
'Authentication required. You need to connect your wallet to vote.',
};
}
// Check if user has basic verification or better, or owns ENS/Ordinal
const hasENSOrOrdinal = !!(
currentUser.ensDetails || currentUser.ordinalDetails
);
const isVerified =
currentUser.verificationStatus === EVerificationStatus.VERIFIED_OWNER ||
currentUser.verificationStatus === EVerificationStatus.VERIFIED_BASIC ||
hasENSOrOrdinal;
if (
!isVerified &&
(currentUser.verificationStatus === EVerificationStatus.UNVERIFIED ||
currentUser.verificationStatus === EVerificationStatus.VERIFYING)
) {
return {
success: false,
error:
'Verification required. Please complete wallet verification to vote.',
};
}
try {
const voteId = uuidv4();
const voteMessage: UnsignedVoteMessage = {
type: MessageType.VOTE,
id: voteId,
targetId,
value: isUpvote ? 1 : -1,
timestamp: Date.now(),
author: currentUser.address,
};
const cryptoService = new CryptoService();
const messageService = new MessageService(cryptoService);
const result = await messageService.sendMessage(voteMessage);
if (!result.success) {
return {
success: false,
error:
result.error || 'Failed to register your vote. Please try again.',
};
}
updateStateFromCache();
return {
success: true,
data: true,
};
} catch (error) {
console.error('Error voting:', error);
return {
success: false,
error: 'Failed to register your vote. Please try again.',
};
}
};
/* ------------------------------------------------------------------
MODERATION
-------------------------------------------------------------------*/
export const moderatePost = async (
cellId: string,
postId: string,
reason: string | undefined,
currentUser: User | null,
isAuthenticated: boolean,
cellOwner: string,
updateStateFromCache: () => void
): Promise<ActionResult<boolean>> => {
if (!isAuthenticated || !currentUser) {
return {
success: false,
error:
'Authentication required. You need to verify Ordinal ownership to moderate posts.',
};
}
if (currentUser.address !== cellOwner) {
return {
success: false,
error: 'Not authorized. Only the cell admin can moderate posts.',
};
}
try {
const modMsg: UnsignedModerateMessage = {
type: MessageType.MODERATE,
id: uuidv4(),
cellId,
targetType: 'post',
targetId: postId,
reason,
timestamp: Date.now(),
author: currentUser.address,
};
const cryptoService = new CryptoService();
const messageService = new MessageService(cryptoService);
const result = await messageService.sendMessage(modMsg);
if (!result.success) {
return {
success: false,
error: result.error || 'Failed to moderate post. Please try again.',
};
}
updateStateFromCache();
return {
success: true,
data: true,
};
} catch (error) {
console.error('Error moderating post:', error);
return {
success: false,
error: 'Failed to moderate post. Please try again.',
};
}
};
export const moderateComment = async (
cellId: string,
commentId: string,
reason: string | undefined,
currentUser: User | null,
isAuthenticated: boolean,
cellOwner: string,
updateStateFromCache: () => void
): Promise<ActionResult<boolean>> => {
if (!isAuthenticated || !currentUser) {
return {
success: false,
error:
'Authentication required. You need to verify Ordinal ownership to moderate comments.',
};
}
if (currentUser.address !== cellOwner) {
return {
success: false,
error: 'Not authorized. Only the cell admin can moderate comments.',
};
}
try {
const modMsg: UnsignedModerateMessage = {
type: MessageType.MODERATE,
id: uuidv4(),
cellId,
targetType: 'comment',
targetId: commentId,
reason,
timestamp: Date.now(),
author: currentUser.address,
};
const cryptoService = new CryptoService();
const messageService = new MessageService(cryptoService);
const result = await messageService.sendMessage(modMsg);
if (!result.success) {
return {
success: false,
error: result.error || 'Failed to moderate comment. Please try again.',
};
}
updateStateFromCache();
return {
success: true,
data: true,
};
} catch (error) {
console.error('Error moderating comment:', error);
return {
success: false,
error: 'Failed to moderate comment. Please try again.',
};
}
};
export const moderateUser = async (
cellId: string,
userAddress: string,
reason: string | undefined,
currentUser: User | null,
isAuthenticated: boolean,
cellOwner: string,
updateStateFromCache: () => void
): Promise<ActionResult<boolean>> => {
if (!isAuthenticated || !currentUser) {
return {
success: false,
error:
'Authentication required. You need to verify Ordinal ownership to moderate users.',
};
}
if (currentUser.address !== cellOwner) {
return {
success: false,
error: 'Not authorized. Only the cell admin can moderate users.',
};
}
try {
const modMsg: UnsignedModerateMessage = {
type: MessageType.MODERATE,
id: uuidv4(),
cellId,
targetType: 'user',
targetId: userAddress,
reason,
author: currentUser.address,
timestamp: Date.now(),
};
const cryptoService = new CryptoService();
const messageService = new MessageService(cryptoService);
const result = await messageService.sendMessage(modMsg);
if (!result.success) {
return {
success: false,
error: result.error || 'Failed to moderate user. Please try again.',
};
}
updateStateFromCache();
return {
success: true,
data: true,
};
} catch (error) {
console.error('Error moderating user:', error);
return {
success: false,
error: 'Failed to moderate user. Please try again.',
};
}
};

View File

@ -6,7 +6,7 @@ import {
VoteMessage,
} from '@/types/waku';
import messageManager from '@/lib/waku';
import { RelevanceCalculator } from './relevance';
import { RelevanceCalculator } from './RelevanceCalculator';
import { UserVerificationStatus } from '@/types/forum';
import { MessageValidator } from '@/lib/utils/MessageValidator';

View File

@ -13,7 +13,7 @@ import PostCard from '@/components/PostCard';
import FeedSidebar from '@/components/FeedSidebar';
import { useForum } from '@/contexts/useForum';
import { useAuth } from '@/contexts/useAuth';
import { sortPosts, SortOption } from '@/lib/forum/sorting';
import { sortPosts, SortOption } from '@/lib/utils/sorting';
const FeedPage: React.FC = () => {
const { posts, comments, isInitialLoading, isRefreshing, refreshData } =