deletion reason and email for soft deleted forum posts and comments by admin

This commit is contained in:
jackiettran
2025-11-20 18:08:30 -05:00
parent b2f18d77f6
commit f7767dfd13
10 changed files with 911 additions and 21 deletions

View File

@@ -23,6 +23,7 @@ const ForumPostDetail: React.FC = () => {
type: 'deletePost' | 'deleteComment' | 'restorePost' | 'restoreComment' | 'closePost' | 'reopenPost';
id?: string;
} | null>(null);
const [deletionReason, setDeletionReason] = useState('');
// Read filter from URL query param
const filter = searchParams.get('filter') || 'active';
@@ -174,13 +175,19 @@ const ForumPostDetail: React.FC = () => {
const confirmAdminAction = async () => {
if (!adminAction) return;
// Validate deletion reason for delete actions
if ((adminAction.type === 'deletePost' || adminAction.type === 'deleteComment') && !deletionReason.trim()) {
alert('Please provide a reason for deletion');
return;
}
try {
setActionLoading(true);
setShowAdminModal(false);
switch (adminAction.type) {
case 'deletePost':
await forumAPI.adminDeletePost(id!);
await forumAPI.adminDeletePost(id!, deletionReason.trim());
break;
case 'restorePost':
await forumAPI.adminRestorePost(id!);
@@ -192,7 +199,7 @@ const ForumPostDetail: React.FC = () => {
await forumAPI.adminReopenPost(id!);
break;
case 'deleteComment':
await forumAPI.adminDeleteComment(adminAction.id!);
await forumAPI.adminDeleteComment(adminAction.id!, deletionReason.trim());
break;
case 'restoreComment':
await forumAPI.adminRestoreComment(adminAction.id!);
@@ -205,12 +212,14 @@ const ForumPostDetail: React.FC = () => {
} finally {
setActionLoading(false);
setAdminAction(null);
setDeletionReason('');
}
};
const cancelAdminAction = () => {
setShowAdminModal(false);
setAdminAction(null);
setDeletionReason('');
};
const formatDate = (dateString: string) => {
@@ -520,7 +529,26 @@ const ForumPostDetail: React.FC = () => {
</div>
<div className="modal-body">
{adminAction?.type === 'deletePost' && (
<p>Are you sure you want to delete this post? It will be deleted and hidden from regular users but can be restored later.</p>
<>
<p>Are you sure you want to delete this post? It will be deleted and hidden from regular users but can be restored later.</p>
<div className="mb-3">
<label htmlFor="deletionReason" className="form-label">
<strong>Reason for deletion <span className="text-danger">*</span></strong>
</label>
<textarea
id="deletionReason"
className="form-control"
rows={4}
placeholder="Please explain why this post is being deleted. The author will receive this reason via email."
value={deletionReason}
onChange={(e) => setDeletionReason(e.target.value)}
required
/>
<small className="text-muted">
This reason will be sent to the post author via email.
</small>
</div>
</>
)}
{adminAction?.type === 'restorePost' && (
<p>Are you sure you want to restore this post? It will become visible to all users again.</p>
@@ -532,7 +560,26 @@ const ForumPostDetail: React.FC = () => {
<p>Are you sure you want to reopen this discussion? Users will be able to add comments again.</p>
)}
{adminAction?.type === 'deleteComment' && (
<p>Are you sure you want to delete this comment? It will be deleted and hidden from regular users but can be restored later.</p>
<>
<p>Are you sure you want to delete this comment? It will be deleted and hidden from regular users but can be restored later.</p>
<div className="mb-3">
<label htmlFor="deletionReason" className="form-label">
<strong>Reason for deletion <span className="text-danger">*</span></strong>
</label>
<textarea
id="deletionReason"
className="form-control"
rows={4}
placeholder="Please explain why this comment is being deleted. The author will receive this reason via email."
value={deletionReason}
onChange={(e) => setDeletionReason(e.target.value)}
required
/>
<small className="text-muted">
This reason will be sent to the comment author via email.
</small>
</div>
</>
)}
{adminAction?.type === 'restoreComment' && (
<p>Are you sure you want to restore this comment? It will become visible to all users again.</p>

View File

@@ -286,9 +286,9 @@ export const forumAPI = {
deleteComment: (commentId: string) =>
api.delete(`/forum/comments/${commentId}`),
// Admin endpoints
adminDeletePost: (id: string) => api.delete(`/forum/admin/posts/${id}`),
adminDeletePost: (id: string, reason: string) => api.delete(`/forum/admin/posts/${id}`, { data: { reason } }),
adminRestorePost: (id: string) => api.patch(`/forum/admin/posts/${id}/restore`),
adminDeleteComment: (id: string) => api.delete(`/forum/admin/comments/${id}`),
adminDeleteComment: (id: string, reason: string) => api.delete(`/forum/admin/comments/${id}`, { data: { reason } }),
adminRestoreComment: (id: string) => api.patch(`/forum/admin/comments/${id}/restore`),
adminClosePost: (id: string) => api.patch(`/forum/admin/posts/${id}/close`),
adminReopenPost: (id: string) => api.patch(`/forum/admin/posts/${id}/reopen`),