Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 40 additions & 1 deletion frontend/src/components/ModeratorQueue.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useState, useEffect } from "react";
import { Article, ReviewData } from "../types/article";
import { commentTemplates, CommentTemplate } from "../utils/commentTemplates";
import styles from "../styles/ModeratorQueue.module.scss";

const ModeratorQueue: React.FC = () => {
Expand All @@ -22,6 +23,7 @@ const ModeratorQueue: React.FC = () => {
const [filterStatus, setFilterStatus] = useState<
"all" | "duplicate" | "normal"
>("all");
const [selectedTemplate, setSelectedTemplate] = useState<string>('');

useEffect(() => {
fetchPendingArticles();
Expand Down Expand Up @@ -138,6 +140,18 @@ const ModeratorQueue: React.FC = () => {
return true;
});

const applyTemplate = () => {
if (selectedTemplate) {
const template = commentTemplates.find(t => t.id === selectedTemplate);
if (template) {
setReviewData({
...reviewData,
reviewComment: template.content
});
}
}
};

const duplicateCount = articles.filter((a) => a.isDuplicate).length;

if (loading) {
Expand Down Expand Up @@ -642,7 +656,32 @@ const ModeratorQueue: React.FC = () => {
)}

<div className={styles.inputGroup}>
<label>Review Comments</label>
<div className={styles.templateControls}>
<label htmlFor="comment-template">Review Comments</label>
<div className={styles.templateSelector}>
<select
id="comment-template"
value={selectedTemplate}
onChange={(e) => setSelectedTemplate(e.target.value)}
className={styles.templateSelect}
>
<option value="">Select a template...</option>
{commentTemplates.map((template) => (
<option key={template.id} value={template.id}>
{template.name}
</option>
))}
</select>
<button
type="button"
onClick={applyTemplate}
disabled={!selectedTemplate}
className={`${styles.applyTemplateBtn} ${!selectedTemplate ? styles.disabled : ''}`}
>
Apply Template
</button>
</div>
</div>
<textarea
value={reviewData.reviewComment}
onChange={(e) =>
Expand Down
86 changes: 78 additions & 8 deletions frontend/src/styles/ModeratorQueue.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -467,8 +467,8 @@ $border-radius-sm: 8px;

// ===== Sections =====
.section {
margin-bottom: 1rem;
padding-bottom: 1rem;
margin-bottom: 0.75rem;
padding-bottom: 0.5rem;
border-bottom: 1px solid $gray-200;

&:last-child {
Expand Down Expand Up @@ -801,15 +801,15 @@ $border-radius-sm: 8px;
}

.inputGroup {
margin-bottom: 1rem;
margin-bottom: 0.75rem;
box-sizing: border-box;

label {
display: block;
font-size: 0.875rem;
font-weight: 600;
color: $gray-700;
margin-bottom: 0.5rem;
margin-bottom: 0.25rem;
}
}

Expand All @@ -818,7 +818,7 @@ $border-radius-sm: 8px;
padding: 0.875rem;
border: 2px solid $gray-200;
border-radius: 8px;
font-size: 0.9375rem;
font-size: 0.875rem;
color: $gray-900;
transition: $transition;
font-family: inherit;
Expand All @@ -840,7 +840,7 @@ $border-radius-sm: 8px;
padding: 0.875rem;
border: 2px solid $gray-200;
border-radius: 8px;
font-size: 0.9375rem;
font-size: 0.875rem;
color: $gray-900;
transition: $transition;
font-family: inherit;
Expand All @@ -862,8 +862,8 @@ $border-radius-sm: 8px;

// ===== Submit Section =====
.submitSection {
margin-top: 1.5rem;
padding-top: 0.5rem;
margin-top: 1rem;
padding-top: 0.25rem;
border-top: none;
}

Expand Down Expand Up @@ -937,3 +937,73 @@ $border-radius-sm: 8px;
height: 96px;
color: $gray-300;
}

// ===== Template Controls =====
.templateControls {
display: flex;
flex-direction: column;
gap: 0.75rem;
margin-bottom: 0.75rem;

label {
margin-bottom: 0;
}
}

.templateSelector {
display: flex;
gap: 0.75rem;

@media (max-width: 640px) {
flex-direction: column;
}
}

.templateSelect {
flex: 1;
padding: 0.75rem;
border: 2px solid $gray-200;
border-radius: 8px;
font-size: 0.875rem;
color: $gray-900;
background-color: white;
transition: $transition;
font-family: inherit;
cursor: pointer;

&:focus {
outline: none;
border-color: $primary;
box-shadow: 0 0 0 3px rgba($primary, 0.1);
}
}

.applyTemplateBtn {
padding: 0.75rem 1rem;
background: $primary;
color: white;
border: none;
border-radius: 8px;
font-size: 0.875rem;
font-weight: 500;
cursor: pointer;
transition: $transition;
white-space: nowrap;

&:hover:not(:disabled) {
background: $primary-dark;
box-shadow: $shadow-md;
}

&:disabled {
background: $gray-400;
cursor: not-allowed;
opacity: 0.6;
}

&.disabled {
background: $gray-400;
cursor: not-allowed;
opacity: 0.6;
}
}
77 changes: 77 additions & 0 deletions frontend/src/utils/commentTemplates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// commentTemplates.ts
// Predefined comment templates for article moderation

export interface CommentTemplate {
id: string;
name: string;
category: 'approval' | 'rejection' | 'clarification' | 'duplicate';
content: string;
}

export const commentTemplates: CommentTemplate[] = [
// Approval Templates
{
id: 'approval-general',
name: 'General Approval',
category: 'approval',
content: 'This article meets all the submission criteria and provides valuable evidence regarding the software engineering practice. The methodology is sound and the findings are clearly presented.'
},
{
id: 'approval-high-quality',
name: 'High Quality Article',
category: 'approval',
content: 'This is an excellent article that makes a significant contribution to the field. The evidence presented is robust and the conclusions are well-supported by the data.'
},

// Rejection Templates
{
id: 'rejection-low-quality',
name: 'Low Quality/Methodology Issues',
category: 'rejection',
content: 'This article does not meet the quality standards for inclusion in the database. The methodology has significant flaws that undermine the validity of the findings.'
},
{
id: 'rejection-insufficient-evidence',
name: 'Insufficient Evidence',
category: 'rejection',
content: 'This article provides insufficient evidence to support its claims about the software engineering practice. Additional research and validation would be needed to make the findings credible.'
},
{
id: 'rejection-off-topic',
name: 'Off Topic/Out of Scope',
category: 'rejection',
content: 'This article is not relevant to the scope of the SE Evidence Database. It does not address a software engineering practice or provides information that is tangential to our focus.'
},

// Clarification Requests
{
id: 'clarification-needed',
name: 'Clarification Needed',
category: 'clarification',
content: 'This article has potential but needs clarification on key aspects before it can be approved. Please provide additional information about the methodology and evidence.'
},
{
id: 'clarification-evidence',
name: 'Evidence Clarification',
category: 'clarification',
content: 'The relationship between the evidence presented and the claims made about the software engineering practice is unclear. Please clarify this connection.'
},

// Duplicate Templates
{
id: 'duplicate-found',
name: 'Duplicate Content',
category: 'duplicate',
content: 'This article appears to be substantially similar to an existing entry in the database. After review, it does not provide significantly new information or evidence to warrant separate inclusion.'
}
];

// Function to get templates by category
export const getTemplatesByCategory = (category: CommentTemplate['category']) => {
return commentTemplates.filter(template => template.category === category);
};

// Function to get all templates
export const getAllTemplates = () => {
return commentTemplates;
};