Initial commit
This commit is contained in:
@@ -0,0 +1,252 @@
|
||||
<div
|
||||
x-data="studentFormState()"
|
||||
x-init="init()"
|
||||
>
|
||||
<script>
|
||||
function studentFormState() {
|
||||
return {
|
||||
selectedAcademicYear: @js((string) old('academic_year_id', $student->academic_year_id ?? '')),
|
||||
selectedDepartment: @js((string) old('department_id', $student->department_id ?? '')),
|
||||
selectedClass: @js((string) old('class_id', $student->class_id ?? '')),
|
||||
selectedProvince: @js((string) old('province_id', $student->province_id ?? '')),
|
||||
selectedRegency: @js((string) old('regency_id', $student->regency_id ?? '')),
|
||||
selectedDistrict: @js((string) old('district_id', $student->district_id ?? '')),
|
||||
selectedVillage: @js((string) old('village_id', $student->village_id ?? '')),
|
||||
classOptions: @js($classOptions),
|
||||
departments: @js(collect($departments)->map(fn ($name, $id) => ['id' => (string) $id, 'name' => $name])->values()),
|
||||
regencies: [],
|
||||
districts: [],
|
||||
villages: [],
|
||||
loadingRegencies: false,
|
||||
loadingDistricts: false,
|
||||
loadingVillages: false,
|
||||
get filteredDepartments() {
|
||||
if (!this.selectedAcademicYear) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const departmentIds = [...new Set(
|
||||
this.classOptions
|
||||
.filter(item => String(item.academic_year_id) === String(this.selectedAcademicYear))
|
||||
.map(item => String(item.department_id))
|
||||
)];
|
||||
|
||||
return this.departments.filter(item => departmentIds.includes(String(item.id)));
|
||||
},
|
||||
get filteredClasses() {
|
||||
if (!this.selectedAcademicYear || !this.selectedDepartment) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return this.classOptions.filter(item => {
|
||||
const matchAcademicYear = String(item.academic_year_id) === String(this.selectedAcademicYear);
|
||||
const matchDepartment = String(item.department_id) === String(this.selectedDepartment);
|
||||
return matchAcademicYear && matchDepartment;
|
||||
});
|
||||
},
|
||||
get departmentPlaceholder() {
|
||||
if (!this.selectedAcademicYear) {
|
||||
return 'Pilih Tahun Angkatan dulu';
|
||||
}
|
||||
|
||||
if (this.filteredDepartments.length === 0) {
|
||||
return 'Belum ada Program Keahlian untuk Tahun Angkatan ini';
|
||||
}
|
||||
|
||||
return '-- Pilih Program Keahlian --';
|
||||
},
|
||||
get classPlaceholder() {
|
||||
if (!this.selectedAcademicYear) {
|
||||
return 'Pilih Tahun Angkatan dulu';
|
||||
}
|
||||
|
||||
if (!this.selectedDepartment) {
|
||||
return 'Pilih Program Keahlian dulu';
|
||||
}
|
||||
|
||||
if (this.filteredClasses.length === 0) {
|
||||
return 'Belum ada Kelas untuk kombinasi ini';
|
||||
}
|
||||
|
||||
return '-- Pilih Kelas --';
|
||||
},
|
||||
syncDepartmentSelection() {
|
||||
if (!this.selectedAcademicYear) {
|
||||
this.selectedDepartment = '';
|
||||
this.selectedClass = '';
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.selectedDepartment) {
|
||||
this.selectedClass = '';
|
||||
return;
|
||||
}
|
||||
|
||||
const exists = this.filteredDepartments.some(item => String(item.id) === String(this.selectedDepartment));
|
||||
if (!exists) {
|
||||
this.selectedDepartment = '';
|
||||
this.selectedClass = '';
|
||||
}
|
||||
},
|
||||
syncClassSelection() {
|
||||
this.syncDepartmentSelection();
|
||||
if (!this.selectedClass) return;
|
||||
const exists = this.filteredClasses.some(item => String(item.id) === String(this.selectedClass));
|
||||
if (!exists) this.selectedClass = '';
|
||||
},
|
||||
async init() {
|
||||
this.syncDepartmentSelection();
|
||||
this.syncClassSelection();
|
||||
if (this.selectedProvince) await this.loadRegencies(false);
|
||||
if (this.selectedRegency) await this.loadDistricts(false);
|
||||
if (this.selectedDistrict) await this.loadVillages(false);
|
||||
},
|
||||
async loadRegencies(reset = true) {
|
||||
if (reset) {
|
||||
this.selectedRegency = '';
|
||||
this.selectedDistrict = '';
|
||||
this.selectedVillage = '';
|
||||
this.districts = [];
|
||||
this.villages = [];
|
||||
}
|
||||
this.regencies = [];
|
||||
if (!this.selectedProvince) return;
|
||||
this.loadingRegencies = true;
|
||||
const response = await fetch(`/regions/provinces/${this.selectedProvince}/regencies`);
|
||||
this.regencies = await response.json();
|
||||
this.loadingRegencies = false;
|
||||
},
|
||||
async loadDistricts(reset = true) {
|
||||
if (reset) {
|
||||
this.selectedDistrict = '';
|
||||
this.selectedVillage = '';
|
||||
this.villages = [];
|
||||
}
|
||||
this.districts = [];
|
||||
if (!this.selectedRegency) return;
|
||||
this.loadingDistricts = true;
|
||||
const response = await fetch(`/regions/regencies/${this.selectedRegency}/districts`);
|
||||
this.districts = await response.json();
|
||||
this.loadingDistricts = false;
|
||||
},
|
||||
async loadVillages(reset = true) {
|
||||
if (reset) this.selectedVillage = '';
|
||||
this.villages = [];
|
||||
if (!this.selectedDistrict) return;
|
||||
this.loadingVillages = true;
|
||||
const response = await fetch(`/regions/districts/${this.selectedDistrict}/villages`);
|
||||
this.villages = await response.json();
|
||||
this.loadingVillages = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="grid grid-cols-1 gap-6 xl:grid-cols-2">
|
||||
<x-master-card title="Identitas Siswa" subtitle="Data utama identitas dan akademik siswa.">
|
||||
<div class="grid grid-cols-1 gap-5 md:grid-cols-2">
|
||||
<x-form-input name="student_number" label="NIS" :value="$student->student_number ?? ''" placeholder="Nomor induk siswa" />
|
||||
<x-form-input name="nisn" label="NISN" :value="$student->nisn ?? ''" placeholder="Nomor induk siswa nasional" />
|
||||
<div class="md:col-span-2">
|
||||
<x-form-input name="full_name" label="Nama Lengkap" :value="$student->full_name ?? ''" placeholder="Nama lengkap siswa" required />
|
||||
</div>
|
||||
<x-form-select name="gender" label="Jenis Kelamin" :options="$genders" :value="$student->gender ?? null" required />
|
||||
<x-form-select name="status" label="Status Siswa" :options="$statuses" :value="$student->status ?? 'active'" x-ref="statusField" x-on:change="statusValue = $event.target.value" required />
|
||||
<x-form-input name="place_of_birth" label="Tempat Lahir" :value="$student->place_of_birth ?? ''" placeholder="Kota kelahiran" />
|
||||
<x-form-input name="date_of_birth" label="Tanggal Lahir" type="date" :value="isset($student?->date_of_birth) ? $student->date_of_birth?->format('Y-m-d') : ''" />
|
||||
<x-form-select name="religion" label="Agama" :options="$religions" :value="$student->religion ?? null" />
|
||||
<x-form-input name="nationality" label="Kewarganegaraan" :value="$student->nationality ?? 'Indonesia'" placeholder="Contoh: Indonesia" />
|
||||
<x-form-input name="family_card_number" label="No. Kartu Keluarga" :value="$student->family_card_number ?? ''" placeholder="Nomor KK" />
|
||||
<x-form-input name="entry_date" label="Tanggal Masuk" type="date" :value="isset($student?->entry_date) ? $student->entry_date?->format('Y-m-d') : ''" />
|
||||
<x-form-input name="child_order" label="Anak Ke" type="number" :value="$student->child_order ?? ''" placeholder="Contoh: 1" />
|
||||
<x-form-input name="number_of_siblings" label="Jumlah Saudara" type="number" :value="$student->number_of_siblings ?? ''" placeholder="Contoh: 2" />
|
||||
</div>
|
||||
</x-master-card>
|
||||
|
||||
<x-master-card title="Akademik & Kontak" subtitle="Relasi akademik, alamat, dan informasi kontak siswa.">
|
||||
<div class="grid grid-cols-1 gap-5 md:grid-cols-2">
|
||||
<x-form-select name="academic_year_id" label="Tahun Angkatan" :options="$academicYears->all()" :value="$student->academic_year_id ?? null" x-model="selectedAcademicYear" x-on:change="syncDepartmentSelection(); syncClassSelection()" required />
|
||||
|
||||
<div>
|
||||
<label for="department_id" class="mb-2 block text-sm font-medium text-slate-700">Program Keahlian</label>
|
||||
<select id="department_id" name="department_id" x-model="selectedDepartment" x-on:change="syncClassSelection()" class="h-12 w-full rounded-2xl border border-slate-200 bg-white px-4 text-sm text-slate-700 focus:border-indigo-300 focus:outline-none focus:ring-4 focus:ring-indigo-100 disabled:cursor-not-allowed disabled:bg-slate-100 disabled:text-slate-400" :disabled="!selectedAcademicYear || filteredDepartments.length === 0" required>
|
||||
<option value="" x-text="departmentPlaceholder"></option>
|
||||
<template x-for="department in filteredDepartments" :key="department.id">
|
||||
<option :value="department.id" x-text="department.name"></option>
|
||||
</template>
|
||||
</select>
|
||||
<p class="mt-2 text-xs text-slate-500" x-text="!selectedAcademicYear ? 'Pilih Tahun Angkatan terlebih dahulu untuk membuka daftar Program Keahlian.' : (filteredDepartments.length === 0 ? 'Belum ada kelas yang menghubungkan Tahun Angkatan ini dengan Program Keahlian mana pun.' : 'Program Keahlian difilter otomatis berdasarkan Tahun Angkatan yang dipilih.')"></p>
|
||||
<x-input-error :messages="$errors->get('department_id')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="class_id" class="mb-2 block text-sm font-medium text-slate-700">Kelas</label>
|
||||
<select id="class_id" name="class_id" x-model="selectedClass" class="h-12 w-full rounded-2xl border border-slate-200 bg-white px-4 text-sm text-slate-700 focus:border-indigo-300 focus:outline-none focus:ring-4 focus:ring-indigo-100 disabled:cursor-not-allowed disabled:bg-slate-100 disabled:text-slate-400" :disabled="!selectedAcademicYear || !selectedDepartment || filteredClasses.length === 0" required>
|
||||
<option value="" x-text="classPlaceholder"></option>
|
||||
<template x-for="classOption in filteredClasses" :key="classOption.id">
|
||||
<option :value="classOption.id" x-text="classOption.name"></option>
|
||||
</template>
|
||||
</select>
|
||||
<p class="mt-2 text-xs text-slate-500" x-text="!selectedAcademicYear ? 'Pilih Tahun Angkatan terlebih dahulu.' : (!selectedDepartment ? 'Pilih Program Keahlian terlebih dahulu.' : (filteredClasses.length === 0 ? 'Belum ada kelas aktif untuk kombinasi Tahun Angkatan dan Program Keahlian ini.' : 'Hanya kelas yang cocok dengan kombinasi pilihan yang ditampilkan.'))"></p>
|
||||
<x-input-error :messages="$errors->get('class_id')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<x-form-input name="phone_number" label="No. HP" :value="$student->phone_number ?? ''" placeholder="Nomor HP siswa" />
|
||||
<x-form-input name="email" label="Email" type="email" :value="$student->email ?? ''" placeholder="Alamat email" />
|
||||
|
||||
<div>
|
||||
<label for="province_id" class="mb-2 block text-sm font-medium text-slate-700">Provinsi</label>
|
||||
<select id="province_id" name="province_id" x-model="selectedProvince" @change="loadRegencies()" class="h-12 w-full rounded-2xl border border-slate-200 bg-white px-4 text-sm text-slate-700 focus:border-indigo-300 focus:outline-none focus:ring-4 focus:ring-indigo-100">
|
||||
<option value="">-- Pilih Provinsi --</option>
|
||||
@foreach($provinces as $id => $name)
|
||||
<option value="{{ $id }}">{{ $name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="regency_id" class="mb-2 block text-sm font-medium text-slate-700">Kota/Kabupaten</label>
|
||||
<select id="regency_id" name="regency_id" x-model="selectedRegency" @change="loadDistricts()" class="h-12 w-full rounded-2xl border border-slate-200 bg-white px-4 text-sm text-slate-700 focus:border-indigo-300 focus:outline-none focus:ring-4 focus:ring-indigo-100">
|
||||
<option value="" x-text="loadingRegencies ? 'Memuat...' : '-- Pilih Kota/Kabupaten --'"></option>
|
||||
<template x-for="regency in regencies" :key="regency.id">
|
||||
<option :value="regency.id" x-text="regency.name"></option>
|
||||
</template>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="district_id" class="mb-2 block text-sm font-medium text-slate-700">Kecamatan</label>
|
||||
<select id="district_id" name="district_id" x-model="selectedDistrict" @change="loadVillages()" class="h-12 w-full rounded-2xl border border-slate-200 bg-white px-4 text-sm text-slate-700 focus:border-indigo-300 focus:outline-none focus:ring-4 focus:ring-indigo-100">
|
||||
<option value="" x-text="loadingDistricts ? 'Memuat...' : '-- Pilih Kecamatan --'"></option>
|
||||
<template x-for="district in districts" :key="district.id">
|
||||
<option :value="district.id" x-text="district.name"></option>
|
||||
</template>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="village_id" class="mb-2 block text-sm font-medium text-slate-700">Desa/Kelurahan</label>
|
||||
<select id="village_id" name="village_id" x-model="selectedVillage" class="h-12 w-full rounded-2xl border border-slate-200 bg-white px-4 text-sm text-slate-700 focus:border-indigo-300 focus:outline-none focus:ring-4 focus:ring-indigo-100">
|
||||
<option value="" x-text="loadingVillages ? 'Memuat...' : '-- Pilih Desa/Kelurahan --'"></option>
|
||||
<template x-for="village in villages" :key="village.id">
|
||||
<option :value="village.id" x-text="village.name"></option>
|
||||
</template>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<x-form-input name="postal_code" label="Kode Pos" :value="$student->postal_code ?? ''" placeholder="Kode pos" />
|
||||
<div class="md:col-span-2">
|
||||
<x-form-textarea name="address" label="Alamat" :value="$student->address ?? ''" placeholder="Alamat lengkap siswa" rows="4" />
|
||||
</div>
|
||||
<div class="md:col-span-2">
|
||||
<x-form-textarea name="notes" label="Catatan" :value="$student->notes ?? ''" placeholder="Catatan tambahan terkait siswa" rows="4" />
|
||||
</div>
|
||||
</div>
|
||||
</x-master-card>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex flex-wrap items-center gap-3">
|
||||
<button type="submit" class="rounded-2xl bg-indigo-600 px-5 py-3 text-sm font-semibold text-white shadow-lg shadow-indigo-200 transition hover:bg-indigo-700">{{ $submitLabel }}</button>
|
||||
<a href="{{ route('students.index') }}" class="rounded-2xl border border-slate-200 px-5 py-3 text-sm font-semibold text-slate-700 transition hover:bg-slate-50">Batal</a>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user