feat: add semester parity validation for course duplication and enhance UI for target term selection
This commit is contained in:
parent
5613078c00
commit
c57787eb20
@ -3,6 +3,8 @@
|
||||
namespace App\Http\Requests\Admin\Manage;
|
||||
|
||||
use App\Enums\ClassMethod;
|
||||
use App\Enums\Semester;
|
||||
use App\Models\AcademicTerm;
|
||||
use App\Models\Course;
|
||||
use App\Models\Lecturer;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
@ -18,6 +20,26 @@ public function authorize(): bool
|
||||
public function rules(): array
|
||||
{
|
||||
$academicTermId = $this->input('academic_term_id');
|
||||
$academicTerm = $academicTermId ? AcademicTerm::find($academicTermId) : null;
|
||||
|
||||
$semesterParityRule = function ($attribute, $value, $fail) use ($academicTerm) {
|
||||
if (! $academicTerm) {
|
||||
return;
|
||||
}
|
||||
|
||||
$semesterNumber = Course::find($value)?->semester_number;
|
||||
|
||||
if ($semesterNumber === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$isOddSemester = $semesterNumber % 2 === 1;
|
||||
$matches = $academicTerm->semester === Semester::odd ? $isOddSemester : ! $isOddSemester;
|
||||
|
||||
if (! $matches) {
|
||||
$fail('Mata kuliah semester '.$semesterNumber.' tidak sesuai dengan periode '.$academicTerm->semester->label().'.');
|
||||
}
|
||||
};
|
||||
|
||||
if ($this->isMethod('post')) {
|
||||
return [
|
||||
@ -28,6 +50,7 @@ public function rules(): array
|
||||
Rule::unique('course_classes', 'course_id')
|
||||
->where('academic_term_id', $academicTermId)
|
||||
->whereNull('deleted_at'),
|
||||
$semesterParityRule,
|
||||
],
|
||||
'lecturer_id' => [
|
||||
'required',
|
||||
@ -61,6 +84,7 @@ function ($attribute, $value, $fail) {
|
||||
->where('academic_term_id', $academicTermId)
|
||||
->whereNull('deleted_at')
|
||||
->ignore($this->route('course_class')?->id),
|
||||
$semesterParityRule,
|
||||
],
|
||||
'lecturer_id' => [
|
||||
'required',
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http\Requests\Admin\Manage;
|
||||
|
||||
use App\Models\AcademicTerm;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Validation\Validator;
|
||||
@ -26,6 +27,15 @@ public function withValidator(Validator $validator): void
|
||||
$validator->after(function (Validator $validator) {
|
||||
if ($this->input('source_academic_term_id') === $this->input('target_academic_term_id')) {
|
||||
$validator->errors()->add('target_academic_term_id', 'Periode tujuan harus berbeda dari periode sumber.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$sourceTerm = AcademicTerm::find($this->input('source_academic_term_id'));
|
||||
$targetTerm = AcademicTerm::find($this->input('target_academic_term_id'));
|
||||
|
||||
if ($sourceTerm && $targetTerm && $sourceTerm->semester !== $targetTerm->semester) {
|
||||
$validator->errors()->add('target_academic_term_id', 'Periode tujuan harus semester yang sama dengan periode sumber (Ganjil ke Ganjil, Genap ke Genap).');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -810,6 +810,15 @@ function DuplicateForm({
|
||||
const [sourceTermId, setSourceTermId] = useState('');
|
||||
const [targetTermId, setTargetTermId] = useState('');
|
||||
|
||||
const sourceTerm = academicTerms.find(
|
||||
(term) => String(term.id) === sourceTermId,
|
||||
);
|
||||
const targetOptions = academicTerms.filter(
|
||||
(term) =>
|
||||
String(term.id) !== sourceTermId &&
|
||||
(!sourceTerm || term.semester === sourceTerm.semester),
|
||||
);
|
||||
|
||||
function reset() {
|
||||
setSourceTermId('');
|
||||
setTargetTermId('');
|
||||
@ -834,8 +843,10 @@ function DuplicateForm({
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Menyalin semua kelas mata kuliah (mata kuliah, dosen
|
||||
pengampu, metode) dari periode sumber ke periode
|
||||
tujuan. Mata kuliah yang sudah punya kelas di periode
|
||||
tujuan akan dilewati.
|
||||
tujuan. Periode tujuan hanya bisa dipilih dari
|
||||
semester yang sama (Ganjil ke Ganjil, Genap ke Genap).
|
||||
Mata kuliah yang sudah punya kelas di periode tujuan
|
||||
akan dilewati.
|
||||
</p>
|
||||
<div className="grid gap-2">
|
||||
<Label>
|
||||
@ -849,7 +860,10 @@ function DuplicateForm({
|
||||
/>
|
||||
<Select
|
||||
value={sourceTermId}
|
||||
onValueChange={setSourceTermId}
|
||||
onValueChange={(value) => {
|
||||
setSourceTermId(value);
|
||||
setTargetTermId('');
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="w-full">
|
||||
<SelectValue placeholder="Pilih periode sumber" />
|
||||
@ -882,12 +896,19 @@ function DuplicateForm({
|
||||
<Select
|
||||
value={targetTermId}
|
||||
onValueChange={setTargetTermId}
|
||||
disabled={!sourceTermId}
|
||||
>
|
||||
<SelectTrigger className="w-full">
|
||||
<SelectValue placeholder="Pilih periode tujuan" />
|
||||
<SelectValue
|
||||
placeholder={
|
||||
sourceTermId
|
||||
? 'Pilih periode tujuan'
|
||||
: 'Pilih periode sumber terlebih dahulu'
|
||||
}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{academicTerms.map((term) => (
|
||||
{targetOptions.map((term) => (
|
||||
<SelectItem
|
||||
key={term.id}
|
||||
value={String(term.id)}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user