wip emoji reactions
This commit is contained in:
parent
48ea06294e
commit
72389136a7
2 changed files with 98 additions and 0 deletions
|
@ -44,10 +44,63 @@ export default function PostItem({ post }: PostItemProps) {
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<PostReactions post={post} />
|
||||||
</article>
|
</article>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface PostReactionsProps {
|
||||||
|
post: Post
|
||||||
|
}
|
||||||
|
|
||||||
|
function PostReactions({ post }: PostReactionsProps) {
|
||||||
|
// State to track user's reactions
|
||||||
|
const [userReactions, setUserReactions] = useState<Set<string>>(new Set())
|
||||||
|
|
||||||
|
// Function to format reaction count
|
||||||
|
const formatCount = (count: number): string => {
|
||||||
|
if (count < 1000) return count.toString()
|
||||||
|
if (count < 10000) return `${(count / 1000).toFixed(1)}K`
|
||||||
|
return `${Math.floor(count / 1000)}K`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to handle reaction click
|
||||||
|
const handleReactionClick = (emoji: string) => {
|
||||||
|
setUserReactions((prev) => {
|
||||||
|
const newReactions = new Set(prev)
|
||||||
|
if (newReactions.has(emoji)) {
|
||||||
|
newReactions.delete(emoji)
|
||||||
|
} else {
|
||||||
|
newReactions.add(emoji)
|
||||||
|
}
|
||||||
|
return newReactions
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-wrap gap-2 mt-3 justify-end">
|
||||||
|
{post.reactions.map((reaction) => {
|
||||||
|
const isSelected = userReactions.has(reaction.emoji)
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={reaction.emoji}
|
||||||
|
onClick={() => handleReactionClick(reaction.emoji)}
|
||||||
|
className={`flex items-center px-2 py-1 rounded-full border ${
|
||||||
|
isSelected ? 'bg-gray-100 border-gray-400' : 'bg-white border-gray-200'
|
||||||
|
} hover:bg-gray-100 transition-colors`}
|
||||||
|
>
|
||||||
|
<span className="mr-1">{reaction.emoji}</span>
|
||||||
|
<span className="text-xs text-gray-600">
|
||||||
|
{formatCount(reaction.count + (isSelected ? 1 : 0))}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
interface PostMediaProps {
|
interface PostMediaProps {
|
||||||
media: PostMedia
|
media: PostMedia
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,18 @@
|
||||||
import { Temporal } from '@js-temporal/polyfill'
|
import { Temporal } from '@js-temporal/polyfill'
|
||||||
import { components } from '../../api/schema.ts'
|
import { components } from '../../api/schema.ts'
|
||||||
|
|
||||||
|
export interface EmojiReaction {
|
||||||
|
emoji: string
|
||||||
|
count: number
|
||||||
|
}
|
||||||
|
|
||||||
export class Post {
|
export class Post {
|
||||||
public readonly postId: string
|
public readonly postId: string
|
||||||
public readonly content: string
|
public readonly content: string
|
||||||
public readonly media: PostMedia[]
|
public readonly media: PostMedia[]
|
||||||
public readonly createdAt: Temporal.Instant
|
public readonly createdAt: Temporal.Instant
|
||||||
public readonly authorName: string
|
public readonly authorName: string
|
||||||
|
public readonly reactions: EmojiReaction[]
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
postId: string,
|
postId: string,
|
||||||
|
@ -14,12 +20,51 @@ export class Post {
|
||||||
media: PostMedia[],
|
media: PostMedia[],
|
||||||
createdAt: string | Temporal.Instant,
|
createdAt: string | Temporal.Instant,
|
||||||
authorName: string,
|
authorName: string,
|
||||||
|
reactions: EmojiReaction[] = [],
|
||||||
) {
|
) {
|
||||||
this.postId = postId
|
this.postId = postId
|
||||||
this.content = content
|
this.content = content
|
||||||
this.media = media
|
this.media = media
|
||||||
this.createdAt = Temporal.Instant.from(createdAt)
|
this.createdAt = Temporal.Instant.from(createdAt)
|
||||||
this.authorName = authorName
|
this.authorName = authorName
|
||||||
|
this.reactions = reactions.length > 0 ? reactions : this.generateRandomReactions()
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateRandomReactions(): EmojiReaction[] {
|
||||||
|
// List of popular emojis
|
||||||
|
const emojis = [
|
||||||
|
'👍',
|
||||||
|
'❤️',
|
||||||
|
'😂',
|
||||||
|
'🎉',
|
||||||
|
'🔥',
|
||||||
|
'👏',
|
||||||
|
'🙏',
|
||||||
|
'💯',
|
||||||
|
'🤔',
|
||||||
|
'😍',
|
||||||
|
'🥰',
|
||||||
|
'😮',
|
||||||
|
'😢',
|
||||||
|
'😡',
|
||||||
|
'🤩',
|
||||||
|
]
|
||||||
|
|
||||||
|
// Randomly select 5 unique emojis
|
||||||
|
const selectedEmojis: string[] = []
|
||||||
|
while (selectedEmojis.length < 5) {
|
||||||
|
const randomIndex = Math.floor(Math.random() * emojis.length)
|
||||||
|
const emoji = emojis[randomIndex]
|
||||||
|
if (!selectedEmojis.includes(emoji!)) {
|
||||||
|
selectedEmojis.push(emoji!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create reaction objects with random counts
|
||||||
|
return selectedEmojis.map((emoji) => ({
|
||||||
|
emoji,
|
||||||
|
count: Math.floor(Math.random() * 50), // Random count between 0 and 49
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
public static fromDto(dto: components['schemas']['PostDto']): Post {
|
public static fromDto(dto: components['schemas']['PostDto']): Post {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue