diff --git a/app/dashboard/page.js b/app/dashboard/page.js index 48090c1..98b2ed3 100644 --- a/app/dashboard/page.js +++ b/app/dashboard/page.js @@ -735,6 +735,29 @@ export default function Dashboard() { } }; + // ── Mark as Solved ──────────────────────────────────────────────────────── + const handleMarkSolved = async (post, comment) => { + if (!user || user.uid !== post.uid) return; + const alreadySolved = post.solved && post.solvedCommentId === comment.createdAt; + try { + await updateDoc(doc(db, "posts", post.id), { + solved: !alreadySolved, + solvedCommentId: alreadySolved ? null : comment.createdAt, + }); + if (!alreadySolved && comment.uid !== user.uid) { + await createNotification({ + toUid: comment.uid, + fromUser: user, + type: "solved", + postId: post.id, + }); + } + } catch (err) { + console.error(err); + setError("Failed to update solved status."); + } + }; + // ── Shared props bundles ────────────────────────────────────────────────── const sharedPostProps = { user, @@ -766,6 +789,7 @@ export default function Dashboard() { onDeleteComment: handleDeleteComment, onVotePoll: handleVotePoll, onToggleCommentReaction: handleToggleCommentReaction, + onMarkSolved: handleMarkSolved, }; const composerProps = { diff --git a/components/Notifications.js b/components/Notifications.js index 26a97ca..b65eb6a 100644 --- a/components/Notifications.js +++ b/components/Notifications.js @@ -135,6 +135,7 @@ const ICONS = { follow: "➕", comment: "💬", comment_edit: "✏️", + solved: "✅", }; function textFor(n) { @@ -147,6 +148,8 @@ function textFor(n) { return <>commented on your post{n.preview ? `: "${n.preview}"` : ""}; case "comment_edit": return <>edited their comment{n.preview ? `: "${n.preview}"` : ""}; + case "solved": + return <>marked your comment as the accepted answer ✅; default: return <>interacted with your content; } diff --git a/components/dashboard/FeedColumn.js b/components/dashboard/FeedColumn.js index c9fb4c5..5889814 100644 --- a/components/dashboard/FeedColumn.js +++ b/components/dashboard/FeedColumn.js @@ -104,6 +104,7 @@ export default function FeedColumn({ onDeleteComment, onVotePoll, onToggleCommentReaction, + onMarkSolved, // Composer props content, setContent, @@ -135,6 +136,7 @@ export default function FeedColumn({ onDeleteComment, onVotePoll, onToggleCommentReaction, + onMarkSolved, }; return ( diff --git a/components/dashboard/PostCard.js b/components/dashboard/PostCard.js index b01db46..4a60c15 100644 --- a/components/dashboard/PostCard.js +++ b/components/dashboard/PostCard.js @@ -63,6 +63,50 @@ const S = { textTransform: "uppercase", whiteSpace: "nowrap", }), + solvedBadge: { + display: "inline-flex", + alignItems: "center", + gap: 4, + padding: "2px 8px", + backgroundColor: "rgba(52,211,153,0.12)", + border: "1px solid rgba(52,211,153,0.4)", + color: "#34d399", + borderRadius: "var(--radius-sm)", + fontSize: "0.7rem", + fontWeight: 600, + textTransform: "uppercase", + whiteSpace: "nowrap", + }, + acceptedCommentWrapper: { + border: "1px solid rgba(52,211,153,0.35)", + borderRadius: "var(--radius-md)", + backgroundColor: "rgba(52,211,153,0.05)", + padding: "8px 10px", + }, + acceptedLabel: { + display: "inline-flex", + alignItems: "center", + gap: 4, + fontSize: "0.72rem", + fontWeight: 600, + color: "#34d399", + marginBottom: 4, + }, + btnAccept: (isAccepted) => ({ + display: "flex", + alignItems: "center", + gap: 3, + padding: "2px 8px", + fontSize: "0.72rem", + fontWeight: 600, + border: isAccepted ? "1px solid rgba(52,211,153,0.6)" : "1px solid var(--border-color)", + borderRadius: "var(--radius-sm)", + backgroundColor: isAccepted ? "rgba(52,211,153,0.12)" : "transparent", + color: isAccepted ? "#34d399" : "var(--text-muted)", + cursor: "pointer", + transition: "all 0.15s", + whiteSpace: "nowrap", + }), postBody: { fontSize: "0.9rem", color: "var(--text-secondary)" }, pollQuestion: { fontSize: "0.95rem", @@ -450,6 +494,7 @@ export default function PostCard({ onDeleteComment, onVotePoll, onToggleCommentReaction, + onMarkSolved, }) { const [openPickerFor, setOpenPickerFor] = useState(null); @@ -495,7 +540,12 @@ export default function PostCard({
- {typeLabel} +
+ {typeLabel} + {type === "question" && post.solved && ( + ✓ Solved + )} +
{post.timestamp?.toDate ? post.timestamp.toDate().toLocaleString(undefined, { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" }) @@ -602,13 +652,24 @@ export default function PostCard({ const commentName = getLiveName(c.uid, c.displayName); const commentKey = `${c.uid}-${c.createdAt}`; const isPickerOpen = openPickerFor === commentKey; + const isAccepted = post.solved && post.solvedCommentId === c.createdAt; + const isPostAuthor = user?.uid === post.uid; + const isQuestion = post.postType === "question"; // extra emojis that already have at least one reaction (show inline) const activeExtra = Object.keys(c.reactions || {}) .filter((e) => !DEFAULT_EMOJIS.includes(e) && (c.reactions[e]?.length || 0) > 0); return ( -
+
+ {/* Accepted answer label */} + {isAccepted && ( +
✓ Accepted Answer
+ )} + {/* Comment header */}
@@ -629,6 +690,15 @@ export default function PostCard({
{new Date(c.createdAt).toLocaleString(undefined, { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" })} {c.edited && (edited)} + {isQuestion && isPostAuthor && !isEditingThis && ( + + )} {isOwner && !isEditingThis && ( <>