ENCOA-311
This commit is contained in:
@@ -1,13 +1,18 @@
|
||||
import { Module } from "@/interfaces";
|
||||
import clsx from "clsx";
|
||||
import { ReactNode } from "react";
|
||||
import { MdDelete, MdEdit, MdEditOff, MdRefresh, MdSave } from "react-icons/md";
|
||||
import { ReactNode, useEffect, useState } from "react";
|
||||
import { MdDelete, MdEdit, MdEditOff, MdRefresh, MdSave, MdSignalCellularAlt } from "react-icons/md";
|
||||
import { HiOutlineClipboardCheck, HiOutlineClipboardList } from "react-icons/hi";
|
||||
import { Difficulty } from "@/interfaces/exam";
|
||||
import Option from "@/interfaces/option";
|
||||
import ReactSelect, { components } from "react-select";
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
description: string;
|
||||
editing: boolean;
|
||||
difficulty?: Difficulty;
|
||||
saveDifficulty?: (diff: Difficulty) => void;
|
||||
module?: Module;
|
||||
handleSave: () => void;
|
||||
handleDiscard: () => void;
|
||||
@@ -19,69 +24,135 @@ interface Props {
|
||||
}
|
||||
|
||||
const Header: React.FC<Props> = ({
|
||||
title, description, editing, isEvaluationEnabled, handleSave, handleDiscard, handleDelete, handleEdit, handlePractice, children, module }) => {
|
||||
title, description, editing, difficulty, saveDifficulty, isEvaluationEnabled, handleSave, handleDiscard, handleDelete, handleEdit, handlePractice, children, module
|
||||
}) => {
|
||||
const DIFFICULTIES: Difficulty[] = ["A1", "A2", "B1", "B2", "C1", "C2"];
|
||||
const difficultyOptions: Option[] = DIFFICULTIES.map(level => ({
|
||||
label: level,
|
||||
value: level
|
||||
}));
|
||||
|
||||
return (
|
||||
<div className="flex justify-between items-center mb-6 text-sm">
|
||||
<div className="flex flex-col md:flex-row items-start md:items-center mb-6 text-sm">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-gray-800">{title}</h1>
|
||||
<p className="text-gray-600 mt-1">{description}</p>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
{children}
|
||||
<button
|
||||
onClick={handleSave}
|
||||
disabled={!editing}
|
||||
className={
|
||||
clsx("px-4 py-2 rounded-lg flex items-center gap-2 transition-all duration-200",
|
||||
editing ? 'bg-green-500 text-white hover:bg-green-600' : 'bg-gray-100 text-gray-400 cursor-not-allowed'
|
||||
)}
|
||||
>
|
||||
<MdSave size={18} />
|
||||
Save
|
||||
</button>
|
||||
<button
|
||||
onClick={handleDiscard}
|
||||
disabled={!editing}
|
||||
className={clsx(
|
||||
"px-4 py-2 rounded-lg flex items-center gap-2 transition-all duration-200",
|
||||
editing ? 'bg-gray-500 text-white hover:bg-gray-600' : 'bg-gray-100 text-gray-400 cursor-not-allowed'
|
||||
)}
|
||||
>
|
||||
<MdRefresh size={18} />
|
||||
Discard
|
||||
</button>
|
||||
{handleEdit && (
|
||||
<div className="flex w-[50%] ml-auto justify-end flex-wrap gap-2">
|
||||
<div className="flex flex-wrap gap-2 justify-end">
|
||||
<button
|
||||
onClick={handleEdit}
|
||||
className={`px-4 py-2 bg-ielts-${module}/80 text-white hover:bg-ielts-${module} rounded-lg transition-all duration-200 flex items-center gap-2`}
|
||||
onClick={handleSave}
|
||||
disabled={!editing}
|
||||
className={
|
||||
clsx("px-3 py-2 rounded-lg flex items-center gap-1 transition-all duration-200 min-w-[90px] justify-center",
|
||||
editing ? 'bg-green-500 text-white hover:bg-green-600' : 'bg-gray-100 text-gray-400 cursor-not-allowed'
|
||||
)}
|
||||
>
|
||||
{editing ? <MdEditOff size={18} /> : <MdEdit size={18} />}
|
||||
Edit
|
||||
<MdSave size={18} />
|
||||
Save
|
||||
</button>
|
||||
)}
|
||||
{handlePractice &&
|
||||
<button
|
||||
onClick={handlePractice}
|
||||
onClick={handleDiscard}
|
||||
disabled={!editing}
|
||||
className={clsx(
|
||||
"px-4 py-2 rounded-lg flex items-center gap-2 transition-all duration-200",
|
||||
isEvaluationEnabled
|
||||
? 'bg-amber-500 text-white hover:bg-amber-600'
|
||||
: 'bg-gray-200 text-gray-600 hover:bg-gray-300'
|
||||
"px-3 py-2 rounded-lg flex items-center gap-1 transition-all duration-200 min-w-[90px] justify-center",
|
||||
editing ? 'bg-gray-500 text-white hover:bg-gray-600' : 'bg-gray-100 text-gray-400 cursor-not-allowed'
|
||||
)}
|
||||
>
|
||||
{isEvaluationEnabled ? <HiOutlineClipboardCheck size={18} /> : <HiOutlineClipboardList size={18} />}
|
||||
{isEvaluationEnabled ? 'Graded' : 'Practice'}
|
||||
<MdRefresh size={18} />
|
||||
Discard
|
||||
</button>
|
||||
}
|
||||
{handleDelete && (
|
||||
<button
|
||||
onClick={handleDelete}
|
||||
className="px-4 py-2 bg-white border border-red-500 text-red-500 hover:bg-red-50 rounded-lg transition-all duration-200 flex items-center gap-2"
|
||||
>
|
||||
<MdDelete size={18} />
|
||||
Delete
|
||||
</button>
|
||||
)}
|
||||
{handleEdit && (
|
||||
<button
|
||||
onClick={handleEdit}
|
||||
className={`px-3 py-2 bg-ielts-${module}/80 text-white hover:bg-ielts-${module} rounded-lg transition-all duration-200 flex items-center gap-1 min-w-[90px] justify-center`}
|
||||
>
|
||||
{editing ? <MdEditOff size={18} /> : <MdEdit size={18} />}
|
||||
Edit
|
||||
</button>
|
||||
)}
|
||||
{handlePractice &&
|
||||
<button
|
||||
onClick={handlePractice}
|
||||
className={clsx(
|
||||
"px-3 py-2 rounded-lg flex items-center gap-1 transition-all duration-200 min-w-[90px] justify-center",
|
||||
isEvaluationEnabled
|
||||
? 'bg-amber-500 text-white hover:bg-amber-600'
|
||||
: 'bg-gray-200 text-gray-600 hover:bg-gray-300'
|
||||
)}
|
||||
>
|
||||
{isEvaluationEnabled ? <HiOutlineClipboardCheck size={18} /> : <HiOutlineClipboardList size={18} />}
|
||||
{isEvaluationEnabled ? 'Graded' : 'Practice'}
|
||||
</button>
|
||||
}
|
||||
{handleDelete && (
|
||||
<button
|
||||
onClick={handleDelete}
|
||||
className="px-3 py-2 bg-white border border-red-500 text-red-500 hover:bg-red-50 rounded-lg transition-all duration-200 flex items-center gap-1 min-w-[90px] justify-center"
|
||||
>
|
||||
<MdDelete size={18} />
|
||||
Delete
|
||||
</button>
|
||||
)}
|
||||
{difficulty !== undefined && (
|
||||
<div className="w-[92px]">
|
||||
<ReactSelect
|
||||
options={difficultyOptions}
|
||||
value={difficultyOptions.find(opt => opt.value === difficulty)}
|
||||
onChange={(value) => saveDifficulty!(value!.value as Difficulty)}
|
||||
menuPortalTarget={document?.body}
|
||||
components={{
|
||||
IndicatorSeparator: null,
|
||||
ValueContainer: ({ children, ...props }) => (
|
||||
<components.ValueContainer {...props}>
|
||||
<div className="flex flex-row gap-2 items-center pl-0.5">
|
||||
<MdSignalCellularAlt size={14} className="text-gray-600" />
|
||||
{children}
|
||||
</div>
|
||||
</components.ValueContainer>
|
||||
)
|
||||
}}
|
||||
styles={{
|
||||
menuPortal: (base) => ({ ...base, zIndex: 9999 }),
|
||||
control: (styles) => ({
|
||||
...styles,
|
||||
minHeight: '40px',
|
||||
border: '1px solid #e5e7eb',
|
||||
borderRadius: '0.5rem',
|
||||
boxShadow: 'none',
|
||||
backgroundColor: '#f3f4f6',
|
||||
cursor: 'pointer',
|
||||
'&:hover': {
|
||||
border: '1px solid #e5e7eb',
|
||||
}
|
||||
}),
|
||||
valueContainer: (styles) => ({
|
||||
...styles,
|
||||
padding: '0 8px',
|
||||
display: 'flex',
|
||||
alignItems: 'center'
|
||||
}),
|
||||
input: (styles) => ({
|
||||
...styles,
|
||||
margin: '0',
|
||||
padding: '0'
|
||||
}),
|
||||
dropdownIndicator: (styles) => ({
|
||||
...styles,
|
||||
padding: '8px'
|
||||
}),
|
||||
option: (styles, state) => ({
|
||||
...styles,
|
||||
backgroundColor: state.isFocused ? "#D5D9F0" : state.isSelected ? "#7872BF" : "white",
|
||||
color: state.isFocused ? "black" : styles.color,
|
||||
}),
|
||||
}}
|
||||
className="text-sm"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user