diff options
Diffstat (limited to 'frontend/src/components/ArticleItem.tsx')
| -rw-r--r-- | frontend/src/components/ArticleItem.tsx | 38 |
1 files changed, 13 insertions, 25 deletions
diff --git a/frontend/src/components/ArticleItem.tsx b/frontend/src/components/ArticleItem.tsx index faa86fe..4942518 100644 --- a/frontend/src/components/ArticleItem.tsx +++ b/frontend/src/components/ArticleItem.tsx @@ -1,6 +1,5 @@ import { faCheck, faCircle } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { useOptimistic } from "react"; import { useMutation } from "urql"; import type { GetReadArticlesQuery, @@ -18,27 +17,19 @@ type Article = NonNullable< interface Props { article: Article; + onReadChange?: (articleId: string, isRead: boolean) => void; } -export function ArticleItem({ article }: Props) { +export function ArticleItem({ article, onReadChange }: Props) { const [, markArticleRead] = useMutation(MarkArticleReadDocument); const [, markArticleUnread] = useMutation(MarkArticleUnreadDocument); - const [optimisticArticle, setOptimisticArticle] = useOptimistic( - article, - (currentArticle, newReadState: boolean) => ({ - ...currentArticle, - isRead: newReadState, - }), - ); - const handleToggleRead = async ( articleId: string, isCurrentlyRead: boolean, ) => { const newReadState = !isCurrentlyRead; - - setOptimisticArticle(newReadState); + onReadChange?.(articleId, newReadState); if (isCurrentlyRead) { await markArticleUnread({ id: articleId }); @@ -50,9 +41,8 @@ export function ArticleItem({ article }: Props) { const handleArticleClick = async (article: Article) => { // Open article in new tab and mark as read if it's unread window.open(article.url, "_blank", "noreferrer"); - if (!optimisticArticle.isRead) { - setOptimisticArticle(true); - + if (!article.isRead) { + onReadChange?.(article.id, true); await markArticleRead({ id: article.id }); } }; @@ -60,38 +50,36 @@ export function ArticleItem({ article }: Props) { return ( <div className={`group flex items-center gap-3 rounded-lg border p-3 hover:bg-gray-50 ${ - optimisticArticle.isRead + article.isRead ? "border-gray-200 bg-white" : "border-blue-200 bg-blue-50" }`} > <button type="button" - onClick={() => handleToggleRead(article.id, optimisticArticle.isRead)} + onClick={() => handleToggleRead(article.id, article.isRead)} className={`flex-shrink-0 rounded p-1 transition-colors ${ - optimisticArticle.isRead + article.isRead ? "text-gray-400 hover:text-gray-600" : "text-blue-600 hover:text-blue-700" }`} - title={optimisticArticle.isRead ? "Mark as unread" : "Mark as read"} + title={article.isRead ? "Mark as unread" : "Mark as read"} > <FontAwesomeIcon - icon={optimisticArticle.isRead ? faCheck : faCircle} + icon={article.isRead ? faCheck : faCircle} className="w-4 h-4" /> </button> <div className="flex-1 min-w-0"> <button type="button" - onClick={() => handleArticleClick(optimisticArticle)} + onClick={() => handleArticleClick(article)} className={`text-left w-full group-hover:text-blue-600 transition-colors ${ - optimisticArticle.isRead - ? "text-gray-700" - : "text-gray-900 font-medium" + article.isRead ? "text-gray-700" : "text-gray-900 font-medium" }`} > <div className="flex items-center gap-2 break-words"> - {optimisticArticle.title} + {article.title} </div> </button> </div> |
