void
+ isSubmitting?: boolean
+}
+
+export default function NewCommentWidget({
+ onSubmit,
+ isSubmitting = false,
+}: NewCommentWidgetProps) {
+ const { t } = useTranslations()
+ const [content, setContent] = useState('')
+
+ const onContentInput = (value: string) => {
+ setContent(value)
+ }
+
+ const handleSubmit = () => {
+ if (!content.trim()) {
+ return
+ }
+
+ onSubmit(content)
+
+ setContent('')
+ }
+
+ const onInputKeyDown = (e: TextInputKeyDownEvent) => {
+ if (e.key === 'Enter' && e.ctrlKey) {
+ e.preventDefault()
+ handleSubmit()
+ }
+ }
+
+ return (
+
+
+
+
+
+
+
+ )
+}
diff --git a/src/components/NewPostWidget.tsx b/src/app/feed/components/NewPostWidget.tsx
similarity index 95%
rename from src/components/NewPostWidget.tsx
rename to src/app/feed/components/NewPostWidget.tsx
index c943577..e0bd87a 100644
--- a/src/components/NewPostWidget.tsx
+++ b/src/app/feed/components/NewPostWidget.tsx
@@ -1,9 +1,9 @@
import { useState } from 'react'
-import FancyTextEditor, { TextInputKeyDownEvent } from './inputs/FancyTextEditor.tsx'
-import Button from './buttons/Button.tsx'
-import { openFileDialog } from '../utils/openFileDialog.ts'
+import FancyTextEditor, { TextInputKeyDownEvent } from '../../../components/inputs/FancyTextEditor.tsx'
+import Button from '../../../components/buttons/Button.tsx'
+import { openFileDialog } from '../../../utils/openFileDialog.ts'
import makePica from 'pica'
-import { useTranslations } from '../app/i18n/translations.ts'
+import { useTranslations } from '../../i18n/translations.ts'
interface NewPostWidgetProps {
onSubmit: (
diff --git a/src/app/feed/components/PostItem.tsx b/src/app/feed/components/PostItem.tsx
index a0a541c..db766f6 100644
--- a/src/app/feed/components/PostItem.tsx
+++ b/src/app/feed/components/PostItem.tsx
@@ -1,13 +1,24 @@
-import { Post, PostMedia } from '../posts/posts.ts'
+import { PostMedia, PostReaction } from '../posts/posts.ts'
import { useEffect, useState } from 'react'
+import { Link } from 'react-router-dom'
+import { PostInfo } from '../posts/usePostViewModel.ts'
+import { useUserStore } from '../../user/user.ts'
interface PostItemProps {
- post: Post
+ post: PostInfo
+ reactions: PostReaction[]
addReaction: (emoji: string) => void
clearReaction: (emoji: string) => void
+ hideViewButton?: boolean
}
-export default function PostItem({ post, addReaction, clearReaction }: PostItemProps) {
+export default function PostItem({
+ post,
+ reactions,
+ addReaction,
+ clearReaction,
+ hideViewButton = false,
+}: PostItemProps) {
const formattedDate = post.createdAt.toLocaleString('en-US', {
year: 'numeric',
month: 'short',
@@ -31,6 +42,14 @@ export default function PostItem({ post, addReaction, clearReaction }: PostItemP
@{post.authorName}• {formattedDate}
+ {!hideViewButton && (
+ <>
+ {' • '}
+
+ View
+
+ >
+ )}
{post.content}
@@ -43,26 +62,30 @@ export default function PostItem({ post, addReaction, clearReaction }: PostItemP
)
}
interface PostReactionsProps {
- post: Post
+ post: PostInfo
+ reactions: PostReaction[]
addReaction: (emoji: string) => void
clearReaction: (emoji: string) => void
}
-function PostReactions({ post, addReaction, clearReaction }: PostReactionsProps) {
- const reactionMap = new Map(post.reactions.map((r) => [r.emoji, r]))
-
+function PostReactions({ post, reactions, addReaction, clearReaction }: PostReactionsProps) {
+ const username = useUserStore((state) => state.user?.username)
return (
{post.possibleReactions.map((emoji) => {
- const reaction = reactionMap.get(emoji)
- const count = reaction?.count ?? 0
- const didReact = reaction?.didReact ?? false
+ const count = reactions.filter((r) => r.emoji === emoji).length
+ const didReact = reactions.some((r) => r.emoji == emoji && r.authorName == username)
const onClick = () => {
if (didReact) {
clearReaction(emoji)
@@ -99,7 +122,7 @@ function PostReactionButton({ emoji, didReact, onClick, count }: PostReactionBut