Skip to content

Commit

Permalink
Add expert view and temporary auxilaries
Browse files Browse the repository at this point in the history
Adds the expert view and auxiliary data and an auxiliary button to access the expert view temporarily in testing
  • Loading branch information
DominikRemo committed Sep 23, 2024
1 parent 114a20c commit b9db380
Show file tree
Hide file tree
Showing 6 changed files with 317 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import React, { useState } from 'react';
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
import {faCircleInfo} from "@fortawesome/free-solid-svg-icons/faCircleInfo";

interface SingleChoiceLikertScaleProps {
title: string;
summary: string;
description: string;
}

const SingleChoiceLikertScale: React.FC<SingleChoiceLikertScaleProps> = ({
title,
summary,
description,
}) => {
const [selectedValue, setSelectedValue] = useState<number | null>(null); // No default value

const handleInfoClick = () => {
alert(description);
};

const handleChange = (value: number) => {
setSelectedValue(value);
};

// Define background colors matching the slider colors
const scaleColors = [
'bg-red-600', // First section
'bg-orange-500', // Second section
'bg-yellow-400', // Third section
'bg-green-400', // Fourth section
'bg-green-700', // Fifth section
];

return (
<>
{/* Title and Info Section */}
<div className="flex items-center">
<h3 className="text-xl font-semibold mr-2">{title}</h3>
<span
onClick={handleInfoClick}
className="text-gray-500 cursor-pointer hover:text-gray-700"
role="img"
aria-label="info"
>
<FontAwesomeIcon icon={faCircleInfo} />
</span>
</div>

{/* Question Section */}
<p className="text-gray-800">{summary}</p>

{/* Single Choice Likert Scale */}
<div className="flex items-center w-full">
{[1, 2, 3, 4, 5].map((value, index) => (
<label
key={value}
className={`flex-1 flex items-center justify-center cursor-pointer py-0.5 ${scaleColors[index]} ${index === 0 ? 'rounded-l-full' : ''} ${index === 4 ? 'rounded-r-full' : ''}`}
>
<input
type="radio"
name="likert"
value={value}
checked={selectedValue === value}
onChange={() => handleChange(value)}
className={`w-4 h-4 ${selectedValue === value ? 'border-white bg-black border-4' : 'border-gray-400 bg-transparent border-2'} rounded-full appearance-none`}
/>
</label>
))}
</div>
</>
);
};

export default SingleChoiceLikertScale;
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import React from 'react';
import SingleChoiceLikertScale from "@/components/expert_evaluation/expert_view/likert_scale";
import TextSubmissionDetail from "@/components/details/submission_detail/text";
import type { TextSubmission } from "@/model/submission";
import {TextFeedback} from "@/model/feedback";

// Define the metric data
const metrics = [
{
title: '✅ Correctness',
summary: 'Is the feedback free of content errors?',
description: `
**Good**: The feedback accurately reflects the submission, solution, and criteria, with no errors.
**Mid**: The feedback is mostly accurate but includes minor errors that don’t impact the overall evaluation.
**Bad**: The feedback contains major errors that misrepresent the submission or solution, likely causing confusion.
`,
},
{
title: '🎯 Actionability',
summary: 'Can students realistically act on this feedback?',
description: `
**Good**: The feedback provides specific steps for improvement or reinforces correct approaches.
**Mid**: The feedback notes correctness or errors but lacks detailed improvement guidance.
**Bad**: The feedback identifies errors without solutions or offers no additional insights for correct work.
`,
},
{
title: '💬 Tone',
summary: 'Is the feedback respectful and constructive?',
description: `
**Good**: The feedback is respectful and constructive, recognizing both strengths and areas for improvement.
**Mid**: The feedback is professional but mainly corrective, with little positive reinforcement.
**Bad**: The feedback is overly critical or dismissive, using unprofessional or disrespectful language.
`,
},
{
title: '🔍 Completeness',
summary: 'Does the feedback cover all relevant aspects without unnecessary information?',
description: `
**Good**: The feedback addresses all key aspects and avoids irrelevant details.
**Mid**: The feedback covers most important points but may miss minor details or include some irrelevant information.
**Bad**: The feedback misses important aspects or includes too much irrelevant content.
`,
},
];

// Define the submission and feedbacks data
const submission: TextSubmission = {
exercise_id: 0,
meta: {},
type: "text",
id: 1,
text: 'Groups are a loosely coupled amount of people whereas teams are people who work for the same goal together.'
};

// Define the Feedbacks type
type Feedbacks = {
Tutor: TextFeedback[];
LLM: TextFeedback[];
Coffee: TextFeedback[];
};

const feedbacks: Feedbacks = {
Tutor: [
{
id: 37715264,
title: undefined,
description: "Instead of stating what comprises a team and a group, please provide differences between the two, and explain these differences by means of two examples",
credits: 0.0,
type: "text",
exercise_id: 0,
submission_id: 1,
meta: {}
},
{
id: 37715265,
title: undefined,
description: "Your answer is quite short, please elaborate more in the future, also use examples to illustrate your point",
credits: 0.0,
type: "text",
exercise_id: 0,
submission_id: 1,
meta: {}
}
],
LLM: [
{
id: 1722786968303000,
title: undefined,
description: "Good explanation of a difference between groups and teams. You clearly stated that groups are loosely coupled, while teams work towards the same goal.",
credits: 1.0,
type: "text",
exercise_id: 0,
submission_id: 1,
meta: {}
},
{
id: 1722786968303001,
title: undefined,
description: "You did not provide any examples to illustrate the differences between groups and teams. Including examples would strengthen your explanation.",
credits: 0.0,
type: "text",
exercise_id: 0,
submission_id: 1,
meta: {}
}
],
Coffee: [
// Add Coffee feedbacks here if available
]
};

const LikertScaleForm: React.FC = () => {
return (
<div className="overflow-x-auto">
<div className="flex min-w-[480px] space-x-6">
{Object.entries(feedbacks).map(([feedbackType, feedbackList]) => (
<div key={feedbackType} className="flex-1 min-w-[480px] flex flex-col">
{/* Render TextSubmissionDetail */}
<div className="flex-grow flex flex-col mb-6">
<TextSubmissionDetail
identifier={`id-${submission.id}`}
key={submission.id}
submission={submission}
feedbacks={feedbackList}
onFeedbacksChange={undefined}
hideFeedbackDetails={true}
/>
</div>

{/* Render SingleChoiceLikertScale components */}
<div className="flex flex-col mt-auto">
{metrics.map((metric, index) => (
<div key={index} className="mb-4">
<SingleChoiceLikertScale
title={metric.title}
summary={metric.summary}
description={metric.description}
/>
</div>
))}
</div>
</div>
))}
</div>
</div>
);
};

export default LikertScaleForm;
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React from 'react';

function SideBySideHeader() {
return (
<div className={"mb-12"}>
{/* Title and Submission Info Section */}
<div className="flex flex-col md:flex-row items-start md:items-center justify-between mb-4 space-y-2 md:space-y-0">
<h1 className="text-3xl font-semibold text-gray-900">Side by Side Evaluation</h1>
<span className="text-lg text-gray-700">
Submission <strong>15</strong> / 105
</span>
</div>

{/* Subtitle and Details Buttons Section */}
<div className="flex flex-col md:flex-row justify-between items-end gap-4">
<div className="flex flex-col gap-2 w-full md:w-auto">
<span className="text-lg text-gray-800">
Exercise L13E02 Strategy vs. Bridge (id=642)
</span>
<div className="flex flex-col md:flex-row gap-2 w-full">
<button className="w-full md:w-auto px-4 py-2 bg-gray-300 text-gray-700 rounded-md hover:bg-gray-400 transition">
📄 Exercise Details
</button>
<button className="w-full md:w-auto px-4 py-2 bg-gray-300 text-gray-700 rounded-md hover:bg-gray-400 transition">
📊 Metric Details
</button>
<button className="w-full md:w-auto px-4 py-2 bg-gray-300 text-gray-700 rounded-md hover:bg-gray-400 transition">
📚 Evaluation Tutorial
</button>
</div>
</div>

{/* Navigation Buttons Section */}
<div className="flex flex-col items-end gap-2 mt-4 md:mt-0 w-full md:w-[250px]">
<button className="px-4 py-2 bg-gray-300 text-gray-700 rounded-md hover:bg-gray-400 transition w-full">
😴 Continue Later
</button>
<div className="flex gap-2 w-full">
<button className="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition min-w-[120px] md:w-auto">
⬅️ Previous
</button>
<button className="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition min-w-[120px] md:w-auto">
Next ➡️
</button>
</div>
</div>
</div>
</div>
);
}

export default SideBySideHeader;
24 changes: 24 additions & 0 deletions playground/src/components/expert_evaluation_header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react';
import { useRouter } from 'next/router';

function ExpertEvaluation() {
const router = useRouter();

const handleGoToExpertView = () => {
router.push('/expert_view');
};

return (
<div className="bg-white rounded-md p-4 mb-8 space-y-2">
<h3 className="text-2xl font-bold">Define Experiment</h3>
<button
onClick={handleGoToExpertView}
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition"
>
Go to expert view
</button>
</div>
);
}

export default ExpertEvaluation;
14 changes: 14 additions & 0 deletions playground/src/pages/expert_view.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import SideBySideHeader from '@/components/expert_evaluation/expert_view/side_by_side_header';
import React from 'react';
import LikertScaleForm from "@/components/expert_evaluation/expert_view/likert_scale_form";

function SideBySideExpertView() {
return (
<div className={"bg-white p-6"}>
<SideBySideHeader />
<LikertScaleForm />
</div>
);
}

export default SideBySideExpertView;
2 changes: 2 additions & 0 deletions playground/src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import { useBaseInfo } from "@/hooks/base_info_context";
import BaseInfoHeader from "@/components/base_info_header";
import ModuleRequests from "@/components/view_mode/module_requests";
import EvaluationMode from "@/components/view_mode/evaluation_mode";
import ExpertEvaluation from "@/components/expert_evaluation_header";

export default function Playground() {
const { viewMode } = useBaseInfo();

return (
<main className="flex min-h-screen flex-col p-24">
<h1 className="text-6xl font-bold text-white mb-8">Playground</h1>
<ExpertEvaluation />
<BaseInfoHeader />
{viewMode === "module_requests" && <ModuleRequests />}
{viewMode === "evaluation_mode" && <EvaluationMode />}
Expand Down

0 comments on commit b9db380

Please sign in to comment.