forked from CSI-KJSCE/appointment_to_examiner
Commit
This commit is contained in:
@@ -69,6 +69,38 @@ button[type="submit"] {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.suggestions {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 1px solid #ccc;
|
||||
max-height: 150px;
|
||||
overflow-y: auto;
|
||||
background: #fff;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.suggestions li {
|
||||
padding: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.suggestions li:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
color: red;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.error input {
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.form-container {
|
||||
margin: 20px;
|
||||
|
||||
@@ -1,194 +1,6 @@
|
||||
// import React, { useState, useEffect } from "react";
|
||||
// import { useLocation, useParams, useNavigate } from "react-router-dom";
|
||||
// import "./CourseForm.css";
|
||||
|
||||
// const CourseForm = () => {
|
||||
// const { id } = useParams(); // Get the course ID from the URL params
|
||||
// const location = useLocation();
|
||||
// const navigate = useNavigate(); // Updated for navigation
|
||||
// const { course } = location.state || {};
|
||||
|
||||
// const [options, setOptions] = useState({
|
||||
// assessment: [],
|
||||
// reassessment: [],
|
||||
// paperSetting: [],
|
||||
// moderation: [],
|
||||
// pwdPaperSetter: [],
|
||||
// oralsPracticals: [], // New field for Orals/Practicals
|
||||
// });
|
||||
|
||||
// const [formData, setFormData] = useState({
|
||||
// assessment: "",
|
||||
// reassessment: "",
|
||||
// paperSetting: "",
|
||||
// moderation: "",
|
||||
// pwdPaperSetter: "",
|
||||
// oralsPracticals: "", // New field for Orals/Practicals
|
||||
// });
|
||||
|
||||
// const [errors, setErrors] = useState({}); // To track validation errors
|
||||
|
||||
// // Fetch data for search bars
|
||||
// useEffect(() => {
|
||||
// const fetchOptions = async () => {
|
||||
// try {
|
||||
// const response = await fetch("/api/options"); // Replace with your API endpoint
|
||||
// const data = await response.json();
|
||||
// setOptions(data);
|
||||
// } catch (error) {
|
||||
// console.error("Failed to fetch options:", error);
|
||||
// }
|
||||
// };
|
||||
|
||||
// fetchOptions();
|
||||
// }, []);
|
||||
|
||||
// const handleInputChange = (e) => {
|
||||
// const { name, value } = e.target;
|
||||
// setFormData({ ...formData, [name]: value });
|
||||
// };
|
||||
|
||||
// const validateForm = () => {
|
||||
// const newErrors = {};
|
||||
// Object.keys(formData).forEach((field) => {
|
||||
// if (!formData[field]) {
|
||||
// newErrors[field] = "This field is required";
|
||||
// }
|
||||
// });
|
||||
// setErrors(newErrors);
|
||||
// return Object.keys(newErrors).length === 0;
|
||||
// };
|
||||
|
||||
// const handleSubmit = (e) => {
|
||||
// e.preventDefault();
|
||||
// if (validateForm()) {
|
||||
// console.log("Form submitted:", formData);
|
||||
|
||||
// navigate("/courses", { state: { updatedCourse: { ...course, status: "Submitted" } } });
|
||||
// }
|
||||
// };
|
||||
|
||||
// return (
|
||||
// <div className="form-container">
|
||||
// <h2>Course Info</h2>
|
||||
// <form onSubmit={handleSubmit}>
|
||||
// <label>
|
||||
// Course ID:
|
||||
// <input type="text" value={course?.id || id} readOnly />
|
||||
// </label>
|
||||
// <label>
|
||||
// Course Name:
|
||||
// <input type="text" value={course?.name || ""} readOnly />
|
||||
// </label>
|
||||
// <label className={errors.oralsPracticals ? "error" : ""}>
|
||||
// Orals/Practicals:
|
||||
// <input
|
||||
// type="text"
|
||||
// name="oralsPracticals"
|
||||
// list="oralsPracticals-options"
|
||||
// value={formData.oralsPracticals}
|
||||
// onChange={handleInputChange}
|
||||
// />
|
||||
// <datalist id="oralsPracticals-options">
|
||||
// {options.oralsPracticals.map((option, index) => (
|
||||
// <option key={index} value={option} />
|
||||
// ))}
|
||||
// </datalist>
|
||||
// {errors.oralsPracticals && <span className="error-message">{errors.oralsPracticals}</span>}
|
||||
// </label>
|
||||
// <label className={errors.assessment ? "error" : ""}>
|
||||
// Assessment:
|
||||
// <input
|
||||
// type="text"
|
||||
// name="assessment"
|
||||
// list="assessment-options"
|
||||
// value={formData.assessment}
|
||||
// onChange={handleInputChange}
|
||||
// />
|
||||
// <datalist id="assessment-options">
|
||||
// {options.assessment.map((option, index) => (
|
||||
// <option key={index} value={option} />
|
||||
// ))}
|
||||
// </datalist>
|
||||
// {errors.assessment && <span className="error-message">{errors.assessment}</span>}
|
||||
// </label>
|
||||
// <label className={errors.reassessment ? "error" : ""}>
|
||||
// Reassessment:
|
||||
// <input
|
||||
// type="text"
|
||||
// name="reassessment"
|
||||
// list="reassessment-options"
|
||||
// value={formData.reassessment}
|
||||
// onChange={handleInputChange}
|
||||
// />
|
||||
// <datalist id="reassessment-options">
|
||||
// {options.reassessment.map((option, index) => (
|
||||
// <option key={index} value={option} />
|
||||
// ))}
|
||||
// </datalist>
|
||||
// {errors.reassessment && <span className="error-message">{errors.reassessment}</span>}
|
||||
// </label>
|
||||
// <label className={errors.paperSetting ? "error" : ""}>
|
||||
// Paper Setting:
|
||||
// <input
|
||||
// type="text"
|
||||
// name="paperSetting"
|
||||
// list="paperSetting-options"
|
||||
// value={formData.paperSetting}
|
||||
// onChange={handleInputChange}
|
||||
// />
|
||||
// <datalist id="paperSetting-options">
|
||||
// {options.paperSetting.map((option, index) => (
|
||||
// <option key={index} value={option} />
|
||||
// ))}
|
||||
// </datalist>
|
||||
// {errors.paperSetting && <span className="error-message">{errors.paperSetting}</span>}
|
||||
// </label>
|
||||
// <label className={errors.moderation ? "error" : ""}>
|
||||
// Moderation:
|
||||
// <input
|
||||
// type="text"
|
||||
// name="moderation"
|
||||
// list="moderation-options"
|
||||
// value={formData.moderation}
|
||||
// onChange={handleInputChange}
|
||||
// />
|
||||
// <datalist id="moderation-options">
|
||||
// {options.moderation.map((option, index) => (
|
||||
// <option key={index} value={option} />
|
||||
// ))}
|
||||
// </datalist>
|
||||
// {errors.moderation && <span className="error-message">{errors.moderation}</span>}
|
||||
// </label>
|
||||
// <label className={errors.pwdPaperSetter ? "error" : ""}>
|
||||
// PwD Paper Setter:
|
||||
// <input
|
||||
// type="text"
|
||||
// name="pwdPaperSetter"
|
||||
// list="pwdPaperSetter-options"
|
||||
// value={formData.pwdPaperSetter}
|
||||
// onChange={handleInputChange}
|
||||
// />
|
||||
// <datalist id="pwdPaperSetter-options">
|
||||
// {options.pwdPaperSetter.map((option, index) => (
|
||||
// <option key={index} value={option} />
|
||||
// ))}
|
||||
// </datalist>
|
||||
// {errors.pwdPaperSetter && <span className="error-message">{errors.pwdPaperSetter}</span>}
|
||||
// </label>
|
||||
// <button type="submit" disabled={Object.keys(errors).length > 0}>Submit</button>
|
||||
// </form>
|
||||
// </div>
|
||||
// );
|
||||
// };
|
||||
|
||||
// export default CourseForm;
|
||||
|
||||
// CourseForm.jsx
|
||||
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useLocation, useParams, useNavigate } from "react-router-dom";
|
||||
import { fetchFaculties } from "../api";
|
||||
import { fetchFaculties, saveAppointment } from "../api";
|
||||
import "./CourseForm.css";
|
||||
|
||||
const CourseForm = () => {
|
||||
@@ -198,35 +10,27 @@ const CourseForm = () => {
|
||||
const { course } = location.state || {};
|
||||
|
||||
const [options, setOptions] = useState({
|
||||
assessment: [],
|
||||
reassessment: [],
|
||||
paperSetting: [],
|
||||
moderation: [],
|
||||
pwdPaperSetter: [],
|
||||
oralsPracticals: [],
|
||||
faculties: [], // New field for faculties
|
||||
faculties: [], // List of all faculties
|
||||
});
|
||||
|
||||
const [suggestions, setSuggestions] = useState({}); // To hold suggestions for each field
|
||||
const [formData, setFormData] = useState({
|
||||
oralsPracticals: "",
|
||||
assessment: "",
|
||||
reassessment: "",
|
||||
paperSetting: "",
|
||||
moderation: "",
|
||||
pwdPaperSetter: "",
|
||||
oralsPracticals: "", // New field for Orals/Practicals
|
||||
});
|
||||
|
||||
const [errors, setErrors] = useState({});
|
||||
|
||||
// Fetch faculty list on mount
|
||||
useEffect(() => {
|
||||
const fetchOptionsAndFaculties = async () => {
|
||||
try {
|
||||
const facultiesData = await fetchFaculties(); // Fetch faculty names from the backend
|
||||
console.log(facultiesData);
|
||||
setOptions(prevOptions => ({
|
||||
...prevOptions,
|
||||
faculties: facultiesData,
|
||||
}));
|
||||
const facultiesData = await fetchFaculties(); // Fetch faculty names from backend
|
||||
setOptions((prev) => ({ ...prev, faculties: facultiesData }));
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch faculties:", error);
|
||||
}
|
||||
@@ -235,11 +39,25 @@ const CourseForm = () => {
|
||||
fetchOptionsAndFaculties();
|
||||
}, []);
|
||||
|
||||
// Handle input changes for form fields
|
||||
const handleInputChange = (e) => {
|
||||
const { name, value } = e.target;
|
||||
|
||||
setFormData({ ...formData, [name]: value });
|
||||
|
||||
// Filter suggestions for the current field
|
||||
if (options.faculties.length > 0) {
|
||||
const filteredSuggestions = options.faculties.filter((faculty) =>
|
||||
faculty.name.toLowerCase().includes(value.toLowerCase())
|
||||
);
|
||||
setSuggestions((prev) => ({
|
||||
...prev,
|
||||
[name]: filteredSuggestions,
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
// Validate the form
|
||||
const validateForm = () => {
|
||||
const newErrors = {};
|
||||
Object.keys(formData).forEach((field) => {
|
||||
@@ -251,29 +69,49 @@ const CourseForm = () => {
|
||||
return Object.keys(newErrors).length === 0;
|
||||
};
|
||||
|
||||
// const handleSubmit = (e) => {
|
||||
// e.preventDefault();
|
||||
// if (validateForm()) {
|
||||
// console.log("Form submitted:", formData);
|
||||
// navigate("/courses", { state: { updatedCourse: { ...course, status: "Submitted" } } });
|
||||
// }
|
||||
// };
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
// Handle form submission
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault(); // Prevent default form submission behavior
|
||||
if (validateForm()) {
|
||||
console.log("Form submitted:", formData);
|
||||
navigate("/courses", {
|
||||
state: {
|
||||
updatedCourse: {
|
||||
...course,
|
||||
status: "Submitted", // Update status
|
||||
...formData, // Include form data if required
|
||||
try {
|
||||
const groupedTasks = {};
|
||||
|
||||
// Group tasks by facultyId
|
||||
Object.entries(formData).forEach(([field, value]) => {
|
||||
const assignedFaculty = options.faculties.find(
|
||||
(faculty) => faculty.name === value
|
||||
);
|
||||
if (assignedFaculty) {
|
||||
if (!groupedTasks[assignedFaculty.facultyId]) {
|
||||
groupedTasks[assignedFaculty.facultyId] = {
|
||||
facultyId: assignedFaculty.facultyId,
|
||||
courseId: course?.id || id,
|
||||
tasks: [],
|
||||
};
|
||||
}
|
||||
groupedTasks[assignedFaculty.facultyId].tasks.push(field);
|
||||
}
|
||||
});
|
||||
|
||||
const payload = Object.values(groupedTasks); // Convert the grouped tasks into an array
|
||||
console.log("Saving appointment with payload:", payload);
|
||||
await saveAppointment(payload); // Save to backend
|
||||
console.log("Form submitted successfully:", payload);
|
||||
|
||||
// Redirect to courses page after successful submission
|
||||
navigate("/courses", {
|
||||
state: {
|
||||
updatedCourse: {
|
||||
...course,
|
||||
status: "Submitted",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Failed to save appointment:", error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<div className="form-container">
|
||||
@@ -287,103 +125,42 @@ const CourseForm = () => {
|
||||
Course Name:
|
||||
<input type="text" value={course?.name || ""} readOnly />
|
||||
</label>
|
||||
<label className={errors.oralsPracticals ? "error" : ""}>
|
||||
Orals/Practicals:
|
||||
<input
|
||||
type="text"
|
||||
name="oralsPracticals"
|
||||
list="oralsPracticals-options"
|
||||
value={formData.oralsPracticals}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
<datalist id="oralsPracticals-options">
|
||||
{options.oralsPracticals.map((option, index) => (
|
||||
<option key={index} value={option.name} />
|
||||
))}
|
||||
</datalist>
|
||||
{errors.oralsPracticals && <span className="error-message">{errors.oralsPracticals}</span>}
|
||||
</label>
|
||||
<label className={errors.assessment ? "error" : ""}>
|
||||
Assessment:
|
||||
<input
|
||||
type="text"
|
||||
name="assessment"
|
||||
list="assessment-options"
|
||||
value={formData.assessment}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
<datalist id="assessment-options">
|
||||
{options.assessment.map((option, index) => (
|
||||
<option key={index} value={option.name} />
|
||||
))}
|
||||
</datalist>
|
||||
{errors.assessment && <span className="error-message">{errors.assessment}</span>}
|
||||
</label>
|
||||
<label className={errors.reassessment ? "error" : ""}>
|
||||
Reassessment:
|
||||
<input
|
||||
type="text"
|
||||
name="reassessment"
|
||||
list="reassessment-options"
|
||||
value={formData.reassessment}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
<datalist id="reassessment-options">
|
||||
{options.reassessment.map((option, index) => (
|
||||
<option key={index} value={option.name} />
|
||||
))}
|
||||
</datalist>
|
||||
{errors.reassessment && <span className="error-message">{errors.reassessment}</span>}
|
||||
</label>
|
||||
<label className={errors.paperSetting ? "error" : ""}>
|
||||
Paper Setting:
|
||||
<input
|
||||
type="text"
|
||||
name="paperSetting"
|
||||
list="paperSetting-options"
|
||||
value={formData.paperSetting}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
<datalist id="paperSetting-options">
|
||||
{options.paperSetting.map((option, index) => (
|
||||
<option key={index} value={option.name} />
|
||||
))}
|
||||
</datalist>
|
||||
{errors.paperSetting && <span className="error-message">{errors.paperSetting}</span>}
|
||||
</label>
|
||||
<label className={errors.moderation ? "error" : ""}>
|
||||
Moderation:
|
||||
<input
|
||||
type="text"
|
||||
name="moderation"
|
||||
list="moderation-options"
|
||||
value={formData.moderation}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
<datalist id="moderation-options">
|
||||
{options.moderation.map((option, index) => (
|
||||
<option key={index} value={option.name} />
|
||||
))}
|
||||
</datalist>
|
||||
{errors.moderation && <span className="error-message">{errors.moderation}</span>}
|
||||
</label>
|
||||
<label className={errors.pwdPaperSetter ? "error" : ""}>
|
||||
PwD Paper Setter:
|
||||
<input
|
||||
type="text"
|
||||
name="pwdPaperSetter"
|
||||
list="pwdPaperSetter-options"
|
||||
value={formData.pwdPaperSetter}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
<datalist id="pwdPaperSetter-options">
|
||||
{options.pwdPaperSetter.map((option, index) => (
|
||||
<option key={index} value={option.name} />
|
||||
))}
|
||||
</datalist>
|
||||
{errors.pwdPaperSetter && <span className="error-message">{errors.pwdPaperSetter}</span>}
|
||||
</label>
|
||||
<button type="submit" disabled={Object.keys(errors).length > 0}>Submit</button>
|
||||
{[
|
||||
{ name: "oralsPracticals", label: "Orals/Practicals" },
|
||||
{ name: "assessment", label: "Assessment" },
|
||||
{ name: "reassessment", label: "Reassessment" },
|
||||
{ name: "paperSetting", label: "Paper Setting" },
|
||||
{ name: "moderation", label: "Moderation" },
|
||||
{ name: "pwdPaperSetter", label: "PwD Paper Setter" },
|
||||
].map(({ name, label }) => (
|
||||
<div key={name} className={errors[name] ? "error" : ""}>
|
||||
<label>
|
||||
{label}:
|
||||
<input
|
||||
type="text"
|
||||
name={name}
|
||||
value={formData[name]}
|
||||
onChange={handleInputChange}
|
||||
placeholder={`Search faculty for ${label}`}
|
||||
/>
|
||||
<ul className="suggestions">
|
||||
{(suggestions[name] || []).map((faculty) => (
|
||||
<li
|
||||
key={faculty.facultyId}
|
||||
onClick={() => {
|
||||
setFormData({ ...formData, [name]: faculty.name });
|
||||
setSuggestions((prev) => ({ ...prev, [name]: [] })); // Clear suggestions for this field
|
||||
}}
|
||||
>
|
||||
{faculty.name}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</label>
|
||||
{errors[name] && <span className="error-message">{errors[name]}</span>}
|
||||
</div>
|
||||
))}
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
|
||||
392
client/src/Pages/CourseForm1.jsx
Normal file
392
client/src/Pages/CourseForm1.jsx
Normal file
@@ -0,0 +1,392 @@
|
||||
// import React, { useState, useEffect } from "react";
|
||||
// import { useLocation, useParams, useNavigate } from "react-router-dom";
|
||||
// import "./CourseForm.css";
|
||||
|
||||
// const CourseForm = () => {
|
||||
// const { id } = useParams(); // Get the course ID from the URL params
|
||||
// const location = useLocation();
|
||||
// const navigate = useNavigate(); // Updated for navigation
|
||||
// const { course } = location.state || {};
|
||||
|
||||
// const [options, setOptions] = useState({
|
||||
// assessment: [],
|
||||
// reassessment: [],
|
||||
// paperSetting: [],
|
||||
// moderation: [],
|
||||
// pwdPaperSetter: [],
|
||||
// oralsPracticals: [], // New field for Orals/Practicals
|
||||
// });
|
||||
|
||||
// const [formData, setFormData] = useState({
|
||||
// assessment: "",
|
||||
// reassessment: "",
|
||||
// paperSetting: "",
|
||||
// moderation: "",
|
||||
// pwdPaperSetter: "",
|
||||
// oralsPracticals: "", // New field for Orals/Practicals
|
||||
// });
|
||||
|
||||
// const [errors, setErrors] = useState({}); // To track validation errors
|
||||
|
||||
// // Fetch data for search bars
|
||||
// useEffect(() => {
|
||||
// const fetchOptions = async () => {
|
||||
// try {
|
||||
// const response = await fetch("/api/options"); // Replace with your API endpoint
|
||||
// const data = await response.json();
|
||||
// setOptions(data);
|
||||
// } catch (error) {
|
||||
// console.error("Failed to fetch options:", error);
|
||||
// }
|
||||
// };
|
||||
|
||||
// fetchOptions();
|
||||
// }, []);
|
||||
|
||||
// const handleInputChange = (e) => {
|
||||
// const { name, value } = e.target;
|
||||
// setFormData({ ...formData, [name]: value });
|
||||
// };
|
||||
|
||||
// const validateForm = () => {
|
||||
// const newErrors = {};
|
||||
// Object.keys(formData).forEach((field) => {
|
||||
// if (!formData[field]) {
|
||||
// newErrors[field] = "This field is required";
|
||||
// }
|
||||
// });
|
||||
// setErrors(newErrors);
|
||||
// return Object.keys(newErrors).length === 0;
|
||||
// };
|
||||
|
||||
// const handleSubmit = (e) => {
|
||||
// e.preventDefault();
|
||||
// if (validateForm()) {
|
||||
// console.log("Form submitted:", formData);
|
||||
|
||||
// navigate("/courses", { state: { updatedCourse: { ...course, status: "Submitted" } } });
|
||||
// }
|
||||
// };
|
||||
|
||||
// return (
|
||||
// <div className="form-container">
|
||||
// <h2>Course Info</h2>
|
||||
// <form onSubmit={handleSubmit}>
|
||||
// <label>
|
||||
// Course ID:
|
||||
// <input type="text" value={course?.id || id} readOnly />
|
||||
// </label>
|
||||
// <label>
|
||||
// Course Name:
|
||||
// <input type="text" value={course?.name || ""} readOnly />
|
||||
// </label>
|
||||
// <label className={errors.oralsPracticals ? "error" : ""}>
|
||||
// Orals/Practicals:
|
||||
// <input
|
||||
// type="text"
|
||||
// name="oralsPracticals"
|
||||
// list="oralsPracticals-options"
|
||||
// value={formData.oralsPracticals}
|
||||
// onChange={handleInputChange}
|
||||
// />
|
||||
// <datalist id="oralsPracticals-options">
|
||||
// {options.oralsPracticals.map((option, index) => (
|
||||
// <option key={index} value={option} />
|
||||
// ))}
|
||||
// </datalist>
|
||||
// {errors.oralsPracticals && <span className="error-message">{errors.oralsPracticals}</span>}
|
||||
// </label>
|
||||
// <label className={errors.assessment ? "error" : ""}>
|
||||
// Assessment:
|
||||
// <input
|
||||
// type="text"
|
||||
// name="assessment"
|
||||
// list="assessment-options"
|
||||
// value={formData.assessment}
|
||||
// onChange={handleInputChange}
|
||||
// />
|
||||
// <datalist id="assessment-options">
|
||||
// {options.assessment.map((option, index) => (
|
||||
// <option key={index} value={option} />
|
||||
// ))}
|
||||
// </datalist>
|
||||
// {errors.assessment && <span className="error-message">{errors.assessment}</span>}
|
||||
// </label>
|
||||
// <label className={errors.reassessment ? "error" : ""}>
|
||||
// Reassessment:
|
||||
// <input
|
||||
// type="text"
|
||||
// name="reassessment"
|
||||
// list="reassessment-options"
|
||||
// value={formData.reassessment}
|
||||
// onChange={handleInputChange}
|
||||
// />
|
||||
// <datalist id="reassessment-options">
|
||||
// {options.reassessment.map((option, index) => (
|
||||
// <option key={index} value={option} />
|
||||
// ))}
|
||||
// </datalist>
|
||||
// {errors.reassessment && <span className="error-message">{errors.reassessment}</span>}
|
||||
// </label>
|
||||
// <label className={errors.paperSetting ? "error" : ""}>
|
||||
// Paper Setting:
|
||||
// <input
|
||||
// type="text"
|
||||
// name="paperSetting"
|
||||
// list="paperSetting-options"
|
||||
// value={formData.paperSetting}
|
||||
// onChange={handleInputChange}
|
||||
// />
|
||||
// <datalist id="paperSetting-options">
|
||||
// {options.paperSetting.map((option, index) => (
|
||||
// <option key={index} value={option} />
|
||||
// ))}
|
||||
// </datalist>
|
||||
// {errors.paperSetting && <span className="error-message">{errors.paperSetting}</span>}
|
||||
// </label>
|
||||
// <label className={errors.moderation ? "error" : ""}>
|
||||
// Moderation:
|
||||
// <input
|
||||
// type="text"
|
||||
// name="moderation"
|
||||
// list="moderation-options"
|
||||
// value={formData.moderation}
|
||||
// onChange={handleInputChange}
|
||||
// />
|
||||
// <datalist id="moderation-options">
|
||||
// {options.moderation.map((option, index) => (
|
||||
// <option key={index} value={option} />
|
||||
// ))}
|
||||
// </datalist>
|
||||
// {errors.moderation && <span className="error-message">{errors.moderation}</span>}
|
||||
// </label>
|
||||
// <label className={errors.pwdPaperSetter ? "error" : ""}>
|
||||
// PwD Paper Setter:
|
||||
// <input
|
||||
// type="text"
|
||||
// name="pwdPaperSetter"
|
||||
// list="pwdPaperSetter-options"
|
||||
// value={formData.pwdPaperSetter}
|
||||
// onChange={handleInputChange}
|
||||
// />
|
||||
// <datalist id="pwdPaperSetter-options">
|
||||
// {options.pwdPaperSetter.map((option, index) => (
|
||||
// <option key={index} value={option} />
|
||||
// ))}
|
||||
// </datalist>
|
||||
// {errors.pwdPaperSetter && <span className="error-message">{errors.pwdPaperSetter}</span>}
|
||||
// </label>
|
||||
// <button type="submit" disabled={Object.keys(errors).length > 0}>Submit</button>
|
||||
// </form>
|
||||
// </div>
|
||||
// );
|
||||
// };
|
||||
|
||||
// export default CourseForm;
|
||||
|
||||
// CourseForm.jsx
|
||||
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useLocation, useParams, useNavigate } from "react-router-dom";
|
||||
import { fetchFaculties } from "../api";
|
||||
import "./CourseForm.css";
|
||||
|
||||
const CourseForm = () => {
|
||||
const { id } = useParams();
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const { course } = location.state || {};
|
||||
|
||||
const [options, setOptions] = useState({
|
||||
assessment: [],
|
||||
reassessment: [],
|
||||
paperSetting: [],
|
||||
moderation: [],
|
||||
pwdPaperSetter: [],
|
||||
oralsPracticals: [],
|
||||
faculties: [], // New field for faculties
|
||||
});
|
||||
|
||||
const [formData, setFormData] = useState({
|
||||
assessment: "",
|
||||
reassessment: "",
|
||||
paperSetting: "",
|
||||
moderation: "",
|
||||
pwdPaperSetter: "",
|
||||
oralsPracticals: "", // New field for Orals/Practicals
|
||||
});
|
||||
|
||||
const [errors, setErrors] = useState({});
|
||||
|
||||
useEffect(() => {
|
||||
const fetchOptionsAndFaculties = async () => {
|
||||
try {
|
||||
const facultiesData = await fetchFaculties(); // Fetch faculty names from the backend
|
||||
console.log(facultiesData);
|
||||
setOptions(prevOptions => ({
|
||||
...prevOptions,
|
||||
faculties: facultiesData,
|
||||
}));
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch faculties:", error);
|
||||
}
|
||||
};
|
||||
|
||||
fetchOptionsAndFaculties();
|
||||
}, []);
|
||||
|
||||
const handleInputChange = (e) => {
|
||||
const { name, value } = e.target;
|
||||
setFormData({ ...formData, [name]: value });
|
||||
};
|
||||
|
||||
const validateForm = () => {
|
||||
const newErrors = {};
|
||||
Object.keys(formData).forEach((field) => {
|
||||
if (!formData[field]) {
|
||||
newErrors[field] = "This field is required";
|
||||
}
|
||||
});
|
||||
setErrors(newErrors);
|
||||
return Object.keys(newErrors).length === 0;
|
||||
};
|
||||
|
||||
// const handleSubmit = (e) => {
|
||||
// e.preventDefault();
|
||||
// if (validateForm()) {
|
||||
// console.log("Form submitted:", formData);
|
||||
// navigate("/courses", { state: { updatedCourse: { ...course, status: "Submitted" } } });
|
||||
// }
|
||||
// };
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
if (validateForm()) {
|
||||
console.log("Form submitted:", formData);
|
||||
navigate("/courses", {
|
||||
state: {
|
||||
updatedCourse: {
|
||||
...course,
|
||||
status: "Submitted", // Update status
|
||||
...formData, // Include form data if required
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<div className="form-container">
|
||||
<h2>Course Info</h2>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<label>
|
||||
Course ID:
|
||||
<input type="text" value={course?.id || id} readOnly />
|
||||
</label>
|
||||
<label>
|
||||
Course Name:
|
||||
<input type="text" value={course?.name || ""} readOnly />
|
||||
</label>
|
||||
<label className={errors.oralsPracticals ? "error" : ""}>
|
||||
Orals/Practicals:
|
||||
<input
|
||||
type="text"
|
||||
name="oralsPracticals"
|
||||
list="oralsPracticals-options"
|
||||
value={formData.oralsPracticals}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
<datalist id="oralsPracticals-options">
|
||||
{options.oralsPracticals.map((option, index) => (
|
||||
<option key={index} value={option.name} />
|
||||
))}
|
||||
</datalist>
|
||||
{errors.oralsPracticals && <span className="error-message">{errors.oralsPracticals}</span>}
|
||||
</label>
|
||||
<label className={errors.assessment ? "error" : ""}>
|
||||
Assessment:
|
||||
<input
|
||||
type="text"
|
||||
name="assessment"
|
||||
list="assessment-options"
|
||||
value={formData.assessment}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
<datalist id="assessment-options">
|
||||
{options.assessment.map((option, index) => (
|
||||
<option key={index} value={option.name} />
|
||||
))}
|
||||
</datalist>
|
||||
{errors.assessment && <span className="error-message">{errors.assessment}</span>}
|
||||
</label>
|
||||
<label className={errors.reassessment ? "error" : ""}>
|
||||
Reassessment:
|
||||
<input
|
||||
type="text"
|
||||
name="reassessment"
|
||||
list="reassessment-options"
|
||||
value={formData.reassessment}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
<datalist id="reassessment-options">
|
||||
{options.reassessment.map((option, index) => (
|
||||
<option key={index} value={option.name} />
|
||||
))}
|
||||
</datalist>
|
||||
{errors.reassessment && <span className="error-message">{errors.reassessment}</span>}
|
||||
</label>
|
||||
<label className={errors.paperSetting ? "error" : ""}>
|
||||
Paper Setting:
|
||||
<input
|
||||
type="text"
|
||||
name="paperSetting"
|
||||
list="paperSetting-options"
|
||||
value={formData.paperSetting}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
<datalist id="paperSetting-options">
|
||||
{options.paperSetting.map((option, index) => (
|
||||
<option key={index} value={option.name} />
|
||||
))}
|
||||
</datalist>
|
||||
{errors.paperSetting && <span className="error-message">{errors.paperSetting}</span>}
|
||||
</label>
|
||||
<label className={errors.moderation ? "error" : ""}>
|
||||
Moderation:
|
||||
<input
|
||||
type="text"
|
||||
name="moderation"
|
||||
list="moderation-options"
|
||||
value={formData.moderation}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
<datalist id="moderation-options">
|
||||
{options.moderation.map((option, index) => (
|
||||
<option key={index} value={option.name} />
|
||||
))}
|
||||
</datalist>
|
||||
{errors.moderation && <span className="error-message">{errors.moderation}</span>}
|
||||
</label>
|
||||
<label className={errors.pwdPaperSetter ? "error" : ""}>
|
||||
PwD Paper Setter:
|
||||
<input
|
||||
type="text"
|
||||
name="pwdPaperSetter"
|
||||
list="pwdPaperSetter-options"
|
||||
value={formData.pwdPaperSetter}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
<datalist id="pwdPaperSetter-options">
|
||||
{options.pwdPaperSetter.map((option, index) => (
|
||||
<option key={index} value={option.name} />
|
||||
))}
|
||||
</datalist>
|
||||
{errors.pwdPaperSetter && <span className="error-message">{errors.pwdPaperSetter}</span>}
|
||||
</label>
|
||||
<button type="submit" disabled={Object.keys(errors).length > 0}>Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CourseForm;
|
||||
@@ -1,55 +1,122 @@
|
||||
const BASE_URL = "http://localhost:8080/api";
|
||||
|
||||
export const fetchCourses = async (filterData) => {
|
||||
// Helper function for handling fetch requests
|
||||
const fetchData = async (url, options) => {
|
||||
try {
|
||||
const response = await fetch(url, options);
|
||||
|
||||
// Check if response is OK (status 200-299)
|
||||
if (!response.ok) {
|
||||
let errorDetails = {};
|
||||
try {
|
||||
errorDetails = await response.json(); // Attempt to parse error response
|
||||
} catch (err) {
|
||||
console.warn("Failed to parse error details:", err);
|
||||
}
|
||||
throw new Error(
|
||||
`Error: ${response.statusText} (${response.status}) - ${
|
||||
errorDetails.message || "No details available"
|
||||
}`
|
||||
);
|
||||
}
|
||||
|
||||
// Return JSON response if successful
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error(`Request failed for ${url}:`, error.message);
|
||||
throw error; // Re-throw for the caller to handle
|
||||
}
|
||||
};
|
||||
|
||||
// Fetch courses with optional filters
|
||||
export const fetchCourses = async (filterData = {}) => {
|
||||
try {
|
||||
|
||||
// Serialize filterData into query parameters
|
||||
const queryString = new URLSearchParams(filterData).toString();
|
||||
// console.log(queryString);
|
||||
const response = await fetch(`${BASE_URL}/courses?${queryString}`, {
|
||||
const url = `${BASE_URL}/courses?${queryString}`;
|
||||
return fetchData(url, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to fetch courses");
|
||||
}
|
||||
|
||||
const filteredCourses = await response.json();
|
||||
console.log(filteredCourses);
|
||||
return filteredCourses;
|
||||
} catch (error) {
|
||||
console.error("Error fetching courses:", error);
|
||||
throw error; // Re-throw error to be handled by the caller
|
||||
console.error("Error fetching courses:", error.message);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// Fetch list of faculties
|
||||
export const fetchFaculties = async () => {
|
||||
try {
|
||||
const response = await fetch(`${BASE_URL}/faculty`);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch faculties: ${response.statusText}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
return data;
|
||||
const url = `${BASE_URL}/faculty`;
|
||||
return fetchData(url, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error fetching faculties:", error.message);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// Fetch available options for form dropdowns
|
||||
export const fetchOptions = async () => {
|
||||
try {
|
||||
const response = await fetch(`${BASE_URL}/options`);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch options: ${response.statusText}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
return data;
|
||||
const url = `${BASE_URL}/options`;
|
||||
return fetchData(url, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error fetching options:", error.message);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// Save multiple appointments to MongoDB
|
||||
export const saveAppointment = async (appointmentsData) => {
|
||||
console.log("Saving appointments with payload:", appointmentsData);
|
||||
|
||||
// Validate input format
|
||||
if (!Array.isArray(appointmentsData) || appointmentsData.length === 0) {
|
||||
const errorMessage =
|
||||
"Invalid or missing appointment data: expected a non-empty array";
|
||||
console.error(errorMessage);
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
// Validate each appointment's structure
|
||||
const invalidEntries = appointmentsData.filter(
|
||||
(appointment) =>
|
||||
!appointment.facultyId || !appointment.courseId || !Array.isArray(appointment.tasks)
|
||||
);
|
||||
|
||||
if (invalidEntries.length > 0) {
|
||||
const errorMessage = `Invalid appointments detected: ${JSON.stringify(
|
||||
invalidEntries
|
||||
)}`;
|
||||
console.error(errorMessage);
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
try {
|
||||
const url = `${BASE_URL}/appointments`;
|
||||
const response = await fetchData(url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ appointments: appointmentsData }), // Send appointments as an array
|
||||
});
|
||||
|
||||
console.log("Appointments saved successfully:", response);
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error("Error saving appointments:", error.message);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user