diff --git a/src/views/Profile.tsx b/src/views/Profile.tsx index fa9ddad..adc6455 100644 --- a/src/views/Profile.tsx +++ b/src/views/Profile.tsx @@ -13,21 +13,23 @@ import { Loader2, MessageSquareText, PencilLine, - Reply, Trash2, UserRound, XCircle, } from "lucide-react"; +import BlogThumbnail from "@/components/BlogThumbnail"; import Markdown from "@/components/Markdown"; import { Helmet } from "@/lib/helmet"; import { Link, Navigate } from "@/lib/router"; import { useAuth } from "@/contexts/AuthContext"; import { api } from "@/lib/api"; import { blogPostPath } from "@/lib/blog-routes"; +import { apiBaseUrl, toAbsoluteUrl } from "@/lib/site"; import type * as Types from "@/lib/types"; import { formatJalali, formatNumberPersian, + getBlogCardImageUrl, resolveErrorMessage, toPersianDigits, } from "@/lib/utils"; @@ -41,7 +43,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@ import { Textarea } from "@/components/ui/textarea"; type EventTab = "confirmed" | "pending" | "cancelled"; -type BlogTab = "liked" | "saved" | "comments" | "replies"; +type BlogTab = "liked" | "saved" | "comments"; function InfoRow({ label, value }: { label: string; value: ReactNode }) { return ( @@ -144,7 +146,12 @@ export default function Profile() { staleTime: 7 * 24 * 60 * 60 * 1000, }); - const { data: blogActivity } = useQuery({ + const { + data: blogActivity, + isLoading: blogActivityLoading, + isError: blogActivityError, + refetch: refetchBlogActivity, + } = useQuery({ queryKey: ["my-blog-activity"], queryFn: () => api.getMyBlogActivity(), enabled: isAuthenticated, @@ -261,12 +268,20 @@ export default function Profile() { ? pendingRegistrations : canceledRegistrations; + const blogCommentActivity = useMemo( + () => + [...(blogActivity?.comments ?? []), ...(blogActivity?.replies ?? [])].sort( + (left, right) => new Date(right.created_at).getTime() - new Date(left.created_at).getTime(), + ), + [blogActivity?.comments, blogActivity?.replies], + ); + const blogCounts = { liked: blogActivity?.liked_posts.length ?? 0, saved: blogActivity?.saved_posts.length ?? 0, - comments: blogActivity?.comments.length ?? 0, - replies: blogActivity?.replies.length ?? 0, + comments: blogCommentActivity.length, }; + const showBlogActivityTabs = !blogActivityLoading && !blogActivityError; const pageTitle = `پروفایل ${fullName} | انجمن علمی مهندسی کامپیوتر`; const pageDescription = `داشبورد حساب ${fullName} در انجمن علمی مهندسی کامپیوتر.`; @@ -410,10 +425,21 @@ export default function Profile() { const renderPostRow = (post: Types.PostListSchema) => (
- - {post.title} - -

{post.excerpt || "بدون خلاصه"}

+
+ + + +
+ + {post.title} + +

{post.excerpt || "بدون خلاصه"}

+
+
); @@ -450,7 +476,7 @@ export default function Profile() {
{(loading || fetching) && !me ? ( -
+
در حال بارگذاری پروفایل...
@@ -650,32 +676,46 @@ export default function Profile() {
- {blogTab === "liked" ? ( + {blogActivityLoading ? ( +
+ + در حال دریافت فعالیت‌های بلاگ... +
+ ) : null} + {blogActivityError ? ( +
+ دریافت فعالیت‌های بلاگ ناموفق بود. + +
+ ) : null} + {showBlogActivityTabs && blogTab === "liked" ? ( blogActivity?.liked_posts.length ? blogActivity.liked_posts.map(renderPostRow) : ( ) ) : null} - {blogTab === "saved" ? ( + {showBlogActivityTabs && blogTab === "saved" ? ( blogActivity?.saved_posts.length ? blogActivity.saved_posts.map(renderPostRow) : ( ) ) : null} - {blogTab === "comments" ? ( - blogActivity?.comments.length ? blogActivity.comments.map(renderCommentRow) : ( + {showBlogActivityTabs && blogTab === "comments" ? ( + blogCommentActivity.length ? blogCommentActivity.map(renderCommentRow) : ( ) ) : null} - {blogTab === "replies" ? ( - blogActivity?.replies.length ? blogActivity.replies.map(renderCommentRow) : ( - - ) - ) : null}
setBlogTab(value as BlogTab)} /> setBlogTab(value as BlogTab)} /> - setBlogTab(value as BlogTab)} /> - setBlogTab(value as BlogTab)} /> + setBlogTab(value as BlogTab)} />