mirror of
https://github.com/logos-messaging/OpChan.git
synced 2026-01-04 05:43:10 +00:00
feat: verify users in the feed / display ENS
This commit is contained in:
parent
808820b4f4
commit
4ae89d69bb
@ -4,6 +4,7 @@ import { Link } from 'react-router-dom';
|
|||||||
import { formatDistanceToNow } from 'date-fns';
|
import { formatDistanceToNow } from 'date-fns';
|
||||||
import { Skeleton } from '@/components/ui/skeleton';
|
import { Skeleton } from '@/components/ui/skeleton';
|
||||||
import { MessageSquareText, Newspaper } from 'lucide-react';
|
import { MessageSquareText, Newspaper } from 'lucide-react';
|
||||||
|
import { AuthorDisplay } from './ui/author-display';
|
||||||
|
|
||||||
interface FeedItemBase {
|
interface FeedItemBase {
|
||||||
id: string;
|
id: string;
|
||||||
@ -33,7 +34,7 @@ interface CommentFeedItem extends FeedItemBase {
|
|||||||
type FeedItem = PostFeedItem | CommentFeedItem;
|
type FeedItem = PostFeedItem | CommentFeedItem;
|
||||||
|
|
||||||
const ActivityFeed: React.FC = () => {
|
const ActivityFeed: React.FC = () => {
|
||||||
const { posts, comments, cells, getCellById, isInitialLoading } = useForum();
|
const { posts, comments, cells, getCellById, isInitialLoading, userVerificationStatus } = useForum();
|
||||||
|
|
||||||
const combinedFeed: FeedItem[] = [
|
const combinedFeed: FeedItem[] = [
|
||||||
...posts.map((post): PostFeedItem => ({
|
...posts.map((post): PostFeedItem => ({
|
||||||
@ -66,7 +67,6 @@ const ActivityFeed: React.FC = () => {
|
|||||||
|
|
||||||
const renderFeedItem = (item: FeedItem) => {
|
const renderFeedItem = (item: FeedItem) => {
|
||||||
const cell = item.cellId ? getCellById(item.cellId) : undefined;
|
const cell = item.cellId ? getCellById(item.cellId) : undefined;
|
||||||
const ownerShort = `${item.ownerAddress.slice(0, 5)}...${item.ownerAddress.slice(-4)}`;
|
|
||||||
const timeAgo = formatDistanceToNow(new Date(item.timestamp), { addSuffix: true });
|
const timeAgo = formatDistanceToNow(new Date(item.timestamp), { addSuffix: true });
|
||||||
|
|
||||||
const linkTarget = item.type === 'post' ? `/post/${item.postId}` : `/post/${item.postId}#comment-${item.id}`;
|
const linkTarget = item.type === 'post' ? `/post/${item.postId}` : `/post/${item.postId}#comment-${item.id}`;
|
||||||
@ -83,7 +83,12 @@ const ActivityFeed: React.FC = () => {
|
|||||||
{item.type === 'post' ? item.title : `Comment on: ${posts.find(p => p.id === item.postId)?.title || 'post'}`}
|
{item.type === 'post' ? item.title : `Comment on: ${posts.find(p => p.id === item.postId)?.title || 'post'}`}
|
||||||
</span>
|
</span>
|
||||||
by
|
by
|
||||||
<span className="font-medium text-foreground/70 mx-1">{ownerShort}</span>
|
<AuthorDisplay
|
||||||
|
address={item.ownerAddress}
|
||||||
|
userVerificationStatus={userVerificationStatus}
|
||||||
|
className="font-medium text-foreground/70 mx-1"
|
||||||
|
showBadge={false}
|
||||||
|
/>
|
||||||
{cell && (
|
{cell && (
|
||||||
<>
|
<>
|
||||||
in
|
in
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { Post } from '@/types';
|
|||||||
import { useForum } from '@/contexts/useForum';
|
import { useForum } from '@/contexts/useForum';
|
||||||
import { useAuth } from '@/contexts/useAuth';
|
import { useAuth } from '@/contexts/useAuth';
|
||||||
import { RelevanceIndicator } from '@/components/ui/relevance-indicator';
|
import { RelevanceIndicator } from '@/components/ui/relevance-indicator';
|
||||||
|
import { AuthorDisplay } from '@/components/ui/author-display';
|
||||||
|
|
||||||
interface PostCardProps {
|
interface PostCardProps {
|
||||||
post: Post;
|
post: Post;
|
||||||
@ -13,7 +14,7 @@ interface PostCardProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const PostCard: React.FC<PostCardProps> = ({ post, commentCount = 0 }) => {
|
const PostCard: React.FC<PostCardProps> = ({ post, commentCount = 0 }) => {
|
||||||
const { getCellById, votePost, isVoting } = useForum();
|
const { getCellById, votePost, isVoting, userVerificationStatus } = useForum();
|
||||||
const { isAuthenticated, currentUser } = useAuth();
|
const { isAuthenticated, currentUser } = useAuth();
|
||||||
|
|
||||||
const cell = getCellById(post.cellId);
|
const cell = getCellById(post.cellId);
|
||||||
@ -80,7 +81,13 @@ const PostCard: React.FC<PostCardProps> = ({ post, commentCount = 0 }) => {
|
|||||||
<div className="flex items-center text-xs text-cyber-neutral mb-2 space-x-2">
|
<div className="flex items-center text-xs text-cyber-neutral mb-2 space-x-2">
|
||||||
<span className="font-medium text-cyber-accent">r/{cellName}</span>
|
<span className="font-medium text-cyber-accent">r/{cellName}</span>
|
||||||
<span>•</span>
|
<span>•</span>
|
||||||
<span>Posted by u/{post.authorAddress.slice(0, 6)}...{post.authorAddress.slice(-4)}</span>
|
<span>Posted by u/</span>
|
||||||
|
<AuthorDisplay
|
||||||
|
address={post.authorAddress}
|
||||||
|
userVerificationStatus={userVerificationStatus}
|
||||||
|
className="text-xs"
|
||||||
|
showBadge={false}
|
||||||
|
/>
|
||||||
<span>•</span>
|
<span>•</span>
|
||||||
<span>{formatDistanceToNow(new Date(post.timestamp), { addSuffix: true })}</span>
|
<span>{formatDistanceToNow(new Date(post.timestamp), { addSuffix: true })}</span>
|
||||||
{post.relevanceScore !== undefined && (
|
{post.relevanceScore !== undefined && (
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import { Comment } from '@/types';
|
|||||||
import { CypherImage } from './ui/CypherImage';
|
import { CypherImage } from './ui/CypherImage';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { RelevanceIndicator } from './ui/relevance-indicator';
|
import { RelevanceIndicator } from './ui/relevance-indicator';
|
||||||
|
import { AuthorDisplay } from './ui/author-display';
|
||||||
|
|
||||||
const PostDetail = () => {
|
const PostDetail = () => {
|
||||||
const { postId } = useParams<{ postId: string }>();
|
const { postId } = useParams<{ postId: string }>();
|
||||||
@ -28,7 +29,8 @@ const PostDetail = () => {
|
|||||||
isRefreshing,
|
isRefreshing,
|
||||||
refreshData,
|
refreshData,
|
||||||
moderateComment,
|
moderateComment,
|
||||||
moderateUser
|
moderateUser,
|
||||||
|
userVerificationStatus
|
||||||
} = useForum();
|
} = useForum();
|
||||||
const { currentUser, isAuthenticated, verificationStatus } = useAuth();
|
const { currentUser, isAuthenticated, verificationStatus } = useAuth();
|
||||||
const [newComment, setNewComment] = useState('');
|
const [newComment, setNewComment] = useState('');
|
||||||
@ -163,9 +165,11 @@ const PostDetail = () => {
|
|||||||
<MessageCircle className="w-3 h-3 mr-1" />
|
<MessageCircle className="w-3 h-3 mr-1" />
|
||||||
{postComments.length} {postComments.length === 1 ? 'comment' : 'comments'}
|
{postComments.length} {postComments.length === 1 ? 'comment' : 'comments'}
|
||||||
</span>
|
</span>
|
||||||
<span className="truncate max-w-[150px]">
|
<AuthorDisplay
|
||||||
{post.authorAddress.slice(0, 6)}...{post.authorAddress.slice(-4)}
|
address={post.authorAddress}
|
||||||
</span>
|
userVerificationStatus={userVerificationStatus}
|
||||||
|
className="truncate max-w-[150px]"
|
||||||
|
/>
|
||||||
{post.relevanceScore !== undefined && (
|
{post.relevanceScore !== undefined && (
|
||||||
<RelevanceIndicator
|
<RelevanceIndicator
|
||||||
score={post.relevanceScore}
|
score={post.relevanceScore}
|
||||||
@ -258,9 +262,11 @@ const PostDetail = () => {
|
|||||||
alt={comment.authorAddress.slice(0, 6)}
|
alt={comment.authorAddress.slice(0, 6)}
|
||||||
className="rounded-sm w-5 h-5 bg-secondary"
|
className="rounded-sm w-5 h-5 bg-secondary"
|
||||||
/>
|
/>
|
||||||
<span className="text-xs text-muted-foreground">
|
<AuthorDisplay
|
||||||
{comment.authorAddress.slice(0, 6)}...{comment.authorAddress.slice(-4)}
|
address={comment.authorAddress}
|
||||||
</span>
|
userVerificationStatus={userVerificationStatus}
|
||||||
|
className="text-xs"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{comment.relevanceScore !== undefined && (
|
{comment.relevanceScore !== undefined && (
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import { ArrowLeft, MessageSquare, MessageCircle, ArrowUp, ArrowDown, Clock, Ref
|
|||||||
import { formatDistanceToNow } from 'date-fns';
|
import { formatDistanceToNow } from 'date-fns';
|
||||||
import { CypherImage } from './ui/CypherImage';
|
import { CypherImage } from './ui/CypherImage';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
|
import { AuthorDisplay } from './ui/author-display';
|
||||||
|
|
||||||
const PostList = () => {
|
const PostList = () => {
|
||||||
const { cellId } = useParams<{ cellId: string }>();
|
const { cellId } = useParams<{ cellId: string }>();
|
||||||
@ -26,7 +27,8 @@ const PostList = () => {
|
|||||||
isVoting,
|
isVoting,
|
||||||
posts,
|
posts,
|
||||||
moderatePost,
|
moderatePost,
|
||||||
moderateUser
|
moderateUser,
|
||||||
|
userVerificationStatus
|
||||||
} = useForum();
|
} = useForum();
|
||||||
const { isAuthenticated, currentUser, verificationStatus } = useAuth();
|
const { isAuthenticated, currentUser, verificationStatus } = useAuth();
|
||||||
const [newPostTitle, setNewPostTitle] = useState('');
|
const [newPostTitle, setNewPostTitle] = useState('');
|
||||||
@ -258,7 +260,13 @@ const PostList = () => {
|
|||||||
<p className="line-clamp-2 text-sm mb-3">{post.content}</p>
|
<p className="line-clamp-2 text-sm mb-3">{post.content}</p>
|
||||||
<div className="flex items-center gap-4 text-xs text-cyber-neutral">
|
<div className="flex items-center gap-4 text-xs text-cyber-neutral">
|
||||||
<span>{formatDistanceToNow(post.timestamp, { addSuffix: true })}</span>
|
<span>{formatDistanceToNow(post.timestamp, { addSuffix: true })}</span>
|
||||||
<span>by {post.authorAddress.slice(0, 6)}...{post.authorAddress.slice(-4)}</span>
|
<span>by </span>
|
||||||
|
<AuthorDisplay
|
||||||
|
address={post.authorAddress}
|
||||||
|
userVerificationStatus={userVerificationStatus}
|
||||||
|
className="text-xs"
|
||||||
|
showBadge={false}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
{isCellAdmin && !post.moderated && (
|
{isCellAdmin && !post.moderated && (
|
||||||
|
|||||||
59
src/components/ui/author-display.tsx
Normal file
59
src/components/ui/author-display.tsx
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Badge } from '@/components/ui/badge';
|
||||||
|
import { Shield, Crown } from 'lucide-react';
|
||||||
|
import { UserVerificationStatus } from '@/lib/forum/types';
|
||||||
|
|
||||||
|
interface AuthorDisplayProps {
|
||||||
|
address: string;
|
||||||
|
userVerificationStatus?: UserVerificationStatus;
|
||||||
|
className?: string;
|
||||||
|
showBadge?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AuthorDisplay({
|
||||||
|
address,
|
||||||
|
userVerificationStatus,
|
||||||
|
className = "",
|
||||||
|
showBadge = true
|
||||||
|
}: AuthorDisplayProps) {
|
||||||
|
const userStatus = userVerificationStatus?.[address];
|
||||||
|
const isVerified = userStatus?.isVerified || false;
|
||||||
|
const hasENS = userStatus?.hasENS || false;
|
||||||
|
const hasOrdinal = userStatus?.hasOrdinal || false;
|
||||||
|
|
||||||
|
// Get ENS name from user verification status if available
|
||||||
|
const ensName = userStatus?.ensName;
|
||||||
|
const displayName = ensName || `${address.slice(0, 6)}...${address.slice(-4)}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={`flex items-center gap-1.5 ${className}`}>
|
||||||
|
<span className="text-xs text-muted-foreground">
|
||||||
|
{displayName}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{showBadge && isVerified && (
|
||||||
|
<Badge
|
||||||
|
variant="secondary"
|
||||||
|
className="text-xs px-1.5 py-0.5 h-auto bg-green-900/20 border-green-500/30 text-green-400"
|
||||||
|
>
|
||||||
|
{hasENS ? (
|
||||||
|
<>
|
||||||
|
<Crown className="w-3 h-3 mr-1" />
|
||||||
|
ENS
|
||||||
|
</>
|
||||||
|
) : hasOrdinal ? (
|
||||||
|
<>
|
||||||
|
<Shield className="w-3 h-3 mr-1" />
|
||||||
|
Ordinal
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Shield className="w-3 h-3 mr-1" />
|
||||||
|
Verified
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -18,13 +18,16 @@ import {
|
|||||||
} from '@/lib/waku/network';
|
} from '@/lib/waku/network';
|
||||||
import messageManager from '@/lib/waku';
|
import messageManager from '@/lib/waku';
|
||||||
import { getDataFromCache } from '@/lib/forum/transformers';
|
import { getDataFromCache } from '@/lib/forum/transformers';
|
||||||
import { RelevanceCalculator, UserVerificationStatus } from '@/lib/forum/relevance';
|
import { RelevanceCalculator } from '@/lib/forum/relevance';
|
||||||
|
import { UserVerificationStatus } from '@/lib/forum/types';
|
||||||
import { AuthService } from '@/lib/identity/services/AuthService';
|
import { AuthService } from '@/lib/identity/services/AuthService';
|
||||||
|
|
||||||
interface ForumContextType {
|
interface ForumContextType {
|
||||||
cells: Cell[];
|
cells: Cell[];
|
||||||
posts: Post[];
|
posts: Post[];
|
||||||
comments: Comment[];
|
comments: Comment[];
|
||||||
|
// User verification status for display
|
||||||
|
userVerificationStatus: UserVerificationStatus;
|
||||||
// Granular loading states
|
// Granular loading states
|
||||||
isInitialLoading: boolean;
|
isInitialLoading: boolean;
|
||||||
isPostingCell: boolean;
|
isPostingCell: boolean;
|
||||||
@ -80,6 +83,7 @@ export function ForumProvider({ children }: { children: React.ReactNode }) {
|
|||||||
const [isRefreshing, setIsRefreshing] = useState(false);
|
const [isRefreshing, setIsRefreshing] = useState(false);
|
||||||
const [isNetworkConnected, setIsNetworkConnected] = useState(false);
|
const [isNetworkConnected, setIsNetworkConnected] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
const [userVerificationStatus, setUserVerificationStatus] = useState<UserVerificationStatus>({});
|
||||||
|
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const { currentUser, isAuthenticated } = useAuth();
|
const { currentUser, isAuthenticated } = useAuth();
|
||||||
@ -117,11 +121,27 @@ export function ForumProvider({ children }: { children: React.ReactNode }) {
|
|||||||
|
|
||||||
// Create user objects for verification status
|
// Create user objects for verification status
|
||||||
Array.from(userAddresses).forEach(address => {
|
Array.from(userAddresses).forEach(address => {
|
||||||
allUsers.push({
|
// Check if this address matches the current user's address
|
||||||
address,
|
if (currentUser && currentUser.address === address) {
|
||||||
walletType: 'bitcoin', // Default, will be updated if we have more info
|
// Use the current user's actual verification status
|
||||||
verificationStatus: 'unverified'
|
allUsers.push({
|
||||||
});
|
address,
|
||||||
|
walletType: currentUser.walletType,
|
||||||
|
verificationStatus: currentUser.verificationStatus,
|
||||||
|
ensOwnership: currentUser.ensOwnership,
|
||||||
|
ensName: currentUser.ensName,
|
||||||
|
ensAvatar: currentUser.ensAvatar,
|
||||||
|
ordinalOwnership: currentUser.ordinalOwnership,
|
||||||
|
lastChecked: currentUser.lastChecked
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Create generic user object for other addresses
|
||||||
|
allUsers.push({
|
||||||
|
address,
|
||||||
|
walletType: 'bitcoin', // Default, will be updated if we have more info
|
||||||
|
verificationStatus: 'unverified'
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const userVerificationStatus = relevanceCalculator.buildUserVerificationStatus(allUsers);
|
const userVerificationStatus = relevanceCalculator.buildUserVerificationStatus(allUsers);
|
||||||
@ -132,7 +152,8 @@ export function ForumProvider({ children }: { children: React.ReactNode }) {
|
|||||||
setCells(cells);
|
setCells(cells);
|
||||||
setPosts(posts);
|
setPosts(posts);
|
||||||
setComments(comments);
|
setComments(comments);
|
||||||
}, [authService, isAuthenticated]);
|
setUserVerificationStatus(userVerificationStatus);
|
||||||
|
}, [authService, isAuthenticated, currentUser]);
|
||||||
|
|
||||||
const handleRefreshData = async () => {
|
const handleRefreshData = async () => {
|
||||||
setIsRefreshing(true);
|
setIsRefreshing(true);
|
||||||
@ -327,6 +348,7 @@ export function ForumProvider({ children }: { children: React.ReactNode }) {
|
|||||||
cells,
|
cells,
|
||||||
posts,
|
posts,
|
||||||
comments,
|
comments,
|
||||||
|
userVerificationStatus,
|
||||||
isInitialLoading,
|
isInitialLoading,
|
||||||
isPostingCell,
|
isPostingCell,
|
||||||
isPostingPost,
|
isPostingPost,
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
import { RelevanceCalculator } from './relevance';
|
import { RelevanceCalculator } from './relevance';
|
||||||
import { Post, Comment, Cell, User } from '@/types';
|
import { Post, Comment, Cell, User } from '@/types';
|
||||||
import { MessageType, VoteMessage } from '@/lib/waku/types';
|
import { VoteMessage, MessageType } from '@/lib/waku/types';
|
||||||
import { expect, describe, beforeEach, it } from 'vitest';
|
import { expect, describe, beforeEach, it } from 'vitest';
|
||||||
import { UserVerificationStatus } from './types';
|
import { UserVerificationStatus } from './types';
|
||||||
|
|
||||||
describe('RelevanceCalculator', () => {
|
describe('RelevanceCalculator', () => {
|
||||||
let calculator: RelevanceCalculator;
|
let calculator: RelevanceCalculator;
|
||||||
let mockUserVerificationStatus: UserVerificationStatus;
|
let mockUserVerificationStatus: any;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
calculator = new RelevanceCalculator();
|
calculator = new RelevanceCalculator();
|
||||||
@ -55,6 +55,46 @@ describe('RelevanceCalculator', () => {
|
|||||||
expect(result.details.authorVerificationBonus).toBeGreaterThan(0);
|
expect(result.details.authorVerificationBonus).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should correctly identify verified users with ENS ownership', () => {
|
||||||
|
const verifiedUser: User = {
|
||||||
|
address: 'user1',
|
||||||
|
walletType: 'ethereum',
|
||||||
|
verificationStatus: 'verified-owner',
|
||||||
|
ensOwnership: true,
|
||||||
|
ensName: 'test.eth',
|
||||||
|
lastChecked: Date.now()
|
||||||
|
};
|
||||||
|
|
||||||
|
const isVerified = calculator.isUserVerified(verifiedUser);
|
||||||
|
expect(isVerified).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should correctly identify verified users with Ordinal ownership', () => {
|
||||||
|
const verifiedUser: User = {
|
||||||
|
address: 'user3',
|
||||||
|
walletType: 'bitcoin',
|
||||||
|
verificationStatus: 'verified-owner',
|
||||||
|
ordinalOwnership: true,
|
||||||
|
lastChecked: Date.now()
|
||||||
|
};
|
||||||
|
|
||||||
|
const isVerified = calculator.isUserVerified(verifiedUser);
|
||||||
|
expect(isVerified).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should correctly identify unverified users', () => {
|
||||||
|
const unverifiedUser: User = {
|
||||||
|
address: 'user2',
|
||||||
|
walletType: 'ethereum',
|
||||||
|
verificationStatus: 'unverified',
|
||||||
|
ensOwnership: false,
|
||||||
|
lastChecked: Date.now()
|
||||||
|
};
|
||||||
|
|
||||||
|
const isVerified = calculator.isUserVerified(unverifiedUser);
|
||||||
|
expect(isVerified).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
it('should apply moderation penalty', () => {
|
it('should apply moderation penalty', () => {
|
||||||
const post: Post = {
|
const post: Post = {
|
||||||
id: '1',
|
id: '1',
|
||||||
@ -138,4 +178,36 @@ describe('RelevanceCalculator', () => {
|
|||||||
expect(recentResult.score).toBeGreaterThan(oldResult.score);
|
expect(recentResult.score).toBeGreaterThan(oldResult.score);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('buildUserVerificationStatus', () => {
|
||||||
|
it('should correctly build verification status map from users array', () => {
|
||||||
|
const users: User[] = [
|
||||||
|
{
|
||||||
|
address: 'user1',
|
||||||
|
walletType: 'ethereum',
|
||||||
|
verificationStatus: 'verified-owner',
|
||||||
|
ensOwnership: true,
|
||||||
|
ensName: 'test.eth',
|
||||||
|
lastChecked: Date.now()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
address: 'user2',
|
||||||
|
walletType: 'bitcoin',
|
||||||
|
verificationStatus: 'unverified',
|
||||||
|
ordinalOwnership: false,
|
||||||
|
lastChecked: Date.now()
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const status = calculator.buildUserVerificationStatus(users);
|
||||||
|
|
||||||
|
expect(status['user1'].isVerified).toBe(true);
|
||||||
|
expect(status['user1'].hasENS).toBe(true);
|
||||||
|
expect(status['user1'].hasOrdinal).toBe(false);
|
||||||
|
|
||||||
|
expect(status['user2'].isVerified).toBe(false);
|
||||||
|
expect(status['user2'].hasENS).toBe(false);
|
||||||
|
expect(status['user2'].hasOrdinal).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -217,7 +217,8 @@ export class RelevanceCalculator {
|
|||||||
status[user.address] = {
|
status[user.address] = {
|
||||||
isVerified: this.isUserVerified(user),
|
isVerified: this.isUserVerified(user),
|
||||||
hasENS: !!user.ensOwnership,
|
hasENS: !!user.ensOwnership,
|
||||||
hasOrdinal: !!user.ordinalOwnership
|
hasOrdinal: !!user.ordinalOwnership,
|
||||||
|
ensName: user.ensName
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -21,5 +21,6 @@ export interface RelevanceScoreDetails {
|
|||||||
isVerified: boolean;
|
isVerified: boolean;
|
||||||
hasENS: boolean;
|
hasENS: boolean;
|
||||||
hasOrdinal: boolean;
|
hasOrdinal: boolean;
|
||||||
|
ensName?: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user