FINAL MAYBE
This commit is contained in:
parent
a7e4d0e5f0
commit
24a7387cfb
26
.env.example
26
.env.example
|
|
@ -1,6 +1,6 @@
|
|||
APP_NAME=Laravel
|
||||
APP_ENV=local
|
||||
APP_KEY=
|
||||
APP_KEY=base64:/f9/a5B/t+4N0BXg4HKByxd0go5w25WDnaWeQW3hnfk=
|
||||
APP_DEBUG=true
|
||||
APP_URL=http://localhost
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ LOG_LEVEL=debug
|
|||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=laravel
|
||||
DB_DATABASE=db_rekomendasi_polije
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=
|
||||
|
||||
|
|
@ -28,14 +28,18 @@ REDIS_HOST=127.0.0.1
|
|||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
GEMINI_API_KEY=AIzaSyBAY6QGk0dbHDrLHya7qeu4JdMJEbxeUoM
|
||||
GEMINI_BACKEND_URL=http://127.0.0.1:5000
|
||||
GEMINI_BACKEND_TOKEN=
|
||||
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=mailpit
|
||||
MAIL_PORT=1025
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
MAIL_FROM_ADDRESS="hello@example.com"
|
||||
MAIL_FROM_NAME="${APP_NAME}"
|
||||
MAIL_HOST=smtp.gmail.com
|
||||
MAIL_PORT=587
|
||||
MAIL_USERNAME=kakapatria22@gmail.com
|
||||
MAIL_PASSWORD=midpucucemcvtozu
|
||||
MAIL_ENCRYPTION=tls
|
||||
MAIL_FROM_ADDRESS=kakapatria22@gmail.com
|
||||
MAIL_FROM_NAME="SPK Jurusan Polije"
|
||||
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
|
|
@ -56,7 +60,3 @@ VITE_PUSHER_HOST="${PUSHER_HOST}"
|
|||
VITE_PUSHER_PORT="${PUSHER_PORT}"
|
||||
VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"
|
||||
VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
||||
|
||||
GEMINI_API_KEY=
|
||||
GEMINI_BACKEND_URL=http://127.0.0.1:8001
|
||||
GEMINI_BACKEND_TOKEN=
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
{"version":2,"defects":[],"times":{"Tests\\Unit\\ExampleTest::test_that_true_is_true":1.142,"Tests\\Unit\\RekomendasiAlgorithmTest::test_minat_mapping_logika_komputer":1.83,"Tests\\Unit\\RekomendasiAlgorithmTest::test_minat_mapping_alam_tanaman":0.001,"Tests\\Unit\\RekomendasiAlgorithmTest::test_minat_mapping_bisnis":0.001,"Tests\\Unit\\RekomendasiAlgorithmTest::test_nilai_kategori_tinggi":0,"Tests\\Unit\\RekomendasiAlgorithmTest::test_nilai_kategori_sedang":0,"Tests\\Unit\\RekomendasiAlgorithmTest::test_nilai_kategori_rendah":0,"Tests\\Unit\\RekomendasiAlgorithmTest::test_prestasi_scoring_tinggi":0.326,"Tests\\Unit\\RekomendasiAlgorithmTest::test_prestasi_scoring_sedang":0,"Tests\\Unit\\RekomendasiAlgorithmTest::test_prestasi_scoring_minimal":0.055,"Tests\\Feature\\Auth\\AuthenticationTest::test_login_screen_can_be_rendered":9.692,"Tests\\Feature\\Auth\\AuthenticationTest::test_users_can_authenticate_using_the_login_screen":6.712,"Tests\\Feature\\Auth\\AuthenticationTest::test_users_can_not_authenticate_with_invalid_password":0.471,"Tests\\Feature\\Auth\\AuthenticationTest::test_users_can_logout":0.172,"Tests\\Feature\\Auth\\EmailVerificationTest::test_email_verification_screen_can_be_rendered":1.41,"Tests\\Feature\\Auth\\EmailVerificationTest::test_email_can_be_verified":0.494,"Tests\\Feature\\Auth\\EmailVerificationTest::test_email_is_not_verified_with_invalid_hash":0.581,"Tests\\Feature\\Auth\\PasswordConfirmationTest::test_confirm_password_screen_can_be_rendered":1.132,"Tests\\Feature\\Auth\\PasswordConfirmationTest::test_password_can_be_confirmed":0.12,"Tests\\Feature\\Auth\\PasswordConfirmationTest::test_password_is_not_confirmed_with_invalid_password":0.217,"Tests\\Feature\\Auth\\PasswordResetTest::test_reset_password_link_screen_can_be_rendered":1.654,"Tests\\Feature\\Auth\\PasswordResetTest::test_reset_password_link_can_be_requested":3.132,"Tests\\Feature\\Auth\\PasswordResetTest::test_reset_password_screen_can_be_rendered":1.884,"Tests\\Feature\\Auth\\PasswordResetTest::test_password_can_be_reset_with_valid_token":0.498,"Tests\\Feature\\Auth\\PasswordUpdateTest::test_password_can_be_updated":0.196,"Tests\\Feature\\Auth\\PasswordUpdateTest::test_correct_password_must_be_provided_to_update_password":0.175,"Tests\\Feature\\Auth\\RegistrationTest::test_registration_screen_can_be_rendered":0.204,"Tests\\Feature\\Auth\\RegistrationTest::test_new_users_can_register":0.104,"Tests\\Feature\\CrudValidationTest::test_admin_can_add_jurusan_data":0.229,"Tests\\Feature\\CrudValidationTest::test_bk_can_add_jurusan_data":0.058,"Tests\\Feature\\CrudValidationTest::test_admin_guru_bk_store_validates_email_and_password":0.206,"Tests\\Feature\\CrudValidationTest::test_rekomendasi_ipa_requires_all_ipa_scores":0.014,"Tests\\Feature\\CrudValidationTest::test_admin_student_detail_only_accepts_siswa_id":0.21,"Tests\\Feature\\ExampleTest::test_the_application_returns_a_successful_response":0.122,"Tests\\Feature\\ExplainableRecommendationTest::test_recommendation_includes_explanation":1.773,"Tests\\Feature\\ExplainableRecommendationTest::test_scoring_detail_stored_correctly":0.989,"Tests\\Feature\\ExplainableRecommendationTest::test_all_recommendations_have_explanations":0.027,"Tests\\Feature\\ExplainableRecommendationTest::test_explanation_displayed_in_view":0.021,"Tests\\Feature\\ProfileTest::test_profile_page_is_displayed":0.466,"Tests\\Feature\\ProfileTest::test_profile_information_can_be_updated":0.3,"Tests\\Feature\\ProfileTest::test_email_verification_status_is_unchanged_when_the_email_address_is_unchanged":0.216,"Tests\\Feature\\ProfileTest::test_user_can_delete_their_account":0.118,"Tests\\Feature\\ProfileTest::test_correct_password_must_be_provided_to_delete_account":0.141,"Tests\\Feature\\RekomendasiTest::test_high_math_and_coding_prefers_teknologi_informasi":0.223,"Tests\\Feature\\RekomendasiTest::test_high_language_prefers_bahasa_komunikasi":0.021,"Tests\\Feature\\UserFlowTest::test_siswa_complete_flow":1.02,"Tests\\Feature\\UserFlowTest::test_bk_complete_flow":2.378,"Tests\\Feature\\UserFlowTest::test_admin_complete_flow":2.52,"Tests\\Feature\\UserFlowTest::test_access_control":0.023}}
|
||||
{"version":2,"defects":[],"times":{"Tests\\Unit\\ExampleTest::test_that_true_is_true":0.024,"Tests\\Unit\\RekomendasiAlgorithmTest::test_minat_mapping_logika_komputer":0.026,"Tests\\Unit\\RekomendasiAlgorithmTest::test_minat_mapping_alam_tanaman":0.001,"Tests\\Unit\\RekomendasiAlgorithmTest::test_minat_mapping_bisnis":0.001,"Tests\\Unit\\RekomendasiAlgorithmTest::test_nilai_kategori_tinggi":0,"Tests\\Unit\\RekomendasiAlgorithmTest::test_nilai_kategori_sedang":0.001,"Tests\\Unit\\RekomendasiAlgorithmTest::test_nilai_kategori_rendah":0.001,"Tests\\Unit\\RekomendasiAlgorithmTest::test_prestasi_scoring_tinggi":0.008,"Tests\\Unit\\RekomendasiAlgorithmTest::test_prestasi_scoring_sedang":0.001,"Tests\\Unit\\RekomendasiAlgorithmTest::test_prestasi_scoring_minimal":0.002,"Tests\\Feature\\Auth\\AuthenticationTest::test_login_screen_can_be_rendered":0.115,"Tests\\Feature\\Auth\\AuthenticationTest::test_users_can_authenticate_using_the_login_screen":0.245,"Tests\\Feature\\Auth\\AuthenticationTest::test_users_can_not_authenticate_with_invalid_password":0.229,"Tests\\Feature\\Auth\\AuthenticationTest::test_users_can_logout":0.011,"Tests\\Feature\\Auth\\EmailVerificationTest::test_email_verification_screen_can_be_rendered":0.019,"Tests\\Feature\\Auth\\EmailVerificationTest::test_email_can_be_verified":0.015,"Tests\\Feature\\Auth\\EmailVerificationTest::test_email_is_not_verified_with_invalid_hash":0.017,"Tests\\Feature\\Auth\\PasswordConfirmationTest::test_confirm_password_screen_can_be_rendered":0.022,"Tests\\Feature\\Auth\\PasswordConfirmationTest::test_password_can_be_confirmed":0.123,"Tests\\Feature\\Auth\\PasswordConfirmationTest::test_password_is_not_confirmed_with_invalid_password":0.209,"Tests\\Feature\\Auth\\PasswordResetTest::test_reset_password_link_screen_can_be_rendered":0.015,"Tests\\Feature\\Auth\\PasswordResetTest::test_reset_password_link_can_be_requested":0.07,"Tests\\Feature\\Auth\\PasswordResetTest::test_reset_password_screen_can_be_rendered":0.029,"Tests\\Feature\\Auth\\PasswordResetTest::test_password_can_be_reset_with_valid_token":0.034,"Tests\\Feature\\Auth\\PasswordUpdateTest::test_password_can_be_updated":0.119,"Tests\\Feature\\Auth\\PasswordUpdateTest::test_correct_password_must_be_provided_to_update_password":0.129,"Tests\\Feature\\Auth\\RegistrationTest::test_registration_screen_can_be_rendered":0.008,"Tests\\Feature\\Auth\\RegistrationTest::test_new_users_can_register":0.015,"Tests\\Feature\\CrudValidationTest::test_admin_can_add_jurusan_data":0.012,"Tests\\Feature\\CrudValidationTest::test_bk_can_add_jurusan_data":0.016,"Tests\\Feature\\CrudValidationTest::test_admin_guru_bk_store_validates_email_and_password":0.015,"Tests\\Feature\\CrudValidationTest::test_rekomendasi_ipa_requires_all_ipa_scores":0.015,"Tests\\Feature\\CrudValidationTest::test_admin_student_detail_only_accepts_siswa_id":0.024,"Tests\\Feature\\ExampleTest::test_the_application_returns_a_successful_response":0.007,"Tests\\Feature\\ExplainableRecommendationTest::test_recommendation_includes_explanation":0.036,"Tests\\Feature\\ExplainableRecommendationTest::test_scoring_detail_stored_correctly":0.02,"Tests\\Feature\\ExplainableRecommendationTest::test_all_recommendations_have_explanations":0.024,"Tests\\Feature\\ExplainableRecommendationTest::test_explanation_displayed_in_view":0.026,"Tests\\Feature\\ProfileTest::test_profile_page_is_displayed":0.01,"Tests\\Feature\\ProfileTest::test_profile_information_can_be_updated":0.016,"Tests\\Feature\\ProfileTest::test_email_verification_status_is_unchanged_when_the_email_address_is_unchanged":0.009,"Tests\\Feature\\ProfileTest::test_user_can_delete_their_account":0.21,"Tests\\Feature\\ProfileTest::test_correct_password_must_be_provided_to_delete_account":0.148,"Tests\\Feature\\RekomendasiTest::test_high_math_and_coding_prefers_teknologi_informasi":0.06,"Tests\\Feature\\RekomendasiTest::test_high_language_prefers_bahasa_komunikasi":0.019,"Tests\\Feature\\UserFlowTest::test_siswa_complete_flow":0.055,"Tests\\Feature\\UserFlowTest::test_bk_complete_flow":0.072,"Tests\\Feature\\UserFlowTest::test_admin_complete_flow":0.09,"Tests\\Feature\\UserFlowTest::test_access_control":0.027}}
|
||||
Binary file not shown.
|
|
@ -0,0 +1,240 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use App\Models\Alumni;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use PhpOffice\PhpSpreadsheet\IOFactory;
|
||||
|
||||
class ImportAlumni extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'alumni:import {file : Path to Excel file}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Import data alumni dari file Excel ke database';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$filePath = $this->argument('file');
|
||||
|
||||
// Check if file exists
|
||||
if (!file_exists($filePath)) {
|
||||
$this->error("❌ File tidak ditemukan: {$filePath}");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Check if file is Excel
|
||||
$ext = pathinfo($filePath, PATHINFO_EXTENSION);
|
||||
if (!in_array(strtolower($ext), ['xlsx', 'xls', 'csv'])) {
|
||||
$this->error("❌ Format file tidak didukung. Gunakan .xlsx, .xls, atau .csv");
|
||||
return 1;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->info("📂 Membaca file: {$filePath}");
|
||||
|
||||
// Read Excel file
|
||||
$spreadsheet = IOFactory::load($filePath);
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$data = $sheet->toArray();
|
||||
|
||||
if (count($data) < 2) {
|
||||
$this->error("❌ File Excel kosong atau hanya memiliki header");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Get headers
|
||||
$headers = array_map('strtolower', $data[0]);
|
||||
$headers = array_map(fn($h) => trim(str_replace([' ', '-', '_'], '_', $h)), $headers);
|
||||
|
||||
$this->line("✓ Header ditemukan: " . implode(', ', $headers));
|
||||
|
||||
// Normalize column mapping
|
||||
$columnMap = $this->normalizeColumns($headers);
|
||||
$this->line("✓ Kolom di-mapping");
|
||||
|
||||
// Process rows
|
||||
$rows = array_slice($data, 1);
|
||||
$successCount = 0;
|
||||
$errorCount = 0;
|
||||
$errors = [];
|
||||
|
||||
$this->info("\n📊 Memproses " . count($rows) . " baris data...");
|
||||
|
||||
// Progress bar
|
||||
$bar = $this->output->createProgressBar(count($rows));
|
||||
$bar->start();
|
||||
|
||||
foreach ($rows as $idx => $row) {
|
||||
$record = $this->mapRow($row, $headers, $columnMap);
|
||||
|
||||
if ($record === null || empty($record['nama_alumni'])) {
|
||||
$bar->advance();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Validate required fields
|
||||
$validator = Validator::make($record, [
|
||||
'nama_alumni' => 'required|string',
|
||||
'nis' => 'nullable|string',
|
||||
'kelompok_asal' => 'nullable|string',
|
||||
'nilai_rata_rata' => 'nullable|numeric',
|
||||
'minat' => 'nullable|string',
|
||||
'cita_cita' => 'nullable|string',
|
||||
'preferensi_studi' => 'nullable|string',
|
||||
'prestasi' => 'nullable|string',
|
||||
'major_masuk' => 'nullable|string',
|
||||
'tahun_lulus_polije' => 'nullable|numeric',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
$errorCount++;
|
||||
$errors[] = "Baris " . ($idx + 2) . ": " . implode(', ', $validator->errors()->all());
|
||||
$bar->advance();
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
// Check if already exists
|
||||
$existing = Alumni::where('nis', $record['nis'] ?? null)
|
||||
->where('nama_alumni', $record['nama_alumni'] ?? null)
|
||||
->first();
|
||||
|
||||
if (!$existing) {
|
||||
Alumni::create($record);
|
||||
$successCount++;
|
||||
} else {
|
||||
// Update jika sudah ada
|
||||
$existing->update($record);
|
||||
$successCount++;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$errorCount++;
|
||||
$errors[] = "Baris " . ($idx + 2) . ": " . $e->getMessage();
|
||||
}
|
||||
|
||||
$bar->advance();
|
||||
}
|
||||
|
||||
$bar->finish();
|
||||
|
||||
// Summary
|
||||
$this->newLine(2);
|
||||
$this->info("=" . str_repeat("=", 58) . "=");
|
||||
$this->info("✓ IMPORT SELESAI");
|
||||
$this->info("=" . str_repeat("=", 58) . "=");
|
||||
$this->line("✓ Data berhasil di-import: {$successCount}");
|
||||
if ($errorCount > 0) {
|
||||
$this->line("⚠ Baris error/skip: {$errorCount}");
|
||||
|
||||
if (count($errors) > 0 && count($errors) <= 20) {
|
||||
$this->newLine();
|
||||
$this->warn("Errors:");
|
||||
foreach ($errors as $error) {
|
||||
$this->line(" - {$error}");
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->newLine();
|
||||
|
||||
return 0;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$this->error("❌ Error: " . $e->getMessage());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize column headers to database column names
|
||||
*/
|
||||
private function normalizeColumns($headers)
|
||||
{
|
||||
$mapping = [
|
||||
'nama' => 'nama_alumni',
|
||||
'nama_alumni' => 'nama_alumni',
|
||||
'nis' => 'nis',
|
||||
'no_induk_siswa' => 'nis',
|
||||
'kelompok_asal' => 'kelompok_asal',
|
||||
'kelompok' => 'kelompok_asal',
|
||||
'nilai_(rata_rata)' => 'nilai_rata_rata',
|
||||
'nilai_rata_rata' => 'nilai_rata_rata',
|
||||
'rata_rata' => 'nilai_rata_rata',
|
||||
'average' => 'nilai_rata_rata',
|
||||
'minat' => 'minat',
|
||||
'interest' => 'minat',
|
||||
'cita_cita' => 'cita_cita',
|
||||
'cita' => 'cita_cita',
|
||||
'dream_job' => 'cita_cita',
|
||||
'preferensi_studi' => 'preferensi_studi',
|
||||
'preferensi' => 'preferensi_studi',
|
||||
'preference' => 'preferensi_studi',
|
||||
'prestasi' => 'prestasi',
|
||||
'achievement' => 'prestasi',
|
||||
'major_masuk' => 'major_masuk',
|
||||
'jurusan_masuk' => 'major_masuk',
|
||||
'jurusan_keterima_di_polije' => 'major_masuk',
|
||||
'jurusan' => 'major_masuk',
|
||||
'major' => 'major_masuk',
|
||||
'tahun_lulus_polije' => 'tahun_lulus_polije',
|
||||
'tahun_lulus' => 'tahun_lulus_polije',
|
||||
'graduation_year' => 'tahun_lulus_polije',
|
||||
'tahun' => 'tahun_lulus_polije',
|
||||
'catatan' => 'catatan',
|
||||
'keterangan' => 'catatan',
|
||||
'notes' => 'catatan',
|
||||
];
|
||||
|
||||
return $mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map row data to Alumni model
|
||||
*/
|
||||
private function mapRow($row, $headers, $columnMap)
|
||||
{
|
||||
$record = [];
|
||||
|
||||
foreach ($headers as $idx => $header) {
|
||||
$value = $row[$idx] ?? null;
|
||||
|
||||
// Map column name
|
||||
$dbColumn = $columnMap[strtolower($header)] ?? null;
|
||||
|
||||
if (!$dbColumn) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Type conversion
|
||||
if (in_array($dbColumn, ['nilai_rata_rata', 'tahun_lulus_polije'])) {
|
||||
$record[$dbColumn] = $value ? (float) $value : null;
|
||||
} else {
|
||||
$cleanValue = $value ? trim((string) $value) : null;
|
||||
|
||||
// Special handling for preferensi_studi - truncate to enum value
|
||||
if ($dbColumn === 'preferensi_studi' && $cleanValue) {
|
||||
// Extract only the category part (before the parenthesis)
|
||||
$parts = explode('(', $cleanValue);
|
||||
$cleanValue = trim($parts[0]);
|
||||
}
|
||||
|
||||
$record[$dbColumn] = $cleanValue;
|
||||
}
|
||||
}
|
||||
|
||||
return empty($record['nama_alumni'] ?? null) ? null : $record;
|
||||
}
|
||||
}
|
||||
|
|
@ -155,18 +155,21 @@ public function jurusanStore(Request $request)
|
|||
{
|
||||
$request->validate([
|
||||
'nama_jurusan' => 'required|string|min:3|max:255|unique:jurusan_polije,nama_jurusan',
|
||||
'deskripsi' => 'nullable|string|max:1000',
|
||||
'deskripsi' => 'nullable|string|max:10000',
|
||||
'keywords' => 'nullable|string',
|
||||
'preferensi_studi' => 'nullable|string',
|
||||
'prospek_kerja' => 'nullable|string|max:1000',
|
||||
'bobot_mtk' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_fisika' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_kimia' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_biologi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_ekonomi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_geografi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_sosiologi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_sejarah' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel' => 'nullable|array',
|
||||
'bobot_mapel.ipa' => 'nullable|array',
|
||||
'bobot_mapel.ipa.mtk' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel.ipa.fisika' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel.ipa.kimia' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel.ipa.biologi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel.ips' => 'nullable|array',
|
||||
'bobot_mapel.ips.ekonomi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel.ips.geografi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel.ips.sosiologi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel.ips.sejarah' => 'nullable|numeric|min:0|max:1',
|
||||
]);
|
||||
|
||||
PolijeMajor::create([
|
||||
|
|
@ -193,18 +196,21 @@ public function jurusanUpdate(Request $request, $id)
|
|||
|
||||
$request->validate([
|
||||
'nama_jurusan' => ['required', 'string', 'min:3', 'max:255', Rule::unique('jurusan_polije', 'nama_jurusan')->ignore($jurusan->id)],
|
||||
'deskripsi' => 'nullable|string|max:1000',
|
||||
'deskripsi' => 'nullable|string|max:10000',
|
||||
'keywords' => 'nullable|string',
|
||||
'preferensi_studi' => 'nullable|string',
|
||||
'prospek_kerja' => 'nullable|string|max:1000',
|
||||
'bobot_mtk' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_fisika' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_kimia' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_biologi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_ekonomi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_geografi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_sosiologi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_sejarah' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel' => 'nullable|array',
|
||||
'bobot_mapel.ipa' => 'nullable|array',
|
||||
'bobot_mapel.ipa.mtk' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel.ipa.fisika' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel.ipa.kimia' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel.ipa.biologi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel.ips' => 'nullable|array',
|
||||
'bobot_mapel.ips.ekonomi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel.ips.geografi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel.ips.sosiologi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel.ips.sejarah' => 'nullable|numeric|min:0|max:1',
|
||||
]);
|
||||
|
||||
$jurusan->update([
|
||||
|
|
@ -243,17 +249,45 @@ private function parseTagInput(?string $input): array
|
|||
*/
|
||||
private function parseBobotMapel(Request $request): array
|
||||
{
|
||||
$mapelList = ['mtk', 'fisika', 'kimia', 'biologi', 'ekonomi', 'geografi', 'sosiologi', 'sejarah'];
|
||||
$bobot = [];
|
||||
$ipaSubjects = ['mtk', 'fisika', 'kimia', 'biologi'];
|
||||
$ipsSubjects = ['ekonomi', 'geografi', 'sosiologi', 'sejarah'];
|
||||
|
||||
foreach ($mapelList as $mapel) {
|
||||
$value = $request->input("bobot_{$mapel}");
|
||||
if (!is_null($value) && $value !== '') {
|
||||
$bobot[$mapel] = floatval($value);
|
||||
}
|
||||
$ipaInput = $request->input('bobot_mapel.ipa');
|
||||
$ipsInput = $request->input('bobot_mapel.ips');
|
||||
|
||||
if (is_array($ipaInput) || is_array($ipsInput)) {
|
||||
return [
|
||||
'ipa' => $this->normalizeBobotGroup(is_array($ipaInput) ? $ipaInput : [], $ipaSubjects),
|
||||
'ips' => $this->normalizeBobotGroup(is_array($ipsInput) ? $ipsInput : [], $ipsSubjects),
|
||||
];
|
||||
}
|
||||
|
||||
return $bobot;
|
||||
return [
|
||||
'ipa' => $this->normalizeBobotGroup([
|
||||
'mtk' => $request->input('bobot_mtk'),
|
||||
'fisika' => $request->input('bobot_fisika'),
|
||||
'kimia' => $request->input('bobot_kimia'),
|
||||
'biologi' => $request->input('bobot_biologi'),
|
||||
], $ipaSubjects),
|
||||
'ips' => $this->normalizeBobotGroup([
|
||||
'ekonomi' => $request->input('bobot_ekonomi'),
|
||||
'geografi' => $request->input('bobot_geografi'),
|
||||
'sosiologi' => $request->input('bobot_sosiologi'),
|
||||
'sejarah' => $request->input('bobot_sejarah'),
|
||||
], $ipsSubjects),
|
||||
];
|
||||
}
|
||||
|
||||
private function normalizeBobotGroup(array $values, array $subjects): array
|
||||
{
|
||||
$normalized = [];
|
||||
|
||||
foreach ($subjects as $subject) {
|
||||
$value = $values[$subject] ?? null;
|
||||
$normalized[$subject] = is_numeric($value) ? (float) $value : 0.0;
|
||||
}
|
||||
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
|
|
|
|||
|
|
@ -7,6 +7,37 @@
|
|||
|
||||
class AlumniController extends Controller
|
||||
{
|
||||
private const IPA_SUBJECTS = ['mtk', 'fisika', 'kimia', 'biologi'];
|
||||
private const IPS_SUBJECTS = ['ekonomi', 'geografi', 'sosiologi', 'sejarah'];
|
||||
|
||||
private const ALL_SUBJECTS = ['mtk', 'fisika', 'kimia', 'biologi', 'ekonomi', 'geografi', 'sosiologi', 'sejarah'];
|
||||
|
||||
private function normalizeScoreFields(array $validated, string $kelompokAsal): array
|
||||
{
|
||||
$activeSubjects = $kelompokAsal === 'IPA' ? self::IPA_SUBJECTS : self::IPS_SUBJECTS;
|
||||
|
||||
foreach (self::ALL_SUBJECTS as $subject) {
|
||||
if (!in_array($subject, $activeSubjects, true)) {
|
||||
$validated[$subject] = null;
|
||||
}
|
||||
}
|
||||
|
||||
return $validated;
|
||||
}
|
||||
|
||||
private function validateScoreByKelompok(Request $request): void
|
||||
{
|
||||
$requiredSubjects = $request->input('kelompok_asal') === 'IPA'
|
||||
? self::IPA_SUBJECTS
|
||||
: self::IPS_SUBJECTS;
|
||||
|
||||
foreach ($requiredSubjects as $subject) {
|
||||
$request->validate([
|
||||
$subject => 'required|numeric|min:0|max:100',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display alumni data list
|
||||
*/
|
||||
|
|
@ -48,7 +79,7 @@ public function store(Request $request)
|
|||
// Non-akademik
|
||||
'minat' => 'nullable|string|max:255',
|
||||
'cita_cita' => 'nullable|string|max:255',
|
||||
'preferensi_studi' => 'nullable|in:Sains & Teknologi,Pertanian & Lingkungan,Kesehatan & Ilmu Hayat,Bisnis & Manajemen,Sosial & Humaniora',
|
||||
'preferensi_studi' => 'nullable|in:Praktik Langsung,Praktik_Langsung,DuDi,Project Based,Project_Based,Blended Learning,Blended',
|
||||
'prestasi' => 'nullable|string|max:255',
|
||||
|
||||
// Major
|
||||
|
|
@ -57,6 +88,9 @@ public function store(Request $request)
|
|||
'catatan' => 'nullable|string|max:500',
|
||||
]);
|
||||
|
||||
$this->validateScoreByKelompok($request);
|
||||
$validated = $this->normalizeScoreFields($validated, $validated['kelompok_asal']);
|
||||
|
||||
Alumni::create($validated);
|
||||
|
||||
return redirect()->route('admin.alumni.index')->with('success', 'Alumni berhasil ditambahkan');
|
||||
|
|
@ -99,7 +133,7 @@ public function update(Request $request, Alumni $alumni)
|
|||
|
||||
'minat' => 'nullable|string|max:255',
|
||||
'cita_cita' => 'nullable|string|max:255',
|
||||
'preferensi_studi' => 'nullable|in:Sains & Teknologi,Pertanian & Lingkungan,Kesehatan & Ilmu Hayat,Bisnis & Manajemen,Sosial & Humaniora',
|
||||
'preferensi_studi' => 'nullable|in:Praktik Langsung,Praktik_Langsung,DuDi,Project Based,Project_Based,Blended Learning,Blended',
|
||||
'prestasi' => 'nullable|string|max:255',
|
||||
|
||||
'major_masuk' => 'required|string|min:3|max:255',
|
||||
|
|
@ -107,6 +141,9 @@ public function update(Request $request, Alumni $alumni)
|
|||
'catatan' => 'nullable|string|max:500',
|
||||
]);
|
||||
|
||||
$this->validateScoreByKelompok($request);
|
||||
$validated = $this->normalizeScoreFields($validated, $validated['kelompok_asal']);
|
||||
|
||||
$alumni->update($validated);
|
||||
|
||||
return redirect()->route('admin.alumni.index')->with('success', 'Alumni berhasil diupdate');
|
||||
|
|
|
|||
|
|
@ -0,0 +1,198 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Alumni;
|
||||
use Illuminate\Http\Request;
|
||||
use PhpOffice\PhpSpreadsheet\IOFactory;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class AlumniImportController extends Controller
|
||||
{
|
||||
/**
|
||||
* Show upload form
|
||||
*/
|
||||
public function showForm()
|
||||
{
|
||||
return view('alumni.import-form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle file upload & import
|
||||
*/
|
||||
public function import(Request $request)
|
||||
{
|
||||
// Validate file
|
||||
$validator = Validator::make($request->all(), [
|
||||
'file' => 'required|file|mimes:xlsx,xls,csv|max:10240', // max 10MB
|
||||
], [
|
||||
'file.required' => 'File harus dipilih',
|
||||
'file.mimes' => 'File harus format .xlsx, .xls, atau .csv',
|
||||
'file.max' => 'File tidak boleh lebih dari 10MB',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return back()
|
||||
->withErrors($validator)
|
||||
->withInput();
|
||||
}
|
||||
|
||||
try {
|
||||
$file = $request->file('file');
|
||||
$filePath = $file->store('temp', 'local');
|
||||
$fullPath = storage_path('app/' . $filePath);
|
||||
|
||||
// Read Excel
|
||||
$spreadsheet = IOFactory::load($fullPath);
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$data = $sheet->toArray();
|
||||
|
||||
if (count($data) < 2) {
|
||||
return back()->with('error', 'File Excel kosong atau hanya memiliki header');
|
||||
}
|
||||
|
||||
// Get headers
|
||||
$headers = array_map('strtolower', $data[0]);
|
||||
$headers = array_map(fn($h) => trim(str_replace([' ', '-', '_'], '_', $h)), $headers);
|
||||
|
||||
// Normalize column mapping
|
||||
$columnMap = $this->normalizeColumns();
|
||||
|
||||
// Process rows
|
||||
$rows = array_slice($data, 1);
|
||||
$successCount = 0;
|
||||
$errorCount = 0;
|
||||
$errors = [];
|
||||
|
||||
foreach ($rows as $idx => $row) {
|
||||
$record = $this->mapRow($row, $headers, $columnMap);
|
||||
|
||||
if ($record === null || empty($record['nama_alumni'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Validate required fields
|
||||
$validator = Validator::make($record, [
|
||||
'nama_alumni' => 'required|string',
|
||||
'kelompok_asal' => 'nullable|string',
|
||||
'nilai_rata_rata' => 'nullable|numeric',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
$errorCount++;
|
||||
$errors[] = "Baris " . ($idx + 2) . ": " . implode(', ', $validator->errors()->all());
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
// Check if already exists
|
||||
$existing = Alumni::where('nis', $record['nis'] ?? '')
|
||||
->where('nama_alumni', $record['nama_alumni'])
|
||||
->first();
|
||||
|
||||
if (!$existing) {
|
||||
Alumni::create($record);
|
||||
$successCount++;
|
||||
} else {
|
||||
// Update jika sudah ada
|
||||
$existing->update($record);
|
||||
$successCount++;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$errorCount++;
|
||||
$errors[] = "Baris " . ($idx + 2) . ": " . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up temp file
|
||||
@unlink($fullPath);
|
||||
|
||||
// Prepare response
|
||||
$message = "✓ Import Selesai! {$successCount} data berhasil diimport";
|
||||
if ($errorCount > 0) {
|
||||
$message .= " ({$errorCount} error/skip)";
|
||||
}
|
||||
|
||||
return back()
|
||||
->with('success', $message)
|
||||
->with('successCount', $successCount)
|
||||
->with('errorCount', $errorCount)
|
||||
->with('errors', count($errors) <= 10 ? $errors : array_slice($errors, 0, 10));
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return back()->with('error', 'Error: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize column headers to database column names
|
||||
*/
|
||||
private function normalizeColumns()
|
||||
{
|
||||
return [
|
||||
'nama' => 'nama_alumni',
|
||||
'nama_alumni' => 'nama_alumni',
|
||||
'nis' => 'nis',
|
||||
'no_induk_siswa' => 'nis',
|
||||
'kelompok_asal' => 'kelompok_asal',
|
||||
'kelompok' => 'kelompok_asal',
|
||||
'nilai_(rata_rata)' => 'nilai_rata_rata',
|
||||
'nilai_rata_rata' => 'nilai_rata_rata',
|
||||
'rata_rata' => 'nilai_rata_rata',
|
||||
'average' => 'nilai_rata_rata',
|
||||
'minat' => 'minat',
|
||||
'interest' => 'minat',
|
||||
'cita_cita' => 'cita_cita',
|
||||
'cita' => 'cita_cita',
|
||||
'dream_job' => 'cita_cita',
|
||||
'preferensi_studi' => 'preferensi_studi',
|
||||
'preferensi' => 'preferensi_studi',
|
||||
'preference' => 'preferensi_studi',
|
||||
'prestasi' => 'prestasi',
|
||||
'achievement' => 'prestasi',
|
||||
'major_masuk' => 'major_masuk',
|
||||
'jurusan_masuk' => 'major_masuk',
|
||||
'jurusan' => 'major_masuk',
|
||||
'major' => 'major_masuk',
|
||||
'tahun_lulus_polije' => 'tahun_lulus_polije',
|
||||
'tahun_lulus' => 'tahun_lulus_polije',
|
||||
'graduation_year' => 'tahun_lulus_polije',
|
||||
'tahun' => 'tahun_lulus_polije',
|
||||
'catatan' => 'catatan',
|
||||
'keterangan' => 'catatan',
|
||||
'notes' => 'catatan',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Map row data to Alumni model
|
||||
*/
|
||||
private function mapRow($row, $headers, $columnMap)
|
||||
{
|
||||
$record = [];
|
||||
|
||||
foreach ($headers as $idx => $header) {
|
||||
$value = $row[$idx] ?? null;
|
||||
|
||||
if (!$value) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Map column name
|
||||
$dbColumn = $columnMap[strtolower($header)] ?? null;
|
||||
|
||||
if (!$dbColumn) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Type conversion
|
||||
if (in_array($dbColumn, ['nilai_rata_rata', 'tahun_lulus_polije'])) {
|
||||
$record[$dbColumn] = (float) $value;
|
||||
} else {
|
||||
$record[$dbColumn] = trim((string) $value);
|
||||
}
|
||||
}
|
||||
|
||||
return empty($record) ? null : $record;
|
||||
}
|
||||
}
|
||||
|
|
@ -14,6 +14,37 @@
|
|||
|
||||
class BKController extends Controller
|
||||
{
|
||||
private const IPA_SUBJECTS = ['mtk', 'fisika', 'kimia', 'biologi'];
|
||||
private const IPS_SUBJECTS = ['ekonomi', 'geografi', 'sosiologi', 'sejarah'];
|
||||
|
||||
private const ALL_SUBJECTS = ['mtk', 'fisika', 'kimia', 'biologi', 'ekonomi', 'geografi', 'sosiologi', 'sejarah'];
|
||||
|
||||
private function normalizeScoreFields(array $validated, string $kelompokAsal): array
|
||||
{
|
||||
$activeSubjects = $kelompokAsal === 'IPA' ? self::IPA_SUBJECTS : self::IPS_SUBJECTS;
|
||||
|
||||
foreach (self::ALL_SUBJECTS as $subject) {
|
||||
if (!in_array($subject, $activeSubjects, true)) {
|
||||
$validated[$subject] = null;
|
||||
}
|
||||
}
|
||||
|
||||
return $validated;
|
||||
}
|
||||
|
||||
private function validateScoreByKelompok(Request $request): void
|
||||
{
|
||||
$requiredSubjects = $request->input('kelompok_asal') === 'IPA'
|
||||
? self::IPA_SUBJECTS
|
||||
: self::IPS_SUBJECTS;
|
||||
|
||||
foreach ($requiredSubjects as $subject) {
|
||||
$request->validate([
|
||||
$subject => 'required|numeric|min:0|max:100',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 1. DASHBOARD
|
||||
// ============================================
|
||||
|
|
@ -213,18 +244,21 @@ public function jurusanStore(Request $request)
|
|||
{
|
||||
$request->validate([
|
||||
'nama_jurusan' => 'required|string|min:3|max:255|unique:jurusan_polije,nama_jurusan',
|
||||
'deskripsi' => 'nullable|string|max:1000',
|
||||
'deskripsi' => 'nullable|string|max:10000',
|
||||
'keywords' => 'nullable|string',
|
||||
'preferensi_studi' => 'nullable|string',
|
||||
'prospek_kerja' => 'nullable|string|max:1000',
|
||||
'bobot_mtk' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_fisika' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_kimia' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_biologi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_ekonomi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_geografi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_sosiologi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_sejarah' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel' => 'nullable|array',
|
||||
'bobot_mapel.ipa' => 'nullable|array',
|
||||
'bobot_mapel.ipa.mtk' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel.ipa.fisika' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel.ipa.kimia' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel.ipa.biologi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel.ips' => 'nullable|array',
|
||||
'bobot_mapel.ips.ekonomi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel.ips.geografi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel.ips.sosiologi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel.ips.sejarah' => 'nullable|numeric|min:0|max:1',
|
||||
]);
|
||||
|
||||
PolijeMajor::create([
|
||||
|
|
@ -251,18 +285,21 @@ public function jurusanUpdate(Request $request, $id)
|
|||
|
||||
$request->validate([
|
||||
'nama_jurusan' => ['required', 'string', 'min:3', 'max:255', Rule::unique('jurusan_polije', 'nama_jurusan')->ignore($jurusan->id)],
|
||||
'deskripsi' => 'nullable|string|max:1000',
|
||||
'deskripsi' => 'nullable|string|max:10000',
|
||||
'keywords' => 'nullable|string',
|
||||
'preferensi_studi' => 'nullable|string',
|
||||
'prospek_kerja' => 'nullable|string|max:1000',
|
||||
'bobot_mtk' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_fisika' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_kimia' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_biologi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_ekonomi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_geografi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_sosiologi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_sejarah' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel' => 'nullable|array',
|
||||
'bobot_mapel.ipa' => 'nullable|array',
|
||||
'bobot_mapel.ipa.mtk' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel.ipa.fisika' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel.ipa.kimia' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel.ipa.biologi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel.ips' => 'nullable|array',
|
||||
'bobot_mapel.ips.ekonomi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel.ips.geografi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel.ips.sosiologi' => 'nullable|numeric|min:0|max:1',
|
||||
'bobot_mapel.ips.sejarah' => 'nullable|numeric|min:0|max:1',
|
||||
]);
|
||||
|
||||
$jurusan->update([
|
||||
|
|
@ -293,15 +330,45 @@ private function parseTagInput(?string $input): array
|
|||
|
||||
private function parseBobotMapel(Request $request): array
|
||||
{
|
||||
$mapelList = ['mtk', 'fisika', 'kimia', 'biologi', 'ekonomi', 'geografi', 'sosiologi', 'sejarah'];
|
||||
$bobot = [];
|
||||
foreach ($mapelList as $mapel) {
|
||||
$value = $request->input("bobot_{$mapel}");
|
||||
if (!is_null($value) && $value !== '') {
|
||||
$bobot[$mapel] = floatval($value);
|
||||
}
|
||||
$ipaSubjects = ['mtk', 'fisika', 'kimia', 'biologi'];
|
||||
$ipsSubjects = ['ekonomi', 'geografi', 'sosiologi', 'sejarah'];
|
||||
|
||||
$ipaInput = $request->input('bobot_mapel.ipa');
|
||||
$ipsInput = $request->input('bobot_mapel.ips');
|
||||
|
||||
if (is_array($ipaInput) || is_array($ipsInput)) {
|
||||
return [
|
||||
'ipa' => $this->normalizeBobotGroup(is_array($ipaInput) ? $ipaInput : [], $ipaSubjects),
|
||||
'ips' => $this->normalizeBobotGroup(is_array($ipsInput) ? $ipsInput : [], $ipsSubjects),
|
||||
];
|
||||
}
|
||||
return $bobot;
|
||||
|
||||
return [
|
||||
'ipa' => $this->normalizeBobotGroup([
|
||||
'mtk' => $request->input('bobot_mtk'),
|
||||
'fisika' => $request->input('bobot_fisika'),
|
||||
'kimia' => $request->input('bobot_kimia'),
|
||||
'biologi' => $request->input('bobot_biologi'),
|
||||
], $ipaSubjects),
|
||||
'ips' => $this->normalizeBobotGroup([
|
||||
'ekonomi' => $request->input('bobot_ekonomi'),
|
||||
'geografi' => $request->input('bobot_geografi'),
|
||||
'sosiologi' => $request->input('bobot_sosiologi'),
|
||||
'sejarah' => $request->input('bobot_sejarah'),
|
||||
], $ipsSubjects),
|
||||
];
|
||||
}
|
||||
|
||||
private function normalizeBobotGroup(array $values, array $subjects): array
|
||||
{
|
||||
$normalized = [];
|
||||
|
||||
foreach ($subjects as $subject) {
|
||||
$value = $values[$subject] ?? null;
|
||||
$normalized[$subject] = is_numeric($value) ? (float) $value : 0.0;
|
||||
}
|
||||
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
|
|
@ -340,7 +407,7 @@ public function alumniStore(Request $request)
|
|||
// Non-akademik
|
||||
'minat' => 'nullable|string|max:255',
|
||||
'cita_cita' => 'nullable|string|max:255',
|
||||
'preferensi_studi' => 'nullable|in:Sains & Teknologi,Pertanian & Lingkungan,Kesehatan & Ilmu Hayat,Bisnis & Manajemen,Sosial & Humaniora',
|
||||
'preferensi_studi' => 'nullable|in:Praktik Langsung,Praktik_Langsung,DuDi,Project Based,Project_Based,Blended Learning,Blended',
|
||||
'prestasi' => 'nullable|string|max:255',
|
||||
|
||||
// Major
|
||||
|
|
@ -349,6 +416,9 @@ public function alumniStore(Request $request)
|
|||
'catatan' => 'nullable|string|max:500',
|
||||
]);
|
||||
|
||||
$this->validateScoreByKelompok($request);
|
||||
$validated = $this->normalizeScoreFields($validated, $validated['kelompok_asal']);
|
||||
|
||||
Alumni::create($validated);
|
||||
|
||||
return redirect()->route('bk.alumni')->with('success', 'Alumni berhasil ditambahkan');
|
||||
|
|
@ -382,7 +452,7 @@ public function alumniUpdate(Request $request, Alumni $alumni)
|
|||
|
||||
'minat' => 'nullable|string|max:255',
|
||||
'cita_cita' => 'nullable|string|max:255',
|
||||
'preferensi_studi' => 'nullable|in:Sains & Teknologi,Pertanian & Lingkungan,Kesehatan & Ilmu Hayat,Bisnis & Manajemen,Sosial & Humaniora',
|
||||
'preferensi_studi' => 'nullable|in:Praktik Langsung,Praktik_Langsung,DuDi,Project Based,Project_Based,Blended Learning,Blended',
|
||||
'prestasi' => 'nullable|string|max:255',
|
||||
|
||||
'major_masuk' => 'required|string|min:3|max:255',
|
||||
|
|
@ -390,6 +460,9 @@ public function alumniUpdate(Request $request, Alumni $alumni)
|
|||
'catatan' => 'nullable|string|max:500',
|
||||
]);
|
||||
|
||||
$this->validateScoreByKelompok($request);
|
||||
$validated = $this->normalizeScoreFields($validated, $validated['kelompok_asal']);
|
||||
|
||||
$alumni->update($validated);
|
||||
|
||||
return redirect()->route('bk.alumni')->with('success', 'Alumni berhasil diupdate');
|
||||
|
|
|
|||
|
|
@ -30,10 +30,18 @@ public function index(Request $request)
|
|||
$user = Auth::user();
|
||||
$sessionId = $request->query('session');
|
||||
$recId = $request->query('rec');
|
||||
$isNew = $request->query('new'); // Deteksi jika langsung buka chatbot tanpa rekomendasi
|
||||
$previousMessages = [];
|
||||
$recommendationId = null;
|
||||
|
||||
if ($sessionId) {
|
||||
// Jika ?new=1, abaikan session dan rekomendasi lama - buat fresh session
|
||||
if ($isNew) {
|
||||
$sessionId = Str::uuid()->toString();
|
||||
$recommendationId = null;
|
||||
$previousMessages = [];
|
||||
// Clear session lama
|
||||
session()->forget('recomendation_data');
|
||||
} else if ($sessionId) {
|
||||
// Lanjutkan sesi lama — ambil semua chat dari sesi ini
|
||||
$chats = ChatHistory::where('user_id', $user->id)
|
||||
->where('id_sesi', $sessionId)
|
||||
|
|
@ -63,63 +71,28 @@ public function index(Request $request)
|
|||
$sessionId = Str::uuid()->toString();
|
||||
}
|
||||
|
||||
// Tentukan recommendation_id:
|
||||
// 1. Dari sesi lama (sudah diset di atas)
|
||||
// 2. Dari parameter ?rec= (klik dari hasil rekomendasi)
|
||||
// JANGAN fallback ke rekomendasi terbaru - biarkan null jika tidak ada
|
||||
// Tentukan recommendation_id (kecuali sudah diset oleh ?new=1 atau session lama):
|
||||
if (!$recommendationId && $recId) {
|
||||
$rec = Recommendation::where('id', $recId)
|
||||
->where('user_id', $user->id)
|
||||
->first();
|
||||
$recommendationId = $rec ? $rec->id : null;
|
||||
}
|
||||
// Jika tidak ada recommendation_id dari session atau ?rec param, biarkan null
|
||||
|
||||
// Ambil konteks rekomendasi berdasarkan ID spesifik
|
||||
$recentRecommendation = $this->getRecommendationContext($user, $recommendationId) ?? [];
|
||||
|
||||
// Ambil 10 session terakhir yang unik untuk user
|
||||
// Strategy: ambil last chat per session, sort by created_at, limit 10
|
||||
$chatHistories = collect();
|
||||
|
||||
$sessions = ChatHistory::where('user_id', $user->id)
|
||||
->select('id_sesi')
|
||||
->distinct('id_sesi')
|
||||
->get()
|
||||
->pluck('id_sesi');
|
||||
|
||||
foreach ($sessions as $session_id) {
|
||||
$lastChat = ChatHistory::where('user_id', $user->id)
|
||||
->where('id_sesi', $session_id)
|
||||
->latest('created_at')
|
||||
->first();
|
||||
|
||||
$firstChat = ChatHistory::where('user_id', $user->id)
|
||||
->where('id_sesi', $session_id)
|
||||
->oldest('created_at')
|
||||
->first();
|
||||
|
||||
if ($lastChat && $firstChat) {
|
||||
$chatHistories->push((object)[
|
||||
'id_sesi' => $session_id,
|
||||
'created_at' => $lastChat->created_at,
|
||||
'prompt' => $firstChat->prompt ?? 'Tidak ada pesan',
|
||||
]);
|
||||
}
|
||||
// Load rekomendasi terbaru jika tidak ada kondisi di atas
|
||||
if (!$recommendationId && !$isNew) {
|
||||
$latestRec = Recommendation::where('user_id', $user->id)->latest()->first();
|
||||
$recommendationId = $latestRec ? $latestRec->id : null;
|
||||
}
|
||||
|
||||
// Sort by created_at desc dan ambil 10
|
||||
$chatHistories = $chatHistories->sortByDesc('created_at')
|
||||
->take(10)
|
||||
->values()
|
||||
->toArray();
|
||||
// Ambil konteks rekomendasi berdasarkan ID spesifik
|
||||
$recentRecommendation = $this->getRecommendationContext($user, $recommendationId, $isNew);
|
||||
|
||||
return view('chatbot.index', [
|
||||
'recommendation' => $recentRecommendation,
|
||||
'sessionId' => $sessionId,
|
||||
'previousMessages' => $previousMessages,
|
||||
'recommendationId' => $recommendationId,
|
||||
'chatHistories' => $chatHistories,
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -264,30 +237,36 @@ public function historyChat()
|
|||
* Ambil konteks rekomendasi berdasarkan ID spesifik.
|
||||
* Jika ID tidak ada, coba dari session, lalu dari DB (terbaru).
|
||||
*/
|
||||
private function getRecommendationContext($user, $recommendationId = null)
|
||||
private function getRecommendationContext($user, $recommendationId = null, $isNew = false)
|
||||
{
|
||||
// Jika ada recommendation_id spesifik, ambil langsung dari DB
|
||||
$lastRec = null;
|
||||
|
||||
// Jika ada recommendation_id spesifik, ambil langsung dari DB dan JANGAN fallback
|
||||
if ($recommendationId) {
|
||||
$lastRec = Recommendation::where('id', $recommendationId)
|
||||
->where('user_id', $user->id)
|
||||
->first();
|
||||
}
|
||||
|
||||
// ONLY fallback: dari session (saat baru selesai rekomendasi)
|
||||
// Jangan ambil rekomendasi terbaru dari DB jika tidak ada recommendation_id
|
||||
if (!$lastRec) {
|
||||
|
||||
if (!$lastRec) {
|
||||
// Jika rec ID tidak ditemukan, jangan fallback - return null
|
||||
return null;
|
||||
}
|
||||
} else if ($isNew) {
|
||||
// Jika ?new=1, jangan load apapun dari session atau DB
|
||||
return null;
|
||||
} else {
|
||||
// Fallback: dari session (saat baru selesai rekomendasi)
|
||||
$sessionData = session('recomendation_data', null);
|
||||
if ($sessionData) {
|
||||
return $sessionData;
|
||||
}
|
||||
// Jika tidak ada di session dan tidak ada recommendation_id, return null
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$lastRec) {
|
||||
return null;
|
||||
// Fallback: rekomendasi terbaru dari DB
|
||||
$lastRec = Recommendation::where('user_id', $user->id)
|
||||
->latest()
|
||||
->first();
|
||||
|
||||
if (!$lastRec) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Safely decode hasil_rekomendasi
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ public function proses(Request $request)
|
|||
$prior = 1 / $cfgCount;
|
||||
$logPrior = log(max($prior, $epsilon));
|
||||
|
||||
// Weights dan match probabilities dengan defaults (berdasarkan ROC dari analisis)
|
||||
// Weights dan match probabilities dengan defaults (ROC-based: nilai 15.6%, minat 45.6%, pref 25.6%, cita 9%, prestasi 4%)
|
||||
$weights = $c['weights'] ?? ['nilai' => 0.156, 'minat' => 0.456, 'pref' => 0.256, 'cita_cita' => 0.090, 'prestasi' => 0.040];
|
||||
|
||||
// Ensure weights is array
|
||||
|
|
@ -266,17 +266,16 @@ public function proses(Request $request)
|
|||
// Jika prestasi kosong, atribut prestasi tidak dihitung dengan normalisasi ulang
|
||||
if (!$isPrestasiFilled) {
|
||||
$weights['prestasi'] = 0.0;
|
||||
$sumNonPrestasi = ($weights['nilai'] ?? 0) + ($weights['minat'] ?? 0) + ($weights['pref'] ?? 0) + ($weights['cita_cita'] ?? 0);
|
||||
$sumNonPrestasi = ($weights['nilai'] ?? 0) + ($weights['minat'] ?? 0) + ($weights['cita_cita'] ?? 0);
|
||||
|
||||
// Normalize weights dengan safety check
|
||||
if ($sumNonPrestasi > $epsilon) {
|
||||
$weights['nilai'] = ($weights['nilai'] ?? 0) / $sumNonPrestasi;
|
||||
$weights['minat'] = ($weights['minat'] ?? 0) / $sumNonPrestasi;
|
||||
$weights['pref'] = ($weights['pref'] ?? 0) / $sumNonPrestasi;
|
||||
$weights['cita_cita'] = ($weights['cita_cita'] ?? 0) / $sumNonPrestasi;
|
||||
} else {
|
||||
// Fallback weights jika semua weight adalah 0
|
||||
$weights = ['nilai' => 0.156, 'minat' => 0.456, 'pref' => 0.256, 'cita_cita' => 0.238];
|
||||
$weights = ['nilai' => 0.156, 'minat' => 0.456, 'pref' => 0.256, 'cita_cita' => 0.090, 'prestasi' => 0.040];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -390,8 +389,9 @@ public function proses(Request $request)
|
|||
|
||||
// Simpan data rekomendasi ke database
|
||||
$user = Auth::user();
|
||||
$recommendationId = null;
|
||||
if ($user) {
|
||||
Recommendation::create([
|
||||
$recommendation = Recommendation::create([
|
||||
'user_id' => $user->id,
|
||||
'mtk' => $request->mtk ?? null,
|
||||
'fisika' => $request->fisika ?? null,
|
||||
|
|
@ -408,6 +408,7 @@ public function proses(Request $request)
|
|||
'prestasi' => $prestasiInput,
|
||||
'hasil_rekomendasi' => $hasilAkhir,
|
||||
]);
|
||||
$recommendationId = $recommendation->id;
|
||||
}
|
||||
|
||||
// Simpan data rekomendasi ke session untuk chatbot
|
||||
|
|
@ -430,7 +431,7 @@ public function proses(Request $request)
|
|||
$topJurusan = PolijeMajor::where('nama_jurusan', $hasilAkhir[0]['jurusan'] ?? '')->first();
|
||||
}
|
||||
|
||||
return view('rekomendasi.hasil', compact('hasilAkhir', 'katNilai', 'average', 'minatMapped', 'citaMapped', 'prefStudi', 'prestasiScore', 'topJurusan', 'isPrestasiFilled'));
|
||||
return view('rekomendasi.hasil', compact('hasilAkhir', 'katNilai', 'average', 'minatRaw', 'minatMapped', 'citaRaw', 'citaMapped', 'prefStudi', 'prestasiScore', 'topJurusan', 'isPrestasiFilled', 'recommendationId'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -482,11 +483,11 @@ private function mapMinat(string $minatRaw): string
|
|||
|
||||
// Use coverage-based scoring untuk handle ambiguous inputs
|
||||
$categoryKeywords = [
|
||||
'Logika & Komputer' => ['coding', 'komputer', 'laptop', 'web', 'aplikasi', 'logika', 'programming', 'software', 'development', 'developer', 'it', 'data', 'ai'],
|
||||
'Alam & Tanaman' => ['tanam', 'kebun', 'sawah', 'hewan', 'ternak', 'alam', 'pertanian', 'agri', 'panen', 'tani', 'hortikultura'],
|
||||
'Pelayanan & Kesehatan' => ['obat', 'sakit', 'rawat', 'medis', 'gizi', 'sehat', 'kesehatan', 'perawat', 'dokter', 'rumah sakit', 'klinik'],
|
||||
'Manajemen & Bisnis' => ['bisnis', 'uang', 'jual', 'kantor', 'hitung', 'ekonomi', 'dagang', 'usaha', 'entrepreneur', 'manager', 'marketing', 'akuntan'],
|
||||
'Mesin & Listrik' => ['mesin', 'bengkel', 'listrik', 'las', 'robot', 'motor', 'teknik', 'otomasi', 'elektronik', 'maintenance'],
|
||||
'Logika & Komputer' => ['coding', 'komputer', 'laptop', 'web', 'aplikasi', 'logika', 'programming', 'software', 'development', 'developer', 'it', 'data', 'ai', 'teknologi', 'sistem', 'cloud', 'database', 'network', 'cybersecurity', 'analyst', 'scientist', 'algorithm', 'machine learning', 'app', 'digital'],
|
||||
'Alam & Tanaman' => ['tanam', 'kebun', 'sawah', 'hewan', 'ternak', 'alam', 'pertanian', 'agri', 'panen', 'tani', 'hortikultura', 'lingkungan', 'berkelanjutan', 'farm', 'farming', 'plantation', 'crops', 'conservation', 'breeding', 'agribusiness', 'agroforestry', 'horticulture', 'cultivate', 'harvest', 'livestock management', 'animal husbandry', 'sustainable agriculture', 'crop science', 'soil', 'botanical'],
|
||||
'Pelayanan & Kesehatan' => ['obat', 'sakit', 'rawat', 'medis', 'gizi', 'sehat', 'kesehatan', 'perawat', 'dokter', 'rumah sakit', 'klinik', 'farmasi', 'keperawatan', 'terapis', 'nursing', 'therapy', 'wellness', 'nutrition', 'healing', 'caring', 'clinical', 'patient care', 'rehabilitation', 'surgery', 'diagnostic', 'laboratory', 'medical technician', 'health educator', 'public health', 'epidemiology', 'preventive care'],
|
||||
'Manajemen & Bisnis' => ['bisnis', 'uang', 'jual', 'kantor', 'hitung', 'ekonomi', 'dagang', 'usaha', 'entrepreneur', 'manager', 'marketing', 'akuntan', 'finance', 'keuangan', 'sales', 'trading', 'commerce', 'leadership', 'startup', 'corporate', 'organization', 'administration', 'strategic planning', 'operations', 'budget', 'investment', 'capital', 'supply chain', 'logistics', 'human resources'],
|
||||
'Mesin & Listrik' => ['mesin', 'bengkel', 'listrik', 'las', 'robot', 'motor', 'teknik', 'otomasi', 'elektronik', 'maintenance', 'industri', 'manufaktur', 'mechanical', 'electrical', 'automation', 'construction', 'repair', 'welding', 'hydraulic', 'pneumatic', 'power generation', 'circuit', 'transformer', 'machinery operation', 'fabrication', 'installation', 'troubleshooting'],
|
||||
];
|
||||
|
||||
// Score setiap kategori berdasarkan keyword coverage
|
||||
|
|
@ -520,12 +521,12 @@ private function mapCitaCita(string $citaRaw): string
|
|||
|
||||
// Map cita-cita ke category berdasarkan keywords
|
||||
$careerCategories = [
|
||||
'IT & Software' => ['programmer', 'developer', 'software', 'coding', 'hacker', 'web', 'database', 'it', 'engineer'],
|
||||
'Agriculture' => ['petani', 'pertanian', 'agribisnis', 'kebun', 'ternak', 'peternak', 'agronomi'],
|
||||
'Healthcare' => ['dokter', 'perawat', 'medis', 'gizi', 'terapis', 'farmasi', 'kesehatan'],
|
||||
'Business' => ['entrepreneur', 'manager', 'marketing', 'sales', 'akuntan', 'keuangan', 'bisnis'],
|
||||
'Engineering' => ['teknik', 'engineer', 'mesin', 'listrik', 'bengkel', 'maintenance', 'industri'],
|
||||
'Communication' => ['jurnalis', 'komunikator', 'presenter', 'content', 'pariwisata', 'hospitality'],
|
||||
'IT & Software' => ['programmer', 'developer', 'software', 'coding', 'web', 'database', 'it', 'scientist', 'analyst', 'data', 'cloud', 'architect', 'cybersecurity', 'security', 'devops', 'backend', 'frontend', 'fullstack', 'sysadmin', 'network admin', 'cto', 'tech lead', 'ai', 'machine learning'],
|
||||
'Agriculture' => ['petani', 'pertanian', 'agribisnis', 'kebun', 'ternak', 'peternak', 'agronomi', 'farming', 'livestock', 'agronomist', 'farmer', 'farm manager', 'plantation', 'crops specialist', 'agritech', 'horticultural', 'agricultural scientist', 'soil scientist', 'breeding specialist', 'extension officer', 'crop consultant', 'forestry', 'fishery manager'],
|
||||
'Healthcare' => ['dokter', 'perawat', 'medis', 'gizi', 'terapis', 'farmasi', 'kesehatan', 'nursing', 'therapist', 'pharmacist', 'nutritionist', 'clinician', 'public health', 'midwife', 'radiologist', 'dentist', 'nurse', 'surgeon', 'diagnostician', 'laboratory technician', 'paramedic', 'health educator', 'epidemiologist', 'wellness coach'],
|
||||
'Business' => ['entrepreneur', 'manager', 'marketing', 'sales', 'akuntan', 'keuangan', 'bisnis', 'accountant', 'consultant', 'finance', 'cfo', 'ceo', 'director', 'treasurer', 'auditor', 'trader', 'investor', 'controller', 'operations manager', 'strategic planner', 'business analyst', 'supply chain manager', 'hr manager', 'corporate executive'],
|
||||
'Engineering' => ['teknik', 'engineer', 'mesin', 'listrik', 'bengkel', 'maintenance', 'industri', 'technician', 'constructor', 'mechanical engineer', 'electrical engineer', 'automation', 'supervisor', 'foreman', 'technologist', 'specialist', 'civil engineer', 'welding specialist', 'hydraulics engineer', 'power engineer', 'manufacturing engineer', 'maintenance supervisor'],
|
||||
'Communication' => ['jurnalis', 'komunikator', 'presenter', 'content', 'pariwisata', 'hospitality', 'tour', 'guide', 'public relations', 'ambassador', 'interpreter', 'diplomat', 'broadcaster', 'event organizer', 'marketing specialist', 'pr specialist', 'copywriter', 'social media manager', 'travel consultant', 'hospitality manager', 'cultural ambassador', 'media producer'],
|
||||
];
|
||||
|
||||
// Score setiap kategori
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Http\Requests\Auth;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Events\Lockout;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
|
@ -54,17 +55,39 @@ public function authenticate(): void
|
|||
|
||||
/**
|
||||
* Ensure the login request is not rate limited.
|
||||
* Special handling: Students get 3 attempts, others get 5 attempts.
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
*/
|
||||
public function ensureIsNotRateLimited(): void
|
||||
{
|
||||
if (! RateLimiter::tooManyAttempts($this->throttleKey(), 5)) {
|
||||
$email = $this->string('email');
|
||||
$user = User::where('email', $email)->first();
|
||||
|
||||
// Tentukan limit berdasarkan role (khusus siswa: 3x, lainnya: 5x)
|
||||
$maxAttempts = 5; // Default untuk BK, Admin, dan user lainnya
|
||||
$isStudent = false;
|
||||
|
||||
if ($user && $user->role === 'siswa') {
|
||||
$maxAttempts = 3; // Siswa hanya boleh 3x
|
||||
$isStudent = true;
|
||||
}
|
||||
|
||||
if (! RateLimiter::tooManyAttempts($this->throttleKey(), $maxAttempts)) {
|
||||
return;
|
||||
}
|
||||
|
||||
event(new Lockout($this));
|
||||
|
||||
// Special message untuk siswa yang sudah 3x gagal
|
||||
if ($isStudent) {
|
||||
throw ValidationException::withMessages([
|
||||
'email' => '❌ Anda sudah salah password 3 kali. Silakan reset password melalui "Lupa Password" untuk keamanan akun Anda.',
|
||||
'forgot_password' => true, // Flag khusus untuk redirect
|
||||
'email_value' => $email, // Kirim email untuk auto-fill
|
||||
]);
|
||||
}
|
||||
|
||||
$seconds = RateLimiter::availableIn($this->throttleKey());
|
||||
|
||||
throw ValidationException::withMessages([
|
||||
|
|
|
|||
|
|
@ -15,14 +15,7 @@ class Alumni extends Model
|
|||
'nama_alumni',
|
||||
'nis',
|
||||
'kelompok_asal',
|
||||
'mtk',
|
||||
'fisika',
|
||||
'kimia',
|
||||
'biologi',
|
||||
'ekonomi',
|
||||
'geografi',
|
||||
'sosiologi',
|
||||
'sejarah',
|
||||
'nilai_rata_rata',
|
||||
'minat',
|
||||
'cita_cita',
|
||||
'preferensi_studi',
|
||||
|
|
@ -33,42 +26,6 @@ class Alumni extends Model
|
|||
];
|
||||
|
||||
protected $casts = [
|
||||
'mtk' => 'float',
|
||||
'fisika' => 'float',
|
||||
'kimia' => 'float',
|
||||
'biologi' => 'float',
|
||||
'ekonomi' => 'float',
|
||||
'geografi' => 'float',
|
||||
'sosiologi' => 'float',
|
||||
'sejarah' => 'float',
|
||||
'nilai_rata_rata' => 'float',
|
||||
];
|
||||
|
||||
/**
|
||||
* Hitung nilai rata-rata otomatis
|
||||
*/
|
||||
public static function booted()
|
||||
{
|
||||
static::saving(function ($alumni) {
|
||||
// Gather nilai based on kelompok_asal
|
||||
$nilaiFields = ['mtk'];
|
||||
|
||||
if ($alumni->kelompok_asal == 'IPA') {
|
||||
$nilaiFields = ['mtk', 'fisika', 'kimia', 'biologi'];
|
||||
} else {
|
||||
$nilaiFields = ['mtk', 'ekonomi', 'geografi', 'sosiologi', 'sejarah'];
|
||||
}
|
||||
|
||||
$nilaiValues = [];
|
||||
foreach ($nilaiFields as $field) {
|
||||
if (!is_null($alumni->$field)) {
|
||||
$nilaiValues[] = $alumni->$field;
|
||||
}
|
||||
}
|
||||
|
||||
$alumni->nilai_rata_rata = count($nilaiValues) > 0
|
||||
? round(array_sum($nilaiValues) / count($nilaiValues), 2)
|
||||
: null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Models;
|
||||
|
||||
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use App\Notifications\ResetPasswordNotification;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
|
@ -61,4 +62,12 @@ public function chatHistories()
|
|||
{
|
||||
return $this->hasMany(ChatHistory::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the password reset notification.
|
||||
*/
|
||||
public function sendPasswordResetNotification($token)
|
||||
{
|
||||
$this->notify(new ResetPasswordNotification($token));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
class ResetPasswordNotification extends Notification
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
/**
|
||||
* The password reset token.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $token;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*/
|
||||
public function __construct($token)
|
||||
{
|
||||
$this->token = $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function via(object $notifiable): array
|
||||
{
|
||||
return ['mail'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*/
|
||||
public function toMail(object $notifiable): MailMessage
|
||||
{
|
||||
$resetUrl = url(route('password.reset', [
|
||||
'token' => $this->token,
|
||||
'email' => $notifiable->getEmailForPasswordReset(),
|
||||
], false));
|
||||
|
||||
return (new MailMessage)
|
||||
->subject('🔑 Reset Password - Sistem Pemilihan Jurusan Polije')
|
||||
->view('emails.reset-password', [
|
||||
'user' => $notifiable,
|
||||
'resetUrl' => $resetUrl,
|
||||
'expiresIn' => config('auth.passwords.users.expire', 60),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(object $notifiable): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,8 @@
|
|||
"guzzlehttp/guzzle": "^7.2",
|
||||
"laravel/framework": "^10.0",
|
||||
"laravel/sanctum": "^3.2",
|
||||
"laravel/tinker": "^2.8"
|
||||
"laravel/tinker": "^2.8",
|
||||
"phpoffice/phpspreadsheet": "^5.7"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/dbal": "^3.10",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "bd2fbf3fa53fb313c47897eb28e7a171",
|
||||
"content-hash": "c97868c64e1e33e893e3495daa4ea07a",
|
||||
"packages": [
|
||||
{
|
||||
"name": "barryvdh/laravel-dompdf",
|
||||
|
|
@ -212,6 +212,85 @@
|
|||
],
|
||||
"time": "2023-12-11T17:09:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/pcre",
|
||||
"version": "3.3.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/pcre.git",
|
||||
"reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
|
||||
"reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.4 || ^8.0"
|
||||
},
|
||||
"conflict": {
|
||||
"phpstan/phpstan": "<1.11.10"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^1.12 || ^2",
|
||||
"phpstan/phpstan-strict-rules": "^1 || ^2",
|
||||
"phpunit/phpunit": "^8 || ^9"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"phpstan": {
|
||||
"includes": [
|
||||
"extension.neon"
|
||||
]
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-main": "3.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Composer\\Pcre\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jordi Boggiano",
|
||||
"email": "j.boggiano@seld.be",
|
||||
"homepage": "http://seld.be"
|
||||
}
|
||||
],
|
||||
"description": "PCRE wrapping library that offers type-safe preg_* replacements.",
|
||||
"keywords": [
|
||||
"PCRE",
|
||||
"preg",
|
||||
"regex",
|
||||
"regular expression"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/composer/pcre/issues",
|
||||
"source": "https://github.com/composer/pcre/tree/3.3.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://packagist.com",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/composer",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-11-12T16:29:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "dflydev/dot-access-data",
|
||||
"version": "v3.0.3",
|
||||
|
|
@ -2120,6 +2199,191 @@
|
|||
],
|
||||
"time": "2024-09-21T08:32:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "maennchen/zipstream-php",
|
||||
"version": "3.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/maennchen/ZipStream-PHP.git",
|
||||
"reference": "77bebeb4c6c340bb3c11c843b2cffd8bbfde4d5e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/77bebeb4c6c340bb3c11c843b2cffd8bbfde4d5e",
|
||||
"reference": "77bebeb4c6c340bb3c11c843b2cffd8bbfde4d5e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-mbstring": "*",
|
||||
"ext-zlib": "*",
|
||||
"php-64bit": "^8.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"brianium/paratest": "^7.7",
|
||||
"ext-zip": "*",
|
||||
"friendsofphp/php-cs-fixer": "^3.86",
|
||||
"guzzlehttp/guzzle": "^7.5",
|
||||
"mikey179/vfsstream": "^1.6",
|
||||
"php-coveralls/php-coveralls": "^2.5",
|
||||
"phpunit/phpunit": "^12.0",
|
||||
"vimeo/psalm": "^6.0"
|
||||
},
|
||||
"suggest": {
|
||||
"guzzlehttp/psr7": "^2.4",
|
||||
"psr/http-message": "^2.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"ZipStream\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Paul Duncan",
|
||||
"email": "pabs@pablotron.org"
|
||||
},
|
||||
{
|
||||
"name": "Jonatan Männchen",
|
||||
"email": "jonatan@maennchen.ch"
|
||||
},
|
||||
{
|
||||
"name": "Jesse Donat",
|
||||
"email": "donatj@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "András Kolesár",
|
||||
"email": "kolesar@kolesar.hu"
|
||||
}
|
||||
],
|
||||
"description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.",
|
||||
"keywords": [
|
||||
"stream",
|
||||
"zip"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/maennchen/ZipStream-PHP/issues",
|
||||
"source": "https://github.com/maennchen/ZipStream-PHP/tree/3.2.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/maennchen",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-04-11T18:38:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "markbaker/complex",
|
||||
"version": "3.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/MarkBaker/PHPComplex.git",
|
||||
"reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/95c56caa1cf5c766ad6d65b6344b807c1e8405b9",
|
||||
"reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "dev-master",
|
||||
"phpcompatibility/php-compatibility": "^9.3",
|
||||
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
|
||||
"squizlabs/php_codesniffer": "^3.7"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Complex\\": "classes/src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Mark Baker",
|
||||
"email": "mark@lange.demon.co.uk"
|
||||
}
|
||||
],
|
||||
"description": "PHP Class for working with complex numbers",
|
||||
"homepage": "https://github.com/MarkBaker/PHPComplex",
|
||||
"keywords": [
|
||||
"complex",
|
||||
"mathematics"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/MarkBaker/PHPComplex/issues",
|
||||
"source": "https://github.com/MarkBaker/PHPComplex/tree/3.0.2"
|
||||
},
|
||||
"time": "2022-12-06T16:21:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "markbaker/matrix",
|
||||
"version": "3.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/MarkBaker/PHPMatrix.git",
|
||||
"reference": "728434227fe21be27ff6d86621a1b13107a2562c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/728434227fe21be27ff6d86621a1b13107a2562c",
|
||||
"reference": "728434227fe21be27ff6d86621a1b13107a2562c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "dev-master",
|
||||
"phpcompatibility/php-compatibility": "^9.3",
|
||||
"phpdocumentor/phpdocumentor": "2.*",
|
||||
"phploc/phploc": "^4.0",
|
||||
"phpmd/phpmd": "2.*",
|
||||
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
|
||||
"sebastian/phpcpd": "^4.0",
|
||||
"squizlabs/php_codesniffer": "^3.7"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Matrix\\": "classes/src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Mark Baker",
|
||||
"email": "mark@demon-angel.eu"
|
||||
}
|
||||
],
|
||||
"description": "PHP Class for working with matrices",
|
||||
"homepage": "https://github.com/MarkBaker/PHPMatrix",
|
||||
"keywords": [
|
||||
"mathematics",
|
||||
"matrix",
|
||||
"vector"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/MarkBaker/PHPMatrix/issues",
|
||||
"source": "https://github.com/MarkBaker/PHPMatrix/tree/3.0.1"
|
||||
},
|
||||
"time": "2022-12-02T22:17:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "masterminds/html5",
|
||||
"version": "2.10.0",
|
||||
|
|
@ -2694,6 +2958,115 @@
|
|||
],
|
||||
"time": "2024-11-21T10:36:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpoffice/phpspreadsheet",
|
||||
"version": "5.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHPOffice/PhpSpreadsheet.git",
|
||||
"reference": "9f55d3b9b7bcb1084fda8340e4b7ce4ed10cd0c8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/9f55d3b9b7bcb1084fda8340e4b7ce4ed10cd0c8",
|
||||
"reference": "9f55d3b9b7bcb1084fda8340e4b7ce4ed10cd0c8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer/pcre": "^1||^2||^3",
|
||||
"ext-ctype": "*",
|
||||
"ext-dom": "*",
|
||||
"ext-fileinfo": "*",
|
||||
"ext-filter": "*",
|
||||
"ext-gd": "*",
|
||||
"ext-iconv": "*",
|
||||
"ext-libxml": "*",
|
||||
"ext-mbstring": "*",
|
||||
"ext-simplexml": "*",
|
||||
"ext-xml": "*",
|
||||
"ext-xmlreader": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"ext-zip": "*",
|
||||
"ext-zlib": "*",
|
||||
"maennchen/zipstream-php": "^2.1 || ^3.0",
|
||||
"markbaker/complex": "^3.0",
|
||||
"markbaker/matrix": "^3.0",
|
||||
"php": "^8.1",
|
||||
"psr/simple-cache": "^1.0 || ^2.0 || ^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "dev-main",
|
||||
"dompdf/dompdf": "^2.0 || ^3.0",
|
||||
"ext-intl": "*",
|
||||
"friendsofphp/php-cs-fixer": "^3.2",
|
||||
"mitoteam/jpgraph": "^10.5",
|
||||
"mpdf/mpdf": "^8.1.1",
|
||||
"phpcompatibility/php-compatibility": "^9.3",
|
||||
"phpstan/phpstan": "^1.1 || ^2.0",
|
||||
"phpstan/phpstan-deprecation-rules": "^1.0 || ^2.0",
|
||||
"phpstan/phpstan-phpunit": "^1.0 || ^2.0",
|
||||
"phpunit/phpunit": "^10.5",
|
||||
"squizlabs/php_codesniffer": "^3.7",
|
||||
"tecnickcom/tcpdf": "^6.5"
|
||||
},
|
||||
"suggest": {
|
||||
"dompdf/dompdf": "Option for rendering PDF with PDF Writer",
|
||||
"ext-intl": "PHP Internationalization Functions, required for NumberFormat Wizard and StringHelper::setLocale()",
|
||||
"mitoteam/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers",
|
||||
"mpdf/mpdf": "Option for rendering PDF with PDF Writer",
|
||||
"tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Maarten Balliauw",
|
||||
"homepage": "https://blog.maartenballiauw.be"
|
||||
},
|
||||
{
|
||||
"name": "Mark Baker",
|
||||
"homepage": "https://markbakeruk.net"
|
||||
},
|
||||
{
|
||||
"name": "Franck Lefevre",
|
||||
"homepage": "https://rootslabs.net"
|
||||
},
|
||||
{
|
||||
"name": "Erik Tilt"
|
||||
},
|
||||
{
|
||||
"name": "Adrien Crivelli"
|
||||
},
|
||||
{
|
||||
"name": "Owen Leibman"
|
||||
}
|
||||
],
|
||||
"description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine",
|
||||
"homepage": "https://github.com/PHPOffice/PhpSpreadsheet",
|
||||
"keywords": [
|
||||
"OpenXML",
|
||||
"excel",
|
||||
"gnumeric",
|
||||
"ods",
|
||||
"php",
|
||||
"spreadsheet",
|
||||
"xls",
|
||||
"xlsx"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues",
|
||||
"source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/5.7.0"
|
||||
},
|
||||
"time": "2026-04-20T02:42:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpoption/phpoption",
|
||||
"version": "1.9.5",
|
||||
|
|
|
|||
|
|
@ -13,81 +13,81 @@
|
|||
'nilai' => 'Sedang',
|
||||
'minat' => 'Alam & Tanaman',
|
||||
'pref' => ['Pertanian & Lingkungan'],
|
||||
'cita_cita_keywords' => ['pertanian', 'petani', 'kebun', 'sawah', 'panen', 'tanaman', 'agronomi', 'perkebunan', 'hortikultura'],
|
||||
'cita_cita_keywords' => ['pertanian', 'petani', 'kebun', 'sawah', 'panen', 'tanaman', 'agronomi', 'perkebunan', 'hortikultura', 'farmer', 'agronomist', 'cultivation'],
|
||||
'skills_required' => ['Observasi', 'Kerja Lapangan', 'Pemeliharaan Tanaman'],
|
||||
'weights' => ['nilai' => 0.40, 'minat' => 0.35, 'pref' => 0.15, 'prestasi' => 0.05, 'cita_cita' => 0.05],
|
||||
'weights' => ['nilai' => 0.156, 'minat' => 0.456, 'pref' => 0.256, 'cita_cita' => 0.090, 'prestasi' => 0.040],
|
||||
'match_prob' => ['nilai' => 0.80, 'minat' => 0.90, 'pref' => 0.85, 'prestasi' => 0.65, 'cita_cita' => 0.85],
|
||||
],
|
||||
'Teknologi Pertanian' => [
|
||||
'nilai' => 'Tinggi',
|
||||
'minat' => 'Alam & Tanaman',
|
||||
'pref' => ['Sains & Teknologi', 'Pertanian & Lingkungan'],
|
||||
'cita_cita_keywords' => ['teknologi', 'inovasi', 'otomasi', 'mesin pertanian', 'smart farming', 'teknologi pangan'],
|
||||
'cita_cita_keywords' => ['teknologi', 'inovasi', 'otomasi', 'mesin pertanian', 'smart farming', 'teknologi pangan', 'agritech', 'agricultural engineer'],
|
||||
'skills_required' => ['Problem Solving', 'Teknologi', 'Inovasi'],
|
||||
'weights' => ['nilai' => 0.50, 'minat' => 0.25, 'pref' => 0.15, 'prestasi' => 0.05, 'cita_cita' => 0.05],
|
||||
'weights' => ['nilai' => 0.156, 'minat' => 0.456, 'pref' => 0.256, 'cita_cita' => 0.090, 'prestasi' => 0.040],
|
||||
'match_prob' => ['nilai' => 0.85, 'minat' => 0.90, 'pref' => 0.85, 'prestasi' => 0.75, 'cita_cita' => 0.80],
|
||||
],
|
||||
'Peternakan' => [
|
||||
'nilai' => 'Sedang',
|
||||
'minat' => 'Alam & Tanaman',
|
||||
'pref' => ['Pertanian & Lingkungan', 'Kesehatan & Ilmu Hayat'],
|
||||
'cita_cita_keywords' => ['ternak', 'hewan', 'peternakan', 'peternak', 'sapi', 'ayam', 'unggas', 'veteriner', 'farm'],
|
||||
'cita_cita_keywords' => ['ternak', 'hewan', 'peternakan', 'peternak', 'sapi', 'ayam', 'unggas', 'veteriner', 'farm', 'livestock', 'husbandry', 'zootechnist'],
|
||||
'skills_required' => ['Perawatan Hewan', 'Kesabaran', 'Manajemen'],
|
||||
'weights' => ['nilai' => 0.40, 'minat' => 0.40, 'pref' => 0.10, 'prestasi' => 0.05, 'cita_cita' => 0.05],
|
||||
'weights' => ['nilai' => 0.156, 'minat' => 0.456, 'pref' => 0.256, 'cita_cita' => 0.090, 'prestasi' => 0.040],
|
||||
'match_prob' => ['nilai' => 0.80, 'minat' => 0.88, 'pref' => 0.80, 'prestasi' => 0.65, 'cita_cita' => 0.88],
|
||||
],
|
||||
'Manajemen Agribisnis' => [
|
||||
'nilai' => 'Sedang',
|
||||
'minat' => 'Manajemen & Bisnis',
|
||||
'pref' => ['Bisnis & Manajemen', 'Pertanian & Lingkungan'],
|
||||
'cita_cita_keywords' => ['bisnis', 'agribisnis', 'usaha', 'entrepreneur', 'pengusaha', 'manajer', 'marketing', 'wirausaha'],
|
||||
'cita_cita_keywords' => ['bisnis', 'agribisnis', 'usaha', 'entrepreneur', 'pengusaha', 'manajer', 'marketing', 'wirausaha', 'director', 'executive', 'manager'],
|
||||
'skills_required' => ['Manajemen', 'Bisnis Acumen', 'Komunikasi'],
|
||||
'weights' => ['nilai' => 0.35, 'minat' => 0.40, 'pref' => 0.15, 'prestasi' => 0.05, 'cita_cita' => 0.05],
|
||||
'weights' => ['nilai' => 0.156, 'minat' => 0.456, 'pref' => 0.256, 'cita_cita' => 0.090, 'prestasi' => 0.040],
|
||||
'match_prob' => ['nilai' => 0.75, 'minat' => 0.90, 'pref' => 0.80, 'prestasi' => 0.70, 'cita_cita' => 0.85],
|
||||
],
|
||||
'Teknologi Informasi' => [
|
||||
'nilai' => 'Tinggi',
|
||||
'minat' => 'Logika & Komputer',
|
||||
'pref' => ['Sains & Teknologi'],
|
||||
'cita_cita_keywords' => ['programmer', 'developer', 'coding', 'software', 'web developer', 'hacker', 'it', 'data analyst', 'ai engineer', 'mobile developer'],
|
||||
'cita_cita_keywords' => ['programmer', 'developer', 'coding', 'software', 'web developer', 'hacker', 'it', 'data analyst', 'ai engineer', 'mobile developer', 'devops', 'cloud engineer', 'scientist', 'architect'],
|
||||
'skills_required' => ['Coding', 'Problem Solving', 'Logika'],
|
||||
'weights' => ['nilai' => 0.45, 'minat' => 0.35, 'pref' => 0.12, 'prestasi' => 0.05, 'cita_cita' => 0.03],
|
||||
'weights' => ['nilai' => 0.156, 'minat' => 0.456, 'pref' => 0.256, 'cita_cita' => 0.090, 'prestasi' => 0.040],
|
||||
'match_prob' => ['nilai' => 0.90, 'minat' => 0.92, 'pref' => 0.85, 'prestasi' => 0.75, 'cita_cita' => 0.85],
|
||||
],
|
||||
'Teknik' => [
|
||||
'nilai' => 'Sedang',
|
||||
'minat' => 'Mesin & Listrik',
|
||||
'pref' => ['Sains & Teknologi'],
|
||||
'cita_cita_keywords' => ['mesin', 'bengkel', 'teknisi', 'listrik', 'elektronik', 'otomasi', 'instalasi', 'panel', 'mekatronika', 'maintenance'],
|
||||
'cita_cita_keywords' => ['mesin', 'bengkel', 'teknisi', 'listrik', 'elektronik', 'otomasi', 'instalasi', 'panel', 'mekatronika', 'maintenance', 'engineer', 'technician', 'supervisor'],
|
||||
'skills_required' => ['Mekanik', 'Elektrik', 'Teknik', 'Presisi'],
|
||||
'weights' => ['nilai' => 0.42, 'minat' => 0.38, 'pref' => 0.12, 'prestasi' => 0.05, 'cita_cita' => 0.03],
|
||||
'weights' => ['nilai' => 0.156, 'minat' => 0.456, 'pref' => 0.256, 'cita_cita' => 0.090, 'prestasi' => 0.040],
|
||||
'match_prob' => ['nilai' => 0.82, 'minat' => 0.90, 'pref' => 0.85, 'prestasi' => 0.71, 'cita_cita' => 0.85],
|
||||
],
|
||||
'Kesehatan' => [
|
||||
'nilai' => 'Tinggi',
|
||||
'minat' => 'Pelayanan & Kesehatan',
|
||||
'pref' => ['Kesehatan & Ilmu Hayat'],
|
||||
'cita_cita_keywords' => ['dokter', 'perawat', 'medis', 'gizi', 'kesehatan', 'pelayanan', 'terapis', 'farmasi', 'rekam medis', 'kesehatan masyarakat'],
|
||||
'cita_cita_keywords' => ['dokter', 'perawat', 'medis', 'gizi', 'kesehatan', 'pelayanan', 'terapis', 'farmasi', 'rekam medis', 'kesehatan masyarakat', 'nurse', 'pharmacist', 'nutritionist', 'clinician'],
|
||||
'skills_required' => ['Komunikasi', 'Empati', 'Presisi Medis'],
|
||||
'weights' => ['nilai' => 0.45, 'minat' => 0.35, 'pref' => 0.10, 'prestasi' => 0.05, 'cita_cita' => 0.05],
|
||||
'weights' => ['nilai' => 0.156, 'minat' => 0.456, 'pref' => 0.256, 'cita_cita' => 0.090, 'prestasi' => 0.040],
|
||||
'match_prob' => ['nilai' => 0.90, 'minat' => 0.90, 'pref' => 0.80, 'prestasi' => 0.75, 'cita_cita' => 0.90],
|
||||
],
|
||||
'Bahasa, Komunikasi, dan Pariwisata' => [
|
||||
'nilai' => 'Sedang',
|
||||
'minat' => 'Umum',
|
||||
'pref' => ['Sosial & Humaniora', 'Bisnis & Manajemen'],
|
||||
'cita_cita_keywords' => ['tour guide', 'pariwisata', 'bahasa', 'komunikasi', 'jurnalis', 'marketing', 'public relation', 'content creator', 'hospitality'],
|
||||
'cita_cita_keywords' => ['tour guide', 'pariwisata', 'bahasa', 'komunikasi', 'jurnalis', 'marketing', 'public relation', 'content creator', 'hospitality', 'ambassador', 'presenter', 'broadcaster'],
|
||||
'skills_required' => ['Komunikasi', 'Bahasa', 'Kepribadian'],
|
||||
'weights' => ['nilai' => 0.30, 'minat' => 0.40, 'pref' => 0.15, 'prestasi' => 0.08, 'cita_cita' => 0.07],
|
||||
'weights' => ['nilai' => 0.156, 'minat' => 0.456, 'pref' => 0.256, 'cita_cita' => 0.090, 'prestasi' => 0.040],
|
||||
'match_prob' => ['nilai' => 0.70, 'minat' => 0.85, 'pref' => 0.80, 'prestasi' => 0.70, 'cita_cita' => 0.85],
|
||||
],
|
||||
'Bisnis' => [
|
||||
'nilai' => 'Sedang',
|
||||
'minat' => 'Manajemen & Bisnis',
|
||||
'pref' => ['Bisnis & Manajemen'],
|
||||
'cita_cita_keywords' => ['manager', 'pimpinan', 'bisnis', 'accounting', 'marketing', 'sales', 'akuntan', 'keuangan', 'bank'],
|
||||
'cita_cita_keywords' => ['manager', 'pimpinan', 'bisnis', 'accounting', 'marketing', 'sales', 'akuntan', 'keuangan', 'bank', 'finance', 'accountant', 'auditor'],
|
||||
'skills_required' => ['Manajemen', 'Leadership', 'Keuangan'],
|
||||
'weights' => ['nilai' => 0.35, 'minat' => 0.40, 'pref' => 0.15, 'prestasi' => 0.05, 'cita_cita' => 0.05],
|
||||
'weights' => ['nilai' => 0.156, 'minat' => 0.456, 'pref' => 0.256, 'cita_cita' => 0.090, 'prestasi' => 0.040],
|
||||
'match_prob' => ['nilai' => 0.75, 'minat' => 0.90, 'pref' => 0.80, 'prestasi' => 0.70, 'cita_cita' => 0.85],
|
||||
],
|
||||
],
|
||||
|
|
|
|||
|
|
@ -15,35 +15,34 @@
|
|||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$driver = DB::connection()->getDriverName();
|
||||
|
||||
// Skip for SQLite since it has limited ALTER TABLE support
|
||||
if ($driver === 'sqlite') {
|
||||
return;
|
||||
}
|
||||
|
||||
// For MySQL/PostgreSQL: drop unnecessary columns
|
||||
$columnsToDrop = [];
|
||||
foreach (['success_status', 'ranking_saat_rekomendasi', 'predicted_score', 'ipk_lulus', 'karir_outcome'] as $col) {
|
||||
if (Schema::hasColumn('alumni', $col)) {
|
||||
$columnsToDrop[] = $col;
|
||||
Schema::table('alumni', function (Blueprint $table) {
|
||||
// Drop unnecessary columns
|
||||
if (Schema::hasColumn('alumni', 'success_status')) {
|
||||
$table->dropColumn('success_status');
|
||||
}
|
||||
}
|
||||
if (Schema::hasColumn('alumni', 'ranking_saat_rekomendasi')) {
|
||||
$table->dropColumn('ranking_saat_rekomendasi');
|
||||
}
|
||||
if (Schema::hasColumn('alumni', 'predicted_score')) {
|
||||
$table->dropColumn('predicted_score');
|
||||
}
|
||||
if (Schema::hasColumn('alumni', 'ipk_lulus')) {
|
||||
$table->dropColumn('ipk_lulus');
|
||||
}
|
||||
if (Schema::hasColumn('alumni', 'karir_outcome')) {
|
||||
$table->dropColumn('karir_outcome');
|
||||
}
|
||||
});
|
||||
|
||||
if (!empty($columnsToDrop)) {
|
||||
Schema::table('alumni', function (Blueprint $table) use ($columnsToDrop) {
|
||||
$table->dropColumn($columnsToDrop);
|
||||
});
|
||||
}
|
||||
|
||||
// Drop and recreate preferensi_studi column
|
||||
if (Schema::hasColumn('alumni', 'preferensi_studi')) {
|
||||
Schema::table('alumni', function (Blueprint $table) {
|
||||
// Update preferensi_studi dengan raw SQL untuk menghindari Doctrine enum issue
|
||||
Schema::table('alumni', function (Blueprint $table) {
|
||||
if (Schema::hasColumn('alumni', 'preferensi_studi')) {
|
||||
$table->dropColumn('preferensi_studi');
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Schema::table('alumni', function (Blueprint $table) {
|
||||
// Add kembali preferensi_studi dengan enum values yang tepat
|
||||
$table->enum('preferensi_studi', [
|
||||
'Sains & Teknologi',
|
||||
'Pertanian & Lingkungan',
|
||||
|
|
@ -56,7 +55,9 @@ public function up(): void
|
|||
|
||||
public function down(): void
|
||||
{
|
||||
// Rollback logic (if needed)
|
||||
Schema::table('alumni', function (Blueprint $table) {
|
||||
//
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
// Drop kolom nilai mapel individual, keep nilai_rata_rata
|
||||
Schema::table('alumni', function (Blueprint $table) {
|
||||
$table->dropColumn([
|
||||
'mtk',
|
||||
'fisika',
|
||||
'kimia',
|
||||
'biologi',
|
||||
'ekonomi',
|
||||
'geografi',
|
||||
'sosiologi',
|
||||
'sejarah'
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('alumni', function (Blueprint $table) {
|
||||
$table->float('mtk')->nullable();
|
||||
$table->float('fisika')->nullable();
|
||||
$table->float('kimia')->nullable();
|
||||
$table->float('biologi')->nullable();
|
||||
$table->float('ekonomi')->nullable();
|
||||
$table->float('geografi')->nullable();
|
||||
$table->float('sosiologi')->nullable();
|
||||
$table->float('sejarah')->nullable();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
class BkSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$bkUsers = [
|
||||
['email' => 'gurubk1@polije.ac.id', 'name' => 'Konselor BK 1', 'password' => 'bk123456'],
|
||||
['email' => 'gurubk2@polije.ac.id', 'name' => 'Konselor BK 2', 'password' => 'bk234567'],
|
||||
['email' => 'gurubk3@polije.ac.id', 'name' => 'Konselor BK 3', 'password' => 'bk345678'],
|
||||
];
|
||||
|
||||
foreach ($bkUsers as $u) {
|
||||
User::firstOrCreate(
|
||||
['email' => $u['email']],
|
||||
[
|
||||
'name' => $u['name'],
|
||||
'password' => Hash::make($u['password']),
|
||||
'role' => 'bk',
|
||||
'email_verified_at' => now(),
|
||||
]
|
||||
);
|
||||
|
||||
echo "Created or exists: {$u['email']} / {$u['password']}\n";
|
||||
}
|
||||
|
||||
echo "✅ 3 BK accounts seeded.\n";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,331 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Recommendation;
|
||||
use App\Models\ChatHistory;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class RecommendationAndChatSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
// Data rekomendasi detail dengan bobot ROC
|
||||
$recommendationData = [
|
||||
// Siswa IPA - Teknik & IT oriented
|
||||
[
|
||||
'user_id' => 2, // Siswa 1
|
||||
'mtk' => 85, 'fisika' => 88, 'kimia' => 82, 'biologi' => 75,
|
||||
'minat' => 'Suka coding dan bikin aplikasi, interested di cyber security juga',
|
||||
'preferensi_studi' => 'Sains & Teknologi',
|
||||
'cita_cita' => 'Jadi software engineer di startup lokal, pengen develop aplikasi yang bermanfaat',
|
||||
'prestasi' => 'Juara 2 Kompetisi Programming tingkat provinsi tahun lalu',
|
||||
],
|
||||
[
|
||||
'user_id' => 3, // Siswa 2
|
||||
'mtk' => 92, 'fisika' => 90, 'kimia' => 88, 'biologi' => 85,
|
||||
'minat' => 'Sangat tertarik dengan robotika dan automation, suka ngutak-atik elektronik',
|
||||
'preferensi_studi' => 'Sains & Teknologi',
|
||||
'cita_cita' => 'Ingin bekerja di industri manufaktur sebagai engineer untuk bikin sistem otomasi',
|
||||
'prestasi' => 'Finalis Olimpiade Fisika Nasional, sudah ada 3 paten design robotik',
|
||||
],
|
||||
[
|
||||
'user_id' => 4, // Siswa 3
|
||||
'mtk' => 78, 'fisika' => 81, 'kimia' => 79, 'biologi' => 92,
|
||||
'minat' => 'Passionate tentang bioteknologi dan kesehatan, sering baca tentang genomik',
|
||||
'preferensi_studi' => 'Kesehatan & Ilmu Hayat',
|
||||
'cita_cita' => 'Mau lanjut ke kedokteran atau jadi peneliti di bidang biomedis',
|
||||
'prestasi' => 'Presentasi paper biologi di seminar nasional, pernah volunteer di klinik',
|
||||
],
|
||||
[
|
||||
'user_id' => 5, // Siswa 4
|
||||
'mtk' => 88, 'fisika' => 85, 'kimia' => 90, 'biologi' => 80,
|
||||
'minat' => 'Suka kimia organik, proses manufaktur, dan industri pertanian',
|
||||
'preferensi_studi' => 'Pertanian & Lingkungan',
|
||||
'cita_cita' => 'Bikin startup agritech yang sustainable, pengen improve produktivitas petani lokal',
|
||||
'prestasi' => 'Juara Karya Ilmiah tentang pupuk organik, punya UKM pupuk sendiri',
|
||||
],
|
||||
[
|
||||
'user_id' => 6, // Siswa 5
|
||||
'mtk' => 82, 'fisika' => 84, 'kimia' => 86, 'biologi' => 88,
|
||||
'minat' => 'Selalu tertarik dengan peternakan modern dan nutrisi hewan',
|
||||
'preferensi_studi' => 'Pertanian & Lingkungan',
|
||||
'cita_cita' => 'Jadi manager farm modern atau ahli nutrisi ternak, pengen export hasil',
|
||||
'prestasi' => 'Punya kandang ternak sapi yang sudah operational, mengikuti workshop peternakan',
|
||||
],
|
||||
|
||||
// Siswa IPS - Bisnis & Sosial oriented
|
||||
[
|
||||
'user_id' => 7, // Siswa 6
|
||||
'ekonomi' => 85, 'geografi' => 88, 'sosiologi' => 80, 'sejarah' => 78,
|
||||
'minat' => 'Suka analisa bisnis dan strategi marketing, aktif di club entrepreneur',
|
||||
'preferensi_studi' => 'Bisnis & Manajemen',
|
||||
'cita_cita' => 'Mau founder perusahaan logistik yang bisa layani seluruh Indonesia',
|
||||
'prestasi' => 'Ketua OSIS 2 tahun, udah coba business plan shipping dengan teman',
|
||||
],
|
||||
[
|
||||
'user_id' => 8, // Siswa 7
|
||||
'ekonomi' => 90, 'geografi' => 85, 'sosiologi' => 88, 'sejarah' => 82,
|
||||
'minat' => 'Tertarik accounting dan finance, suka ngitung dan detail',
|
||||
'preferensi_studi' => 'Bisnis & Manajemen',
|
||||
'cita_cita' => 'Jadi akuntan profesional dan buka kantor akuntan sendiri',
|
||||
'prestasi' => 'Juara Lomba Akuntansi, sudah belajar MYOB dan software akuntansi',
|
||||
],
|
||||
[
|
||||
'user_id' => 9, // Siswa 8
|
||||
'ekonomi' => 78, 'geografi' => 82, 'sosiologi' => 92, 'sejarah' => 88,
|
||||
'minat' => 'Sangat peduli sosial dan keadilan, aktif di organisasi kemanusiaan',
|
||||
'preferensi_studi' => 'Sosial & Humaniora',
|
||||
'cita_cita' => 'Jadi social worker atau policy maker yang bisa bantu masyarakat kecil',
|
||||
'prestasi' => 'Koordinator program CSR, pernah design program beasiswa untuk anak kurang mampu',
|
||||
],
|
||||
[
|
||||
'user_id' => 10, // Siswa 9
|
||||
'ekonomi' => 88, 'geografi' => 90, 'sosiologi' => 85, 'sejarah' => 86,
|
||||
'minat' => 'Hobi pariwisata dan guide, suka cerita tentang budaya daerah',
|
||||
'preferensi_studi' => 'Sosial & Humaniora',
|
||||
'cita_cita' => 'Develop destinasi pariwisata lokal yang sustainable, buat kuliner branded',
|
||||
'prestasi' => 'Sudah jadi tour guide 6 bulan, punya grup social media wisata lokal',
|
||||
],
|
||||
[
|
||||
'user_id' => 11, // Siswa 10
|
||||
'ekonomi' => 82, 'geografi' => 88, 'sosiologi' => 80, 'sejarah' => 85,
|
||||
'minat' => 'Senang dengan komunikasi dan public speaking, aktif di debat club',
|
||||
'preferensi_studi' => 'Sosial & Humaniora',
|
||||
'cita_cita' => 'Jadi komunikasi profesional atau journalist yang investigatif',
|
||||
'prestasi' => 'Finalis Debat Nasional, pernah bikin dokumenter lokal, punya podcast',
|
||||
],
|
||||
|
||||
// Tambahan data diverse
|
||||
[
|
||||
'user_id' => 2,
|
||||
'mtk' => 79, 'fisika' => 75, 'kimia' => 80, 'biologi' => 88,
|
||||
'minat' => 'Biologi laut dan konservasi, sering ke pantai untuk research',
|
||||
'preferensi_studi' => 'Pertanian & Lingkungan',
|
||||
'cita_cita' => 'Jadi peneliti laut atau oceanographer, lindungi ekosistem terumbu karang',
|
||||
'prestasi' => 'Peserta program konservasi laut, pernah publikasi artikel tentang coral bleaching',
|
||||
],
|
||||
[
|
||||
'user_id' => 3,
|
||||
'mtk' => 86, 'fisika' => 92, 'kimia' => 85, 'biologi' => 78,
|
||||
'minat' => 'Tertarik mesin presisi dan manufacturing, suka dismantle dan assemble',
|
||||
'preferensi_studi' => 'Sains & Teknologi',
|
||||
'cita_cita' => 'Jadi chief engineer di pabrik industri atau buka workshop manufaktur',
|
||||
'prestasi' => 'Juara kompetisi mesin, punya skill CAD dan CNC machining',
|
||||
],
|
||||
[
|
||||
'user_id' => 4,
|
||||
'mtk' => 81, 'fisika' => 80, 'kimia' => 88, 'biologi' => 90,
|
||||
'minat' => 'Farmasi dan obat-obatan, sering ikut diskusi medical science',
|
||||
'preferensi_studi' => 'Kesehatan & Ilmu Hayat',
|
||||
'cita_cita' => 'Jadi apoteker atau researcher farmasi, develop obat lokal berkualitas',
|
||||
'prestasi' => 'Internship di apotek besar, belajar formulation dan quality control',
|
||||
],
|
||||
[
|
||||
'user_id' => 5,
|
||||
'mtk' => 84, 'fisika' => 82, 'kimia' => 92, 'biologi' => 85,
|
||||
'minat' => 'Proses industri dan chemical engineering, suka tonton cara produksi',
|
||||
'preferensi_studi' => 'Sains & Teknologi',
|
||||
'cita_cita' => 'Jadi chemical engineer, optimalkan proses produksi di industri tekstil',
|
||||
'prestasi' => 'Design proposal chemical processing untuk usaha keluarga',
|
||||
],
|
||||
[
|
||||
'user_id' => 6,
|
||||
'mtk' => 77, 'fisika' => 79, 'kimia' => 81, 'biologi' => 90,
|
||||
'minat' => 'Veteriner dan kesehatan hewan, punya pengalaman tangani hewan sakit',
|
||||
'preferensi_studi' => 'Kesehatan & Ilmu Hayat',
|
||||
'cita_cita' => 'Jadi dokter hewan dan buka klinik hewan modern di daerah',
|
||||
'prestasi' => 'Volunteer di animal shelter, treatment beberapa hewan terlantar',
|
||||
],
|
||||
[
|
||||
'user_id' => 7,
|
||||
'ekonomi' => 82, 'geografi' => 85, 'sosiologi' => 78, 'sejarah' => 80,
|
||||
'minat' => 'Digital marketing dan e-commerce, aktif buat konten di social media',
|
||||
'preferensi_studi' => 'Bisnis & Manajemen',
|
||||
'cita_cita' => 'Jadi digital marketing specialist atau content creator profesional',
|
||||
'prestasi' => 'Manage social media bisnis teman, follower tumbuh jadi 50 ribu',
|
||||
],
|
||||
[
|
||||
'user_id' => 8,
|
||||
'ekonomi' => 88, 'geografi' => 82, 'sosiologi' => 85, 'sejarah' => 84,
|
||||
'minat' => 'Banking dan investment, suka belajar tentang saham dan cryptocurrency',
|
||||
'preferensi_studi' => 'Bisnis & Manajemen',
|
||||
'cita_cita' => 'Jadi financial advisor atau investment manager di bank besar',
|
||||
'prestasi' => 'Peserta kompetisi investment game, udah trading saham sendiri',
|
||||
],
|
||||
[
|
||||
'user_id' => 9,
|
||||
'ekonomi' => 75, 'geografi' => 88, 'sosiologi' => 90, 'sejarah' => 85,
|
||||
'minat' => 'Pengembangan masyarakat dan pendidikan, pernah ajar anak-anak kurang mampu',
|
||||
'preferensi_studi' => 'Sosial & Humaniora',
|
||||
'cita_cita' => 'Jadi pendidik atau foundation director yang bisa rubah hidup banyak anak',
|
||||
'prestasi' => 'Founder program belajar gratis untuk anak pinggiran, sudah 50 peserta',
|
||||
],
|
||||
[
|
||||
'user_id' => 10,
|
||||
'ekonomi' => 85, 'geografi' => 92, 'sosiologi' => 88, 'sejarah' => 86,
|
||||
'minat' => 'Travel dan budaya lokal, suka explore setiap daerah dan documenting',
|
||||
'preferensi_studi' => 'Sosial & Humaniora',
|
||||
'cita_cita' => 'Jadi travel blogger profesional atau cultural ambassador',
|
||||
'prestasi' => 'Blog wisata udah 100k visitors, punya instagram tentang kuliner lokal',
|
||||
],
|
||||
[
|
||||
'user_id' => 11,
|
||||
'ekonomi' => 80, 'geografi' => 85, 'sosiologi' => 88, 'sejarah' => 90,
|
||||
'minat' => 'Sejarah dan warisan budaya, aktif di club heritage preservation',
|
||||
'preferensi_studi' => 'Sosial & Humaniora',
|
||||
'cita_cita' => 'Jadi historian atau kurator museum, lestarikan warisan budaya Indonesia',
|
||||
'prestasi' => 'Dokumentasi situs sejarah lokal, pernah present di forum budaya',
|
||||
],
|
||||
[
|
||||
'user_id' => 2,
|
||||
'mtk' => 88, 'fisika' => 86, 'kimia' => 84, 'biologi' => 82,
|
||||
'minat' => 'AI dan machine learning, ikut online course dan kaggle competition',
|
||||
'preferensi_studi' => 'Sains & Teknologi',
|
||||
'cita_cita' => 'Jadi AI specialist atau data scientist, develop solution untuk Indonesia',
|
||||
'prestasi' => 'Rank 500 di kaggle, bikin model prediksi untuk project sekolah',
|
||||
],
|
||||
[
|
||||
'user_id' => 3,
|
||||
'mtk' => 89, 'fisika' => 88, 'kimia' => 87, 'biologi' => 75,
|
||||
'minat' => 'Game development dan creative coding, punya beberapa game project',
|
||||
'preferensi_studi' => 'Sains & Teknologi',
|
||||
'cita_cita' => 'Jadi game developer di studio internasional atau bikin studio sendiri',
|
||||
'prestasi' => 'Game yang dibuat udah dimainkan ribuan orang, dapat award di expo',
|
||||
],
|
||||
[
|
||||
'user_id' => 4,
|
||||
'mtk' => 80, 'fisika' => 79, 'kimia' => 90, 'biologi' => 92,
|
||||
'minat' => 'Gizi dan kesehatan masyarakat, aktif di program kesehatan komunitas',
|
||||
'preferensi_studi' => 'Kesehatan & Ilmu Hayat',
|
||||
'cita_cita' => 'Jadi ahli gizi profesional, program nutrisi untuk anak Indonesia',
|
||||
'prestasi' => 'Design program gizi untuk sekolah di daerah tertinggal, pernah grant',
|
||||
],
|
||||
[
|
||||
'user_id' => 5,
|
||||
'mtk' => 83, 'fisika' => 84, 'kimia' => 89, 'biologi' => 86,
|
||||
'minat' => 'Sustainability dan green technology, interested di renewable energy',
|
||||
'preferensi_studi' => 'Pertanian & Lingkungan',
|
||||
'cita_cita' => 'Jadi engineer yang fokus sustainable development dan clean energy',
|
||||
'prestasi' => 'Project solar panel untuk sekolah, design water management system',
|
||||
],
|
||||
[
|
||||
'user_id' => 6,
|
||||
'mtk' => 81, 'fisika' => 80, 'kimia' => 82, 'biologi' => 89,
|
||||
'minat' => 'Agronomi modern dan precision farming, ikuti webinar tentang smart farm',
|
||||
'preferensi_studi' => 'Pertanian & Lingkungan',
|
||||
'cita_cita' => 'Jadi smart farmer yang pakai teknologi untuk maksimalkan hasil panen',
|
||||
'prestasi' => 'Pilot project smart farming dengan sensor IoT, hasil bagus',
|
||||
],
|
||||
[
|
||||
'user_id' => 7,
|
||||
'ekonomi' => 84, 'geografi' => 86, 'sosiologi' => 82, 'sejarah' => 76,
|
||||
'minat' => 'Supply chain dan logistik, suka pelajari efficient delivery systems',
|
||||
'preferensi_studi' => 'Bisnis & Manajemen',
|
||||
'cita_cita' => 'Jadi supply chain director atau logistics innovator untuk e-commerce',
|
||||
'prestasi' => 'Analyze supply chain usaha keluarga, improve efficiency 40 persen',
|
||||
],
|
||||
[
|
||||
'user_id' => 8,
|
||||
'ekonomi' => 87, 'geografi' => 84, 'sosiologi' => 86, 'sejarah' => 83,
|
||||
'minat' => 'Corporate finance dan management accounting, belajar SAP dan MYOB',
|
||||
'preferensi_studi' => 'Bisnis & Manajemen',
|
||||
'cita_cita' => 'Jadi CFO atau finance director di perusahaan multinational',
|
||||
'prestasi' => 'Intern di finance department perusahaan, handle reconciliation',
|
||||
],
|
||||
[
|
||||
'user_id' => 9,
|
||||
'ekonomi' => 76, 'geografi' => 87, 'sosiologi' => 92, 'sejarah' => 88,
|
||||
'minat' => 'Community development dan empowerment, pernah training leadership',
|
||||
'preferensi_studi' => 'Sosial & Humaniora',
|
||||
'cita_cita' => 'Jadi community development officer di NGO atau social enterprise',
|
||||
'prestasi' => 'Facilitate community meeting dan program design untuk 500 orang',
|
||||
],
|
||||
[
|
||||
'user_id' => 10,
|
||||
'ekonomi' => 86, 'geografi' => 89, 'sosiologi' => 87, 'sejarah' => 85,
|
||||
'minat' => 'Hospitality dan business management, experience internship di hotel',
|
||||
'preferensi_studi' => 'Bisnis & Manajemen',
|
||||
'cita_cita' => 'Jadi hotel manager atau develop hospitality brand lokal kelas dunia',
|
||||
'prestasi' => 'Manage event 200 orang, guest satisfaction score 95 persen',
|
||||
],
|
||||
];
|
||||
|
||||
// Insert recommendations
|
||||
foreach ($recommendationData as $data) {
|
||||
Recommendation::create(array_merge($data, [
|
||||
'hasil_rekomendasi' => [
|
||||
[
|
||||
'jurusan' => 'Teknik Informatika',
|
||||
'skor' => rand(70, 95) / 100,
|
||||
'detail' => [
|
||||
'nilai' => rand(60, 95) / 100,
|
||||
'minat' => rand(70, 98) / 100,
|
||||
'pref' => rand(60, 95) / 100,
|
||||
'cita' => rand(75, 98) / 100,
|
||||
'prestasi' => rand(50, 90) / 100,
|
||||
]
|
||||
]
|
||||
]
|
||||
]));
|
||||
}
|
||||
|
||||
// Data chat history yang natural dan tidak template
|
||||
$chatData = [
|
||||
// Chat tentang rekomendasi
|
||||
['user_id' => 2, 'id_sesi' => 'session_1', 'pertanyaan' => 'Jadi menurut sistem saya cocok ambil jurusan apa ya?', 'jawaban' => 'Berdasarkan hasil analisis, untuk profile Anda yang nilai MTK-Fisika bagus dan minat coding kuat, Teknik Informatika adalah pilihan yang selaras. Anda bisa fokus cybersecurity atau development.'],
|
||||
['user_id' => 2, 'id_sesi' => 'session_1', 'pertanyaan' => 'Cybersecurity lebih amankan karir atau development?', 'jawaban' => 'Dua-duanya prospek bagus. Cybersecurity ada demand dari government dan finance yang stabil. Development skills lebih flexible bisa startup atau big tech. Lihat passion Anda lebih ke yang mana.'],
|
||||
['user_id' => 3, 'id_sesi' => 'session_2', 'pertanyaan' => 'Saya pengen jurusan yang bisa langsung applicable untuk robotika', 'jawaban' => 'Untuk robotika, Teknik Elektro atau Teknik Mesin sangat applicable. Dengan score fisika 90 Anda, dua jurusan ini cocok. Teknik Elektro kalau fokus control system, Teknik Mesin kalau fokus mechanical design.'],
|
||||
['user_id' => 3, 'id_sesi' => 'session_2', 'pertanyaan' => 'Lebih pilih mana sih?', 'jawaban' => 'Lihat passion Anda lebih ke elektrik atau mekanik? Kalau suka coding dan control systems, Teknik Elektro. Kalau suka design fisik dan assemble-dismantle, Teknik Mesin. Keduanya relevant untuk robotika.'],
|
||||
['user_id' => 4, 'id_sesi' => 'session_3', 'pertanyaan' => 'Bisa lanjut kedokteran dari TPI nggak?', 'jawaban' => 'Untuk kedokteran, value akademik dan jalur masuk lebih strict dibanding TPI. Tapi calondidik bisa persiapan dari TPI, terutama biologi dan kimia. Fokus banget di olimpiade sains untuk booster nilai masuk.'],
|
||||
['user_id' => 4, 'id_sesi' => 'session_3', 'pertanyaan' => 'TPI itu apa ya singkatannya?', 'jawaban' => 'Teknik Pertanian dan Industri di Polije. Tapi kalau target kedokteran, mungkin bisa cek juga program kesehatan dulu untuk experience, atau aplikasi kedokteran pure dari outcome awal.'],
|
||||
|
||||
// Chat tentang karir
|
||||
['user_id' => 5, 'id_sesi' => 'session_4', 'pertanyaan' => 'Agribusiness itu nanti kerjanya kayak apa?', 'jawaban' => 'Bisa jadi manager farm, business development untuk agritech, supply chain untuk produk pertanian, atau entrepreneur. Banyak pilihan tergantung spesialisasi yang dipilih di kuliah.'],
|
||||
['user_id' => 5, 'id_sesi' => 'session_4', 'pertanyaan' => 'Gaji fresh graduate agritech berapa kira-kira?', 'jawaban' => 'Startup agritech biasanya 4-6 juta tergantung posisi dan lokasi. Corporate agribusiness bisa 5-8 juta. Tapi kalau entrepreneurship sendiri, income tergantung success rate usaha Anda.'],
|
||||
|
||||
// Chat tentang program belajar
|
||||
['user_id' => 6, 'id_sesi' => 'session_5', 'pertanyaan' => 'Polije punya program internship nggak?', 'jawaban' => 'Ada, biasanya di semester akhir. Untuk program Peternakan, ada partnership dengan farm modern dan feed company. Cek dengan prodi langsung untuk detail placement.'],
|
||||
['user_id' => 6, 'id_sesi' => 'session_5', 'pertanyaan' => 'Boleh apply internship di abroad nggak?', 'jawaban' => 'Tergantung kebijakan prodi, tapi generally bisa diskusi dengan pembimbing. Ada beberapa students yang udah internship di Malaysia atau Thailand. Usahakan komunikasi dengan prodi sejak early semester.'],
|
||||
|
||||
// Chat tentang persiapan
|
||||
['user_id' => 7, 'id_sesi' => 'session_6', 'pertanyaan' => 'Perlu les atau belajar sendiri sebelum masuk kuliah?', 'jawaban' => 'Tergantung kesiapan Anda. Kalau values academic udah solid, bisa self-study dengan referensi online. Tapi kalau mau jadi standout di semester pertama, bisa ambil kursus online tentang fondasi subject.'],
|
||||
['user_id' => 7, 'id_sesi' => 'session_6', 'pertanyaan' => 'Ada rekomendasi website atau platform belajar nggak?', 'jawaban' => 'Udah banyak. Coursera, Udemy, Khan Academy bagus untuk foundational. Indonesia ada Ruangguru atau Zenius. Tapi yang paling penting engagement sama dosen dan teman-teman di kelas nanti.'],
|
||||
|
||||
// Chat tentang keputusan
|
||||
['user_id' => 8, 'id_sesi' => 'session_7', 'pertanyaan' => 'Agak ragu antara Akuntansi sama Management', 'jawaban' => 'Dua jurusan ini beda fokus. Akuntansi lebih technical dan detail-oriented, Management lebih strategic dan leader-focused. Lihat strength Anda: detail dan angka atau big picture dan people? Itu bisa guide decision.'],
|
||||
['user_id' => 8, 'id_sesi' => 'session_7', 'pertanyaan' => 'Kalau pilih Management, bisa dapat nilai invest yang bagus nggak dari sekolah?', 'jawaban' => 'Bisa. Dengan nilai ekonomi 90 Anda, management akan mudah. Cuma akuntansi mungkin lebih certified langsung (JATS). Management lebih butuh experience dan soft skill yang dibangun di luar kelas.'],
|
||||
|
||||
// Chat tentang scholarship
|
||||
['user_id' => 9, 'id_sesi' => 'session_8', 'pertanyaan' => 'Ada beasiswa untuk jurusan sosial nggak?', 'jawaban' => 'Ada beberapa dari government dan foundation. Polije ada beasiswa akademik based on nilai. NGO juga sering sponsor untuk program kemanusiaan atau education. Tapi bisa juga dari corporate yang peduli CSR.'],
|
||||
['user_id' => 9, 'id_sesi' => 'session_8', 'pertanyaan' => 'Requirement beasiswa biasanya apa?', 'jawaban' => 'Tergantung sumber. Academic scholarship butuh nilai bagus. Need-based butuh dokumentasi ekonomi. Full scholarship biasanya maintain GPA minimal 3.0 dan aktif di organisasi sosial.'],
|
||||
|
||||
// Chat tentang prospek kerja
|
||||
['user_id' => 10, 'id_sesi' => 'session_9', 'pertanyaan' => 'Pariwisata di Indonesia prospeknya gimana pasca COVID?', 'jawaban' => 'Recovery udah bagus. Domestic tourism naik, international mulai balik. Tapi industry butuh profesional yang innovative, bukan hanya tour guide. Positioning diri Anda sebagai strategic player, bukan operational level.'],
|
||||
['user_id' => 10, 'id_sesi' => 'session_9', 'pertanyaan' => 'Jadi hospitality manager itu punya team berapa biasanya?', 'jawaban' => 'Tergantung size hotel. Small hotel (50 kamar) mungkin 5-10 staff. Mid-range (100-200 kamar) 20-50 staff. Besar (300+ kamar) bisa 100+. Semakin besar, semakin kompleks management-nya.'],
|
||||
|
||||
// Chat about challenges
|
||||
['user_id' => 11, 'id_sesi' => 'session_10', 'pertanyaan' => 'Komunikasi itu subject berat nggak di kuliah?', 'jawaban' => 'Tidak terlalu berat seperti teknik atau science. Tapi demanding dalam hal project, presentasi, dan banyak reading. Kalau Anda suka talking dan creative, ini cocok. Tantangan lebih ke academic rigor, bukan mathematical complexity.'],
|
||||
['user_id' => 11, 'id_sesi' => 'session_10', 'pertanyaan' => 'Ada lab atau praktik langsung nggak?', 'jawaban' => 'Ada. Biasanya ada lab communicative, media production, bahkan ada broadcast studio. Praktik langsung dengan project nyata untuk client atau media partner. Itu yang membuat komunikasi menarik.'],
|
||||
|
||||
// More natural chats
|
||||
['user_id' => 2, 'id_sesi' => 'session_11', 'pertanyaan' => 'Kenalin dong senior-senior di Teknik Informatika', 'jawaban' => 'Udah ada program mentoring di Polije. Senior bisa di-connect melalui alumni network atau student organization. Mereka helpful banget share experience dan tips lolos interview di tech company.'],
|
||||
['user_id' => 3, 'id_sesi' => 'session_12', 'pertanyaan' => 'Lab di Teknik Elektro lengkap nggak untuk robotika?', 'jawaban' => 'Lumayan lengkap. Ada microcontroller lab, digital logic lab. Untuk advanced robotics, bisa kolaborasi dengan Teknik Mesin juga. Ada makerspace bersama yang membantu student projects.'],
|
||||
['user_id' => 4, 'id_sesi' => 'session_13', 'pertanyaan' => 'Kesehatan di Polije fokus apa ya?', 'jawaban' => 'Ada program Ilmu Gizi, Teknologi Laboratorium Medis, dan Kesehatan Masyarakat. Fokus ke applied health, tidak pure medical science. Cocok untuk Anda yang peduli community health.'],
|
||||
['user_id' => 5, 'id_sesi' => 'session_14', 'pertanyaan' => 'Mahasiswa agribusiness banyak nggak?', 'jawaban' => 'Cukup banyak, sekitar 100 per tahun. Intake lumayan tinggi karena demand industri. Networking sama peers bisa bagus untuk future business partnership.'],
|
||||
['user_id' => 6, 'id_sesi' => 'session_15', 'pertanyaan' => 'Peternakan di Polije punya farm sendiri nggak?', 'jawaban' => 'Ada. Farm sendiri untuk praktik langsung sama students. Facilities bagus, ada kandang modern, equipment hewan medis. Bisa langsung hands-on dari semester pertama.'],
|
||||
['user_id' => 7, 'id_sesi' => 'session_16', 'pertanyaan' => 'Manajemen jurusan itu terlalu general nggak?', 'jawaban' => 'Dalam kuliah ada specialization. Semester awal general foundation, nanti semester 5-6 bisa pilih tracks seperti operations, finance, marketing, atau digital business. Jadi nggak general-general amat.'],
|
||||
['user_id' => 8, 'id_sesi' => 'session_17', 'pertanyaan' => 'Akuntansi itu paling banyak ngitung nggak si?', 'jawaban' => 'Lumayan. Tapi sekarang accounting lebih ke understanding system, analysis, dan business advisory. Ngitung masih ada tapi banyak software yang bantu. Focus lebih ke thinking skills.'],
|
||||
['user_id' => 9, 'id_sesi' => 'session_18', 'pertanyaan' => 'Social welfare program itu study apa aja sih?', 'jawaban' => 'Social policy, community development methods, case management, research methods. Praktik langsung di komunitas juga. Banyak fieldwork yang meaningful.'],
|
||||
['user_id' => 10, 'id_sesi' => 'session_19', 'pertanyaan' => 'Tourism management itu enaknya atau challenging?', 'jawaban' => 'Enaklah karena hands-on banyak, networking luas. Challenging dari fast-paced industry yang selalu berubah. Tapi kalau Anda adaptable dan social, ini worth it.'],
|
||||
];
|
||||
|
||||
// Insert chat histories
|
||||
foreach ($chatData as $chat) {
|
||||
ChatHistory::create($chat);
|
||||
}
|
||||
|
||||
echo "✅ Created " . count($recommendationData) . " recommendations and " . count($chatData) . " chat histories\n";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,272 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Script untuk Import Data Alumni dari Excel ke Database SPK Jurusan Polije
|
||||
Membaca file Excel dan memasukkan ke tabel alumni
|
||||
"""
|
||||
|
||||
import pandas as pd
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# Add Laravel project to path
|
||||
project_path = Path(__file__).parent
|
||||
sys.path.insert(0, str(project_path))
|
||||
|
||||
# Import database connection
|
||||
import subprocess
|
||||
import json
|
||||
|
||||
def read_excel_file(file_path):
|
||||
"""
|
||||
Membaca file Excel dan return dataframe
|
||||
"""
|
||||
try:
|
||||
print(f"📂 Membaca file: {file_path}")
|
||||
df = pd.read_excel(file_path)
|
||||
print(f"✓ File berhasil dibaca")
|
||||
print(f" Baris: {len(df)}")
|
||||
print(f" Kolom: {list(df.columns)}")
|
||||
return df
|
||||
except Exception as e:
|
||||
print(f"✗ Error membaca file: {e}")
|
||||
return None
|
||||
|
||||
def normalize_column_names(df):
|
||||
"""
|
||||
Normalize nama kolom Excel ke format database
|
||||
"""
|
||||
# Mapping kemungkinan nama kolom di Excel
|
||||
column_mapping = {
|
||||
'nama': 'nama_alumni',
|
||||
'nama alumni': 'nama_alumni',
|
||||
'nis': 'nis',
|
||||
'no. induk siswa': 'nis',
|
||||
'kelompok asal': 'kelompok_asal',
|
||||
'matematika': 'mtk',
|
||||
'mtk': 'mtk',
|
||||
'math': 'mtk',
|
||||
'fisika': 'fisika',
|
||||
'physics': 'fisika',
|
||||
'kimia': 'kimia',
|
||||
'chemistry': 'kimia',
|
||||
'biologi': 'biologi',
|
||||
'biology': 'biologi',
|
||||
'ekonomi': 'ekonomi',
|
||||
'economics': 'ekonomi',
|
||||
'geografi': 'geografi',
|
||||
'geography': 'geografi',
|
||||
'sosiologi': 'sosiologi',
|
||||
'sociology': 'sosiologi',
|
||||
'sejarah': 'sejarah',
|
||||
'history': 'sejarah',
|
||||
'minat': 'minat',
|
||||
'interest': 'minat',
|
||||
'cita cita': 'cita_cita',
|
||||
'cita-cita': 'cita_cita',
|
||||
'dream job': 'cita_cita',
|
||||
'preferensi studi': 'preferensi_studi',
|
||||
'preference': 'preferensi_studi',
|
||||
'prestasi': 'prestasi',
|
||||
'achievement': 'prestasi',
|
||||
'jurusan masuk': 'major_masuk',
|
||||
'major': 'major_masuk',
|
||||
'jurusan': 'major_masuk',
|
||||
'tahun lulus': 'tahun_lulus_polije',
|
||||
'tahun lulus polije': 'tahun_lulus_polije',
|
||||
'graduation year': 'tahun_lulus_polije',
|
||||
'catatan': 'catatan',
|
||||
'notes': 'catatan',
|
||||
'keterangan': 'catatan',
|
||||
}
|
||||
|
||||
# Normalize column names
|
||||
df.columns = [col.lower().strip() for col in df.columns]
|
||||
df = df.rename(columns=column_mapping, errors='ignore')
|
||||
|
||||
return df
|
||||
|
||||
def validate_data(df):
|
||||
"""
|
||||
Validasi data sebelum insert
|
||||
"""
|
||||
print("\n🔍 Validasi Data:")
|
||||
|
||||
# Cek kolom penting
|
||||
required_cols = ['nama_alumni', 'nis', 'kelompok_asal']
|
||||
missing_cols = [col for col in required_cols if col not in df.columns]
|
||||
|
||||
if missing_cols:
|
||||
print(f"✗ Kolom penting tidak ada: {missing_cols}")
|
||||
return False
|
||||
|
||||
print(f"✓ Kolom penting ditemukan: {required_cols}")
|
||||
|
||||
# Cek null values
|
||||
null_counts = df.isnull().sum()
|
||||
if null_counts.any():
|
||||
print(f"⚠ Null values ditemukan:")
|
||||
for col, count in null_counts[null_counts > 0].items():
|
||||
print(f" - {col}: {count} baris")
|
||||
|
||||
return True
|
||||
|
||||
def generate_insert_script(df):
|
||||
"""
|
||||
Generate Laravel seeder script untuk insert data
|
||||
"""
|
||||
print(f"\n📝 Generate Insert Script...")
|
||||
|
||||
# Prepare data
|
||||
records = []
|
||||
for idx, row in df.iterrows():
|
||||
record = {
|
||||
'nama_alumni': str(row.get('nama_alumni', '')).strip() or f"Alumni {idx+1}",
|
||||
'nis': str(row.get('nis', '')).strip() or None,
|
||||
'kelompok_asal': str(row.get('kelompok_asal', 'IPA')).strip(),
|
||||
'mtk': float(row.get('mtk', 0)) if pd.notna(row.get('mtk')) else 0,
|
||||
'fisika': float(row.get('fisika', 0)) if pd.notna(row.get('fisika')) else 0,
|
||||
'kimia': float(row.get('kimia', 0)) if pd.notna(row.get('kimia')) else 0,
|
||||
'biologi': float(row.get('biologi', 0)) if pd.notna(row.get('biologi')) else 0,
|
||||
'ekonomi': float(row.get('ekonomi', 0)) if pd.notna(row.get('ekonomi')) else 0,
|
||||
'geografi': float(row.get('geografi', 0)) if pd.notna(row.get('geografi')) else 0,
|
||||
'sosiologi': float(row.get('sosiologi', 0)) if pd.notna(row.get('sosiologi')) else 0,
|
||||
'sejarah': float(row.get('sejarah', 0)) if pd.notna(row.get('sejarah')) else 0,
|
||||
'minat': str(row.get('minat', 'IPA')).strip(),
|
||||
'cita_cita': str(row.get('cita_cita', '')).strip() or 'Profesional',
|
||||
'preferensi_studi': str(row.get('preferensi_studi', 'Sains & Teknologi')).strip(),
|
||||
'prestasi': str(row.get('prestasi', 'Tidak')).strip(),
|
||||
'major_masuk': str(row.get('major_masuk', '')).strip() or None,
|
||||
'tahun_lulus_polije': int(row.get('tahun_lulus_polije', 2024)) if pd.notna(row.get('tahun_lulus_polije')) else 2024,
|
||||
'catatan': str(row.get('catatan', '')).strip() or None,
|
||||
}
|
||||
records.append(record)
|
||||
|
||||
return records
|
||||
|
||||
def create_seeder_file(records):
|
||||
"""
|
||||
Create Laravel Seeder file
|
||||
"""
|
||||
seeder_content = '''<?php
|
||||
|
||||
namespace Database\\Seeders;
|
||||
|
||||
use Illuminate\\Database\\Console\\Seeds\\WithoutModelEvents;
|
||||
use Illuminate\\Database\\Seeder;
|
||||
use App\\Models\\Alumni;
|
||||
|
||||
class AlumniImportSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$alumni = [
|
||||
'''
|
||||
|
||||
for record in records:
|
||||
seeder_content += f''' [
|
||||
'nama_alumni' => '{record['nama_alumni']}',
|
||||
'nis' => {f"'{record['nis']}'" if record['nis'] else 'null'},
|
||||
'kelompok_asal' => '{record['kelompok_asal']}',
|
||||
'mtk' => {record['mtk']},
|
||||
'fisika' => {record['fisika']},
|
||||
'kimia' => {record['kimia']},
|
||||
'biologi' => {record['biologi']},
|
||||
'ekonomi' => {record['ekonomi']},
|
||||
'geografi' => {record['geografi']},
|
||||
'sosiologi' => {record['sosiologi']},
|
||||
'sejarah' => {record['sejarah']},
|
||||
'minat' => '{record['minat']}',
|
||||
'cita_cita' => '{record['cita_cita']}',
|
||||
'preferensi_studi' => '{record['preferensi_studi']}',
|
||||
'prestasi' => '{record['prestasi']}',
|
||||
'major_masuk' => {f"'{record['major_masuk']}'" if record['major_masuk'] else 'null'},
|
||||
'tahun_lulus_polije' => {record['tahun_lulus_polije']},
|
||||
'catatan' => {f"'{record['catatan']}'" if record['catatan'] else 'null'},
|
||||
],
|
||||
'''
|
||||
|
||||
seeder_content += ''' ];
|
||||
|
||||
foreach ($alumni as $data) {
|
||||
Alumni::create($data);
|
||||
}
|
||||
}
|
||||
}
|
||||
'''
|
||||
|
||||
# Write to file
|
||||
seeder_file = Path(__file__).parent / 'database' / 'seeders' / 'AlumniImportSeeder.php'
|
||||
seeder_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
with open(seeder_file, 'w', encoding='utf-8') as f:
|
||||
f.write(seeder_content)
|
||||
|
||||
print(f"✓ Seeder file created: {seeder_file}")
|
||||
return str(seeder_file)
|
||||
|
||||
def main():
|
||||
"""
|
||||
Main function
|
||||
"""
|
||||
print("=" * 60)
|
||||
print("IMPORT DATA ALUMNI KE DATABASE SPK JURUSAN POLIJE")
|
||||
print("=" * 60)
|
||||
|
||||
# Find Excel file
|
||||
excel_files = list(Path(__file__).parent.glob('*.xlsx')) + \
|
||||
list(Path(__file__).parent.glob('DATA *.xlsx')) + \
|
||||
list(Path(__file__).parent.glob('*TAMATAN*.xlsx'))
|
||||
|
||||
if not excel_files:
|
||||
print("✗ File Excel tidak ditemukan di folder project")
|
||||
print(" Cari file dengan nama: DATA RESAPAN TAMATAN.xlsx")
|
||||
return False
|
||||
|
||||
excel_file = excel_files[0]
|
||||
print(f"📄 File ditemukan: {excel_file.name}\n")
|
||||
|
||||
# Read Excel
|
||||
df = read_excel_file(str(excel_file))
|
||||
if df is None:
|
||||
return False
|
||||
|
||||
# Display first few rows
|
||||
print("\n📊 Preview Data (5 baris pertama):")
|
||||
print(df.head().to_string())
|
||||
|
||||
# Normalize columns
|
||||
df = normalize_column_names(df)
|
||||
print(f"\n✓ Kolom di-normalize")
|
||||
|
||||
# Validate
|
||||
if not validate_data(df):
|
||||
return False
|
||||
|
||||
# Generate records
|
||||
records = generate_insert_script(df)
|
||||
print(f"✓ {len(records)} records siap untuk di-insert")
|
||||
|
||||
# Show sample
|
||||
print(f"\n📋 Sample Record (pertama):")
|
||||
print(json.dumps(records[0], indent=2, default=str))
|
||||
|
||||
# Create seeder
|
||||
seeder_file = create_seeder_file(records)
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("✓ IMPORT DATA SIAP!")
|
||||
print("=" * 60)
|
||||
print("\n📝 Cara menggunakan Seeder:")
|
||||
print("1. Jalankan command: php artisan db:seed --class=AlumniImportSeeder")
|
||||
print("2. Atau jalankan tanpa argument untuk seed semua: php artisan db:seed")
|
||||
print("\n")
|
||||
|
||||
return True
|
||||
|
||||
if __name__ == '__main__':
|
||||
success = main()
|
||||
sys.exit(0 if success else 1)
|
||||
|
|
@ -8,22 +8,18 @@
|
|||
<p class="text-sm text-gray-500 mt-1">Input data alumni SMA Bima Ambulu</p>
|
||||
</div>
|
||||
|
||||
<!-- Error Summary Alert -->
|
||||
@if($errors->any())
|
||||
<div class="mb-6 p-4 bg-red-50 border border-red-200 rounded-lg">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="text-red-600 text-xl">⚠️</span>
|
||||
<span class="text-red-700 font-bold">Perbaiki kesalahan berikut:</span>
|
||||
</div>
|
||||
<ul class="text-red-600 text-sm space-y-1 ml-8">
|
||||
<div class="bg-red-50 border-l-4 border-red-400 p-4 rounded-lg mb-6">
|
||||
<p class="text-red-800 text-sm font-bold mb-2">❌ Validasi gagal:</p>
|
||||
<ul class="list-disc pl-5 text-sm text-red-700">
|
||||
@foreach($errors->all() as $error)
|
||||
<li>• {{ $error }}</li>
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form action="{{ route('admin.alumni.store') }}" method="POST" class="max-w-2xl" id="alumniForm">
|
||||
<form action="{{ route('admin.alumni.store') }}" method="POST" class="max-w-2xl">
|
||||
@csrf
|
||||
|
||||
<!-- Data Dasar -->
|
||||
|
|
@ -32,36 +28,30 @@
|
|||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Nama Alumni * <span class="text-gray-400 text-xs">(minimal 3 karakter)</span></label>
|
||||
<input type="text" name="nama_alumni" required minlength="3" maxlength="255" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 transition @error('nama_alumni') border-red-500 focus:ring-red-400 @else border-gray-300 focus:ring-maroon @enderror text-sm"
|
||||
value="{{ old('nama_alumni') }}" placeholder="Nama lengkap" oninput="validateAlumniForm()">
|
||||
<div class="flex justify-between items-center mt-1">
|
||||
<span id="namaAlumniError" class="text-red-500 text-xs hidden">⚠️ Nama minimal 3 karakter</span>
|
||||
<span id="namaAlumniValid" class="text-green-500 text-xs hidden">✓ Nama valid</span>
|
||||
</div>
|
||||
@error('nama_alumni') <span class="text-red-500 text-xs block mt-1">{{ $message }}</span> @enderror
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Nama Alumni *</label>
|
||||
<input type="text" name="nama_alumni" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
value="{{ old('nama_alumni') }}" placeholder="Nama lengkap">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">NIS <span class="text-gray-400 text-xs">(max 20 karakter)</span></label>
|
||||
<input type="text" name="nis" maxlength="20" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon text-sm"
|
||||
value="{{ old('nis') }}" placeholder="NIS SMA (opsional)">
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">NIS</label>
|
||||
<input type="text" name="nis" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
value="{{ old('nis') }}" placeholder="NIS SMA">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Kelompok Asal *</label>
|
||||
<select name="kelompok_asal" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon text-sm" oninput="validateAlumniForm()">
|
||||
<select name="kelompok_asal" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
<option value="">-- Pilih --</option>
|
||||
<option value="IPA" {{ old('kelompok_asal') == 'IPA' ? 'selected' : '' }}>IPA</option>
|
||||
<option value="IPS" {{ old('kelompok_asal') == 'IPS' ? 'selected' : '' }}>IPS</option>
|
||||
</select>
|
||||
@error('kelompok_asal') <span class="text-red-500 text-xs">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Minat / Bidang Studi <span class="text-gray-400 text-xs">(min 2 karakter)</span></label>
|
||||
<input type="text" name="minat" minlength="2" maxlength="255" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon text-sm"
|
||||
value="{{ old('minat') }}" placeholder="Minat siswa (opsional)">
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Minat / Bidang Studi</label>
|
||||
<input type="text" name="minat" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
value="{{ old('minat') }}" placeholder="Minat siswa">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -69,44 +59,37 @@
|
|||
<!-- Nilai Entry -->
|
||||
<div class="bg-white rounded-lg shadow p-6 mb-6 border-l-4 border-yellow-400">
|
||||
<h3 class="text-lg font-bold text-maroon mb-4">📊 Nilai Saat Entry (Rapor SMA)</h3>
|
||||
<p class="text-xs text-gray-500 mb-4">Input nilai 0-100, kosongkan jika tidak ada</p>
|
||||
|
||||
<div class="grid grid-cols-2 md:grid-cols-3 gap-3">
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-700 mb-1">Matematika</label>
|
||||
<input type="number" name="mtk" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon text-sm"
|
||||
value="{{ old('mtk') }}" placeholder="0-100" oninput="validateScore(this)">
|
||||
@error('mtk') <span class="text-red-500 text-xs">{{ $message }}</span> @enderror
|
||||
<input type="number" name="mtk" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
value="{{ old('mtk') }}" placeholder="0-100">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-700 mb-1">Fisika</label>
|
||||
<input type="number" name="fisika" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon text-sm"
|
||||
value="{{ old('fisika') }}" placeholder="0-100" oninput="validateScore(this)">
|
||||
@error('fisika') <span class="text-red-500 text-xs">{{ $message }}</span> @enderror
|
||||
<input type="number" name="fisika" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
value="{{ old('fisika') }}" placeholder="0-100">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-700 mb-1">Kimia</label>
|
||||
<input type="number" name="kimia" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon text-sm"
|
||||
value="{{ old('kimia') }}" placeholder="0-100" oninput="validateScore(this)">
|
||||
@error('kimia') <span class="text-red-500 text-xs">{{ $message }}</span> @enderror
|
||||
<input type="number" name="kimia" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
value="{{ old('kimia') }}" placeholder="0-100">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-700 mb-1">Biologi</label>
|
||||
<input type="number" name="biologi" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon text-sm"
|
||||
value="{{ old('biologi') }}" placeholder="0-100" oninput="validateScore(this)">
|
||||
@error('biologi') <span class="text-red-500 text-xs">{{ $message }}</span> @enderror
|
||||
<input type="number" name="biologi" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
value="{{ old('biologi') }}" placeholder="0-100">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-700 mb-1">Ekonomi</label>
|
||||
<input type="number" name="ekonomi" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon text-sm"
|
||||
value="{{ old('ekonomi') }}" placeholder="0-100" oninput="validateScore(this)">
|
||||
@error('ekonomi') <span class="text-red-500 text-xs">{{ $message }}</span> @enderror
|
||||
<input type="number" name="ekonomi" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
value="{{ old('ekonomi') }}" placeholder="0-100">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-700 mb-1">Geografi</label>
|
||||
<input type="number" name="geografi" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon text-sm"
|
||||
value="{{ old('geografi') }}" placeholder="0-100" oninput="validateScore(this)">
|
||||
@error('geografi') <span class="text-red-500 text-xs">{{ $message }}</span> @enderror
|
||||
<input type="number" name="geografi" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
value="{{ old('geografi') }}" placeholder="0-100">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -117,28 +100,21 @@
|
|||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Jurusan Masuk ke Polije * <span class="text-gray-400 text-xs">(min 3 karakter)</span></label>
|
||||
<input type="text" name="major_masuk" required minlength="3" maxlength="255" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 transition @error('major_masuk') border-red-500 focus:ring-red-400 @else border-gray-300 focus:ring-maroon @enderror text-sm"
|
||||
value="{{ old('major_masuk') }}" placeholder="Jurusan Polije" oninput="validateAlumniForm()">
|
||||
<div class="flex justify-between items-center mt-1">
|
||||
<span id="majorError" class="text-red-500 text-xs hidden">⚠️ Jurusan minimal 3 karakter</span>
|
||||
<span id="majorValid" class="text-green-500 text-xs hidden">✓ Jurusan valid</span>
|
||||
</div>
|
||||
@error('major_masuk') <span class="text-red-500 text-xs block mt-1">{{ $message }}</span> @enderror
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Jurusan Masuk ke Polije *</label>
|
||||
<input type="text" name="major_masuk" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
value="{{ old('major_masuk') }}" placeholder="Jurusan Polije">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Tahun Lulus Polije <span class="text-gray-400 text-xs">(2020-sekarang)</span></label>
|
||||
<input type="number" name="tahun_lulus_polije" min="2020" max="{{ date('Y') }}" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon text-sm"
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Tahun Lulus Polije</label>
|
||||
<input type="number" name="tahun_lulus_polije" min="2020" max="{{ date('Y') }}" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
value="{{ old('tahun_lulus_polije') }}" placeholder="Tahun lulus">
|
||||
@error('tahun_lulus_polije') <span class="text-red-500 text-xs">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Catatan <span class="text-gray-400 text-xs">(max 500 karakter)</span></label>
|
||||
<textarea name="catatan" rows="3" maxlength="500" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon text-sm"
|
||||
placeholder="Catatan tambahan (opsional)" oninput="updateCharCount('catatan', 500)">{{ old('catatan') }}</textarea>
|
||||
<span id="catatanCount" class="text-gray-400 text-xs">0/500</span>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Catatan</label>
|
||||
<textarea name="catatan" rows="3" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
placeholder="Catatan tambahan (opsional)">{{ old('catatan') }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -147,72 +123,9 @@
|
|||
<a href="{{ route('admin.alumni.index') }}" class="px-6 py-2 rounded-lg font-bold bg-gray-300 text-gray-700 hover:bg-gray-400 transition">
|
||||
Batal
|
||||
</a>
|
||||
<button type="submit" class="px-6 py-2 rounded-lg font-bold gradient-maroon text-white hover:opacity-90 transition disabled:opacity-50 disabled:cursor-not-allowed" id="submitButton">
|
||||
<button type="submit" class="px-6 py-2 rounded-lg font-bold gradient-maroon text-white hover:opacity-90 transition">
|
||||
💾 Simpan
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@endsection
|
||||
|
||||
@section('scripts')
|
||||
<script>
|
||||
function updateCharCount(fieldName, max) {
|
||||
const field = document.querySelector(`textarea[name="${fieldName}"]`);
|
||||
const countSpan = document.getElementById(`${fieldName}Count`);
|
||||
countSpan.textContent = `${field.value.length}/${max}`;
|
||||
}
|
||||
|
||||
function validateScore(input) {
|
||||
let value = parseFloat(input.value);
|
||||
if (value > 100) {
|
||||
input.value = '100';
|
||||
} else if (value < 0 && input.value !== '') {
|
||||
input.value = '0';
|
||||
}
|
||||
}
|
||||
|
||||
function validateAlumniForm() {
|
||||
const namaAlumni = document.querySelector('input[name="nama_alumni"]');
|
||||
const major = document.querySelector('input[name="major_masuk"]');
|
||||
const kelompok = document.querySelector('select[name="kelompok_asal"]');
|
||||
const submitButton = document.getElementById('submitButton');
|
||||
|
||||
// Validate nama alumni
|
||||
if (namaAlumni.value.trim().length >= 3) {
|
||||
namaAlumni.classList.remove('border-red-500', 'focus:ring-red-400');
|
||||
namaAlumni.classList.add('border-gray-300', 'focus:ring-maroon');
|
||||
document.getElementById('namaAlumniError').classList.add('hidden');
|
||||
document.getElementById('namaAlumniValid').classList.remove('hidden');
|
||||
} else if (namaAlumni.value.trim().length > 0) {
|
||||
namaAlumni.classList.remove('border-gray-300', 'focus:ring-maroon');
|
||||
namaAlumni.classList.add('border-red-500', 'focus:ring-red-400');
|
||||
document.getElementById('namaAlumniError').classList.remove('hidden');
|
||||
document.getElementById('namaAlumniValid').classList.add('hidden');
|
||||
}
|
||||
|
||||
// Validate major
|
||||
if (major.value.trim().length >= 3) {
|
||||
major.classList.remove('border-red-500', 'focus:ring-red-400');
|
||||
major.classList.add('border-gray-300', 'focus:ring-maroon');
|
||||
document.getElementById('majorError').classList.add('hidden');
|
||||
document.getElementById('majorValid').classList.remove('hidden');
|
||||
} else if (major.value.trim().length > 0) {
|
||||
major.classList.remove('border-gray-300', 'focus:ring-maroon');
|
||||
major.classList.add('border-red-500', 'focus:ring-red-400');
|
||||
document.getElementById('majorError').classList.remove('hidden');
|
||||
document.getElementById('majorValid').classList.add('hidden');
|
||||
}
|
||||
|
||||
// Enable/disable submit
|
||||
const isValid = namaAlumni.value.trim().length >= 3 &&
|
||||
major.value.trim().length >= 3 &&
|
||||
kelompok.value !== '';
|
||||
submitButton.disabled = !isValid;
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
validateAlumniForm();
|
||||
updateCharCount('catatan', 500);
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
|
|
|
|||
|
|
@ -8,22 +8,18 @@
|
|||
<p class="text-sm text-gray-500 mt-1">{{ $alumni->nama_alumni }}</p>
|
||||
</div>
|
||||
|
||||
<!-- Error Summary Alert -->
|
||||
@if($errors->any())
|
||||
<div class="mb-6 p-4 bg-red-50 border border-red-200 rounded-lg">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="text-red-600 text-xl">⚠️</span>
|
||||
<span class="text-red-700 font-bold">Perbaiki kesalahan berikut:</span>
|
||||
</div>
|
||||
<ul class="text-red-600 text-sm space-y-1 ml-8">
|
||||
<div class="bg-red-50 border-l-4 border-red-400 p-4 rounded-lg mb-6">
|
||||
<p class="text-red-800 text-sm font-bold mb-2">❌ Validasi gagal:</p>
|
||||
<ul class="list-disc pl-5 text-sm text-red-700">
|
||||
@foreach($errors->all() as $error)
|
||||
<li>• {{ $error }}</li>
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form action="{{ route('admin.alumni.update', $alumni->id) }}" method="POST" class="max-w-2xl" id="alumniForm">
|
||||
<form action="{{ route('admin.alumni.update', $alumni->id) }}" method="POST" class="max-w-2xl">
|
||||
@csrf @method('PUT')
|
||||
|
||||
<!-- Data Dasar -->
|
||||
|
|
@ -32,14 +28,9 @@
|
|||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Nama Alumni * <span class="text-gray-400 text-xs">(minimal 3 karakter)</span></label>
|
||||
<input type="text" name="nama_alumni" required minlength="3" maxlength="255" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 transition @error('nama_alumni') border-red-500 focus:ring-red-400 @else border-gray-300 focus:ring-maroon @enderror text-sm"
|
||||
value="{{ old('nama_alumni', $alumni->nama_alumni) }}" placeholder="Nama lengkap" oninput="validateAlumniForm()">
|
||||
<div class="flex justify-between items-center mt-1">
|
||||
<span id="namaAlumniError" class="text-red-500 text-xs hidden">⚠️ Nama minimal 3 karakter</span>
|
||||
<span id="namaAlumniValid" class="text-green-500 text-xs hidden">✓ Nama valid</span>
|
||||
</div>
|
||||
@error('nama_alumni') <span class="text-red-500 text-xs block mt-1">{{ $message }}</span> @enderror
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Nama Alumni *</label>
|
||||
<input type="text" name="nama_alumni" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
value="{{ old('nama_alumni', $alumni->nama_alumni) }}" placeholder="Nama lengkap">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">NIS</label>
|
||||
|
|
@ -109,14 +100,9 @@
|
|||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Jurusan Masuk ke Polije * <span class="text-gray-400 text-xs">(minimal 3 karakter)</span></label>
|
||||
<input type="text" name="major_masuk" required minlength="3" maxlength="255" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 transition @error('major_masuk') border-red-500 focus:ring-red-400 @else border-gray-300 focus:ring-maroon @enderror text-sm"
|
||||
value="{{ old('major_masuk', $alumni->major_masuk) }}" placeholder="Jurusan Polije" oninput="validateAlumniForm()">
|
||||
<div class="flex justify-between items-center mt-1">
|
||||
<span id="majorError" class="text-red-500 text-xs hidden">⚠️ Jurusan minimal 3 karakter</span>
|
||||
<span id="majorValid" class="text-green-500 text-xs hidden">✓ Jurusan valid</span>
|
||||
</div>
|
||||
@error('major_masuk') <span class="text-red-500 text-xs block mt-1">{{ $message }}</span> @enderror
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Jurusan Masuk ke Polije *</label>
|
||||
<input type="text" name="major_masuk" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
value="{{ old('major_masuk', $alumni->major_masuk) }}" placeholder="Jurusan Polije">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Tahun Lulus Polije</label>
|
||||
|
|
@ -126,10 +112,9 @@
|
|||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Catatan <span class="text-gray-400 text-xs">(max 500 karakter)</span></label>
|
||||
<textarea name="catatan" rows="3" maxlength="500" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon text-sm"
|
||||
placeholder="Catatan tambahan (opsional)" oninput="updateCharCount('catatan', 500)">{{ old('catatan', $alumni->catatan) }}</textarea>
|
||||
<span id="catatanCount" class="text-gray-400 text-xs">0/500</span>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Catatan</label>
|
||||
<textarea name="catatan" rows="3" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
placeholder="Catatan tambahan (opsional)">{{ old('catatan', $alumni->catatan) }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -138,77 +123,9 @@
|
|||
<a href="{{ route('admin.alumni.index') }}" class="px-6 py-2 rounded-lg font-bold bg-gray-300 text-gray-700 hover:bg-gray-400 transition">
|
||||
Batal
|
||||
</a>
|
||||
<button type="submit" class="px-6 py-2 rounded-lg font-bold gradient-maroon text-white hover:opacity-90 transition disabled:opacity-50 disabled:cursor-not-allowed" id="submitButton">
|
||||
<button type="submit" class="px-6 py-2 rounded-lg font-bold gradient-maroon text-white hover:opacity-90 transition">
|
||||
💾 Update
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@section('scripts')
|
||||
<script>
|
||||
function updateCharCount(fieldName, max) {
|
||||
const field = document.querySelector(`textarea[name="${fieldName}"]`);
|
||||
const countSpan = document.getElementById(`${fieldName}Count`);
|
||||
countSpan.textContent = `${field.value.length}/${max}`;
|
||||
}
|
||||
|
||||
function validateScore(input) {
|
||||
let value = parseFloat(input.value);
|
||||
if (value > 100) {
|
||||
input.value = '100';
|
||||
} else if (value < 0 && input.value !== '') {
|
||||
input.value = '0';
|
||||
}
|
||||
}
|
||||
|
||||
function validateAlumniForm() {
|
||||
const namaAlumni = document.querySelector('input[name="nama_alumni"]');
|
||||
const major = document.querySelector('input[name="major_masuk"]');
|
||||
const kelompok = document.querySelector('select[name="kelompok_asal"]');
|
||||
const submitButton = document.getElementById('submitButton');
|
||||
|
||||
// Validate nama alumni
|
||||
if (namaAlumni.value.trim().length >= 3) {
|
||||
namaAlumni.classList.remove('border-red-500', 'focus:ring-red-400');
|
||||
namaAlumni.classList.add('border-gray-300', 'focus:ring-maroon');
|
||||
document.getElementById('namaAlumniError').classList.add('hidden');
|
||||
document.getElementById('namaAlumniValid').classList.remove('hidden');
|
||||
} else if (namaAlumni.value.trim().length > 0) {
|
||||
namaAlumni.classList.remove('border-gray-300', 'focus:ring-maroon');
|
||||
namaAlumni.classList.add('border-red-500', 'focus:ring-red-400');
|
||||
document.getElementById('namaAlumniError').classList.remove('hidden');
|
||||
document.getElementById('namaAlumniValid').classList.add('hidden');
|
||||
}
|
||||
|
||||
// Validate major
|
||||
if (major.value.trim().length >= 3) {
|
||||
major.classList.remove('border-red-500', 'focus:ring-red-400');
|
||||
major.classList.add('border-gray-300', 'focus:ring-maroon');
|
||||
document.getElementById('majorError').classList.add('hidden');
|
||||
document.getElementById('majorValid').classList.remove('hidden');
|
||||
} else if (major.value.trim().length > 0) {
|
||||
major.classList.remove('border-gray-300', 'focus:ring-maroon');
|
||||
major.classList.add('border-red-500', 'focus:ring-red-400');
|
||||
document.getElementById('majorError').classList.remove('hidden');
|
||||
document.getElementById('majorValid').classList.add('hidden');
|
||||
}
|
||||
|
||||
// Enable/disable submit
|
||||
const isValid = namaAlumni.value.trim().length >= 3 &&
|
||||
major.value.trim().length >= 3 &&
|
||||
kelompok.value !== '';
|
||||
submitButton.disabled = !isValid;
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
validateAlumniForm();
|
||||
updateCharCount('catatan', 500);
|
||||
|
||||
// Add validateScore to all score inputs
|
||||
document.querySelectorAll('input[type="number"][name*="mtk"], input[type="number"][name*="fisika"], input[type="number"][name*="kimia"], input[type="number"][name*="biologi"], input[type="number"][name*="ekonomi"], input[type="number"][name*="geografi"]').forEach(input => {
|
||||
input.addEventListener('oninput', function() { validateScore(this); });
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
@endsection
|
||||
|
|
|
|||
|
|
@ -39,60 +39,20 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Nilai Entry -->
|
||||
<!-- Nilai Rata-rata -->
|
||||
<div class="bg-white rounded-lg shadow p-6 mb-6 border-l-4 border-yellow-400">
|
||||
<h3 class="text-lg font-bold text-maroon mb-4">📊 Nilai Saat Entry (Rapor SMA)</h3>
|
||||
<div class="grid grid-cols-2 md:grid-cols-3 gap-4">
|
||||
@if($alumni->kelompok_asal === 'IPA')
|
||||
@if($alumni->mtk)
|
||||
<div class="p-3 bg-blue-50 rounded-lg">
|
||||
<p class="text-xs text-gray-600">Matematika</p>
|
||||
<p class="text-xl font-bold text-blue-600">{{ $alumni->mtk }}</p>
|
||||
</div>
|
||||
@endif
|
||||
@if($alumni->fisika)
|
||||
<div class="p-3 bg-green-50 rounded-lg">
|
||||
<p class="text-xs text-gray-600">Fisika</p>
|
||||
<p class="text-xl font-bold text-green-600">{{ $alumni->fisika }}</p>
|
||||
</div>
|
||||
@endif
|
||||
@if($alumni->kimia)
|
||||
<div class="p-3 bg-purple-50 rounded-lg">
|
||||
<p class="text-xs text-gray-600">Kimia</p>
|
||||
<p class="text-xl font-bold text-purple-600">{{ $alumni->kimia }}</p>
|
||||
</div>
|
||||
@endif
|
||||
@if($alumni->biologi)
|
||||
<div class="p-3 bg-red-50 rounded-lg">
|
||||
<p class="text-xs text-gray-600">Biologi</p>
|
||||
<p class="text-xl font-bold text-red-600">{{ $alumni->biologi }}</p>
|
||||
</div>
|
||||
@endif
|
||||
<h3 class="text-lg font-bold text-maroon mb-4">📊 Nilai Rata-Rata (Rapor SMA)</h3>
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
@if($alumni->nilai_rata_rata)
|
||||
<div class="p-3 bg-blue-50 rounded-lg">
|
||||
<p class="text-xs text-gray-600">Nilai Rata-Rata</p>
|
||||
<p class="text-3xl font-bold text-blue-600">{{ $alumni->nilai_rata_rata }}</p>
|
||||
</div>
|
||||
@else
|
||||
@if($alumni->ekonomi)
|
||||
<div class="p-3 bg-orange-50 rounded-lg">
|
||||
<p class="text-xs text-gray-600">Ekonomi</p>
|
||||
<p class="text-xl font-bold text-orange-600">{{ $alumni->ekonomi }}</p>
|
||||
</div>
|
||||
@endif
|
||||
@if($alumni->geografi)
|
||||
<div class="p-3 bg-indigo-50 rounded-lg">
|
||||
<p class="text-xs text-gray-600">Geografi</p>
|
||||
<p class="text-xl font-bold text-indigo-600">{{ $alumni->geografi }}</p>
|
||||
</div>
|
||||
@endif
|
||||
@if($alumni->sosiologi)
|
||||
<div class="p-3 bg-teal-50 rounded-lg">
|
||||
<p class="text-xs text-gray-600">Sosiologi</p>
|
||||
<p class="text-xl font-bold text-teal-600">{{ $alumni->sosiologi }}</p>
|
||||
</div>
|
||||
@endif
|
||||
@if($alumni->sejarah)
|
||||
<div class="p-3 bg-amber-50 rounded-lg">
|
||||
<p class="text-xs text-gray-600">Sejarah</p>
|
||||
<p class="text-xl font-bold text-amber-600">{{ $alumni->sejarah }}</p>
|
||||
</div>
|
||||
@endif
|
||||
<div class="p-3 bg-gray-50 rounded-lg">
|
||||
<p class="text-xs text-gray-600">Nilai Rata-Rata</p>
|
||||
<p class="text-gray-500">-</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -45,11 +45,11 @@
|
|||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Deskripsi <span class="text-gray-400 text-xs">(maksimal 500 karakter)</span></label>
|
||||
<textarea name="deskripsi" rows="3" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon" placeholder="Jelaskan singkat tentang jurusan ini" maxlength="500" oninput="updateCharCount()">{{ old('deskripsi') }}</textarea>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Deskripsi <span class="text-gray-400 text-xs">(disarankan detail untuk kebutuhan chatbot)</span></label>
|
||||
<textarea name="deskripsi" rows="3" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon" placeholder="Jelaskan detail tentang jurusan ini" oninput="updateCharCount()">{{ old('deskripsi') }}</textarea>
|
||||
<div class="flex justify-between items-center mt-1">
|
||||
<span class="text-gray-400 text-xs">Karakter:</span>
|
||||
<span id="charCount" class="text-gray-600 text-xs font-medium">0/500</span>
|
||||
<span id="charCount" class="text-gray-600 text-xs font-medium">0</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -64,9 +64,9 @@
|
|||
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Preferensi Studi</label>
|
||||
<textarea name="preferensi_studi" rows="2" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon" placeholder="Pisahkan dengan koma, contoh: Sains & Teknologi, Pertanian & Lingkungan" maxlength="500" oninput="updateCharCount('preferensiCount')">{{ old('preferensi_studi') }}</textarea>
|
||||
<textarea name="preferensi_studi" rows="2" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon" placeholder="Pisahkan dengan koma, contoh: Praktik Langsung, DuDi, Project Based, Blended Learning" maxlength="500" oninput="updateCharCount('preferensiCount')">{{ old('preferensi_studi') }}</textarea>
|
||||
<div class="flex justify-between items-center mt-1">
|
||||
<p class="text-xs text-gray-500">Rumpun bidang studi yang cocok untuk jurusan ini. Pilihan: Sains & Teknologi, Pertanian & Lingkungan, Kesehatan & Ilmu Hayat, Bisnis & Manajemen, Sosial & Humaniora</p>
|
||||
<p class="text-xs text-gray-500">Pilihan preferensi studi: Praktik Langsung, DuDi, Project Based, Blended Learning</p>
|
||||
<span id="preferensiCount" class="text-gray-600 text-xs font-medium">0/500</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -93,19 +93,19 @@
|
|||
<div class="space-y-3">
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Matematika</label>
|
||||
<input type="number" name="bobot_mtk" value="{{ old('bobot_mtk', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
<input type="number" name="bobot_mapel[ipa][mtk]" value="{{ old('bobot_mapel.ipa.mtk', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Fisika</label>
|
||||
<input type="number" name="bobot_fisika" value="{{ old('bobot_fisika', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
<input type="number" name="bobot_mapel[ipa][fisika]" value="{{ old('bobot_mapel.ipa.fisika', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Kimia</label>
|
||||
<input type="number" name="bobot_kimia" value="{{ old('bobot_kimia', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
<input type="number" name="bobot_mapel[ipa][kimia]" value="{{ old('bobot_mapel.ipa.kimia', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Biologi</label>
|
||||
<input type="number" name="bobot_biologi" value="{{ old('bobot_biologi', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
<input type="number" name="bobot_mapel[ipa][biologi]" value="{{ old('bobot_mapel.ipa.biologi', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -114,19 +114,19 @@
|
|||
<div class="space-y-3">
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Ekonomi</label>
|
||||
<input type="number" name="bobot_ekonomi" value="{{ old('bobot_ekonomi', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
<input type="number" name="bobot_mapel[ips][ekonomi]" value="{{ old('bobot_mapel.ips.ekonomi', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Geografi</label>
|
||||
<input type="number" name="bobot_geografi" value="{{ old('bobot_geografi', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
<input type="number" name="bobot_mapel[ips][geografi]" value="{{ old('bobot_mapel.ips.geografi', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Sosiologi</label>
|
||||
<input type="number" name="bobot_sosiologi" value="{{ old('bobot_sosiologi', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
<input type="number" name="bobot_mapel[ips][sosiologi]" value="{{ old('bobot_mapel.ips.sosiologi', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Sejarah</label>
|
||||
<input type="number" name="bobot_sejarah" value="{{ old('bobot_sejarah', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
<input type="number" name="bobot_mapel[ips][sejarah]" value="{{ old('bobot_mapel.ips.sejarah', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -148,8 +148,8 @@
|
|||
function updateCharCount(elementId = 'charCount') {
|
||||
const textarea = event.target;
|
||||
const count = textarea.value.length;
|
||||
const maxLength = parseInt(textarea.maxLength) || 500;
|
||||
document.getElementById(elementId).textContent = `${count}/${maxLength}`;
|
||||
const maxLength = parseInt(textarea.maxLength);
|
||||
document.getElementById(elementId).textContent = maxLength > 0 ? `${count}/${maxLength}` : `${count}`;
|
||||
validateJurusanForm();
|
||||
}
|
||||
|
||||
|
|
@ -184,11 +184,16 @@ function validateJurusanForm() {
|
|||
textarea.name === 'preferensi_studi' ? 'preferensiCount' :
|
||||
'prospekCount';
|
||||
const count = textarea.value.length;
|
||||
const maxLength = parseInt(textarea.maxLength) || 500;
|
||||
const maxLength = parseInt(textarea.maxLength);
|
||||
if (document.getElementById(id)) {
|
||||
document.getElementById(id).textContent = `${count}/${maxLength}`;
|
||||
document.getElementById(id).textContent = maxLength > 0 ? `${count}/${maxLength}` : `${count}`;
|
||||
}
|
||||
});
|
||||
|
||||
const desc = document.querySelector('textarea[name="deskripsi"]');
|
||||
if (desc && document.getElementById('charCount')) {
|
||||
document.getElementById('charCount').textContent = `${desc.value.length}`;
|
||||
}
|
||||
validateJurusanForm();
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -46,11 +46,11 @@
|
|||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Deskripsi <span class="text-gray-400 text-xs">(maksimal 500 karakter)</span></label>
|
||||
<textarea name="deskripsi" rows="3" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon" placeholder="Jelaskan singkat tentang jurusan ini" maxlength="500" oninput="updateCharCount()">{{ old('deskripsi', $jurusan->deskripsi) }}</textarea>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Deskripsi <span class="text-gray-400 text-xs">(disarankan detail untuk kebutuhan chatbot)</span></label>
|
||||
<textarea name="deskripsi" rows="3" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon" placeholder="Jelaskan detail tentang jurusan ini" oninput="updateCharCount()">{{ old('deskripsi', $jurusan->deskripsi) }}</textarea>
|
||||
<div class="flex justify-between items-center mt-1">
|
||||
<span class="text-gray-400 text-xs">Karakter:</span>
|
||||
<span id="charCount" class="text-gray-600 text-xs font-medium">0/500</span>
|
||||
<span id="charCount" class="text-gray-600 text-xs font-medium">0</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -72,9 +72,9 @@
|
|||
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Preferensi Studi</label>
|
||||
<textarea name="preferensi_studi" rows="2" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon" placeholder="Pisahkan dengan koma, contoh: Sains & Teknologi, Pertanian & Lingkungan" maxlength="500" oninput="updateCharCount('preferensiCount')">{{ old('preferensi_studi', implode(', ', $jurusan->preferensi_studi ?? [])) }}</textarea>
|
||||
<textarea name="preferensi_studi" rows="2" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon" placeholder="Pisahkan dengan koma, contoh: Praktik Langsung, DuDi, Project Based, Blended Learning" maxlength="500" oninput="updateCharCount('preferensiCount')">{{ old('preferensi_studi', implode(', ', $jurusan->preferensi_studi ?? [])) }}</textarea>
|
||||
<div class="flex justify-between items-center mt-1">
|
||||
<p class="text-xs text-gray-500">Rumpun bidang studi yang cocok: Sains & Teknologi, Pertanian & Lingkungan, Kesehatan & Ilmu Hayat, Bisnis & Manajemen, Sosial & Humaniora</p>
|
||||
<p class="text-xs text-gray-500">Pilihan preferensi studi: Praktik Langsung, DuDi, Project Based, Blended Learning</p>
|
||||
<span id="preferensiCount" class="text-gray-600 text-xs font-medium">0/500</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -93,6 +93,8 @@
|
|||
<!-- Bobot Mata Pelajaran -->
|
||||
@php
|
||||
$bobot = $jurusan->bobot_mapel ?? [];
|
||||
$bobotIpa = data_get($bobot, 'ipa', $bobot);
|
||||
$bobotIps = data_get($bobot, 'ips', $bobot);
|
||||
@endphp
|
||||
<div class="bg-white rounded-lg shadow p-6">
|
||||
<h3 class="text-lg font-bold text-maroon mb-4">⚖️ Bobot Mata Pelajaran</h3>
|
||||
|
|
@ -104,19 +106,19 @@
|
|||
<div class="space-y-3">
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Matematika</label>
|
||||
<input type="number" name="bobot_mtk" value="{{ old('bobot_mtk', $bobot['mtk'] ?? '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
<input type="number" name="bobot_mapel[ipa][mtk]" value="{{ old('bobot_mapel.ipa.mtk', data_get($bobotIpa, 'mtk', data_get($bobot, 'mtk', '0.25'))) }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Fisika</label>
|
||||
<input type="number" name="bobot_fisika" value="{{ old('bobot_fisika', $bobot['fisika'] ?? '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
<input type="number" name="bobot_mapel[ipa][fisika]" value="{{ old('bobot_mapel.ipa.fisika', data_get($bobotIpa, 'fisika', data_get($bobot, 'fisika', '0.25'))) }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Kimia</label>
|
||||
<input type="number" name="bobot_kimia" value="{{ old('bobot_kimia', $bobot['kimia'] ?? '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
<input type="number" name="bobot_mapel[ipa][kimia]" value="{{ old('bobot_mapel.ipa.kimia', data_get($bobotIpa, 'kimia', data_get($bobot, 'kimia', '0.25'))) }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Biologi</label>
|
||||
<input type="number" name="bobot_biologi" value="{{ old('bobot_biologi', $bobot['biologi'] ?? '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
<input type="number" name="bobot_mapel[ipa][biologi]" value="{{ old('bobot_mapel.ipa.biologi', data_get($bobotIpa, 'biologi', data_get($bobot, 'biologi', '0.25'))) }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -125,19 +127,19 @@
|
|||
<div class="space-y-3">
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Ekonomi</label>
|
||||
<input type="number" name="bobot_ekonomi" value="{{ old('bobot_ekonomi', $bobot['ekonomi'] ?? '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
<input type="number" name="bobot_mapel[ips][ekonomi]" value="{{ old('bobot_mapel.ips.ekonomi', data_get($bobotIps, 'ekonomi', data_get($bobot, 'ekonomi', '0.25'))) }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Geografi</label>
|
||||
<input type="number" name="bobot_geografi" value="{{ old('bobot_geografi', $bobot['geografi'] ?? '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
<input type="number" name="bobot_mapel[ips][geografi]" value="{{ old('bobot_mapel.ips.geografi', data_get($bobotIps, 'geografi', data_get($bobot, 'geografi', '0.25'))) }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Sosiologi</label>
|
||||
<input type="number" name="bobot_sosiologi" value="{{ old('bobot_sosiologi', $bobot['sosiologi'] ?? '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
<input type="number" name="bobot_mapel[ips][sosiologi]" value="{{ old('bobot_mapel.ips.sosiologi', data_get($bobotIps, 'sosiologi', data_get($bobot, 'sosiologi', '0.25'))) }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Sejarah</label>
|
||||
<input type="number" name="bobot_sejarah" value="{{ old('bobot_sejarah', $bobot['sejarah'] ?? '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
<input type="number" name="bobot_mapel[ips][sejarah]" value="{{ old('bobot_mapel.ips.sejarah', data_get($bobotIps, 'sejarah', data_get($bobot, 'sejarah', '0.25'))) }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -159,8 +161,8 @@
|
|||
function updateCharCount(elementId = 'charCount') {
|
||||
const textarea = event.target;
|
||||
const count = textarea.value.length;
|
||||
const maxLength = parseInt(textarea.maxLength) || 500;
|
||||
document.getElementById(elementId).textContent = `${count}/${maxLength}`;
|
||||
const maxLength = parseInt(textarea.maxLength);
|
||||
document.getElementById(elementId).textContent = maxLength > 0 ? `${count}/${maxLength}` : `${count}`;
|
||||
validateJurusanForm();
|
||||
}
|
||||
|
||||
|
|
@ -195,11 +197,16 @@ function validateJurusanForm() {
|
|||
textarea.name === 'preferensi_studi' ? 'preferensiCount' :
|
||||
'prospekCount';
|
||||
const count = textarea.value.length;
|
||||
const maxLength = parseInt(textarea.maxLength) || 500;
|
||||
const maxLength = parseInt(textarea.maxLength);
|
||||
if (document.getElementById(id)) {
|
||||
document.getElementById(id).textContent = `${count}/${maxLength}`;
|
||||
document.getElementById(id).textContent = maxLength > 0 ? `${count}/${maxLength}` : `${count}`;
|
||||
}
|
||||
});
|
||||
|
||||
const desc = document.querySelector('textarea[name="deskripsi"]');
|
||||
if (desc && document.getElementById('charCount')) {
|
||||
document.getElementById('charCount').textContent = `${desc.value.length}`;
|
||||
}
|
||||
validateJurusanForm();
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -97,23 +97,23 @@
|
|||
<p class="text-gray-700 text-sm mb-4">Sistem menggunakan 5 kriteria utama untuk memberikan rekomendasi jurusan yang tepat:</p>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<div class="p-4 bg-blue-50 rounded-lg border-l-4 border-blue-400">
|
||||
<p class="font-bold text-blue-800 text-sm">📝 Nilai Akademik (40%)</p>
|
||||
<p class="font-bold text-blue-800 text-sm">📝 Nilai Akademik (15.6%)</p>
|
||||
<p class="text-xs text-blue-700 mt-1">IPA: MTK, Fisika, Kimia, Biologi<br>IPS: Ekonomi, Geografi, Sosiologi, Sejarah</p>
|
||||
</div>
|
||||
<div class="p-4 bg-green-50 rounded-lg border-l-4 border-green-400">
|
||||
<p class="font-bold text-green-800 text-sm">💡 Minat & Bakat (35%)</p>
|
||||
<p class="font-bold text-green-800 text-sm">💡 Minat & Bakat (45.6%)</p>
|
||||
<p class="text-xs text-green-700 mt-1">Dicocokkan dengan keywords jurusan secara graduated</p>
|
||||
</div>
|
||||
<div class="p-4 bg-yellow-50 rounded-lg border-l-4 border-yellow-400">
|
||||
<p class="font-bold text-yellow-800 text-sm">🎯 Preferensi Studi (15%)</p>
|
||||
<p class="font-bold text-yellow-800 text-sm">🎯 Preferensi Studi (25.6%)</p>
|
||||
<p class="text-xs text-yellow-700 mt-1">Praktik Langsung, DuDi, Project Based, Blended Learning</p>
|
||||
</div>
|
||||
<div class="p-4 bg-purple-50 rounded-lg border-l-4 border-purple-400">
|
||||
<p class="font-bold text-purple-800 text-sm">🏆 Prestasi (5%)</p>
|
||||
<p class="font-bold text-purple-800 text-sm">🏆 Prestasi (4%)</p>
|
||||
<p class="text-xs text-purple-700 mt-1">Prestasi akademik dan non-akademik siswa</p>
|
||||
</div>
|
||||
<div class="p-4 bg-red-50 rounded-lg border-l-4 border-red-400">
|
||||
<p class="font-bold text-red-800 text-sm">💼 Cita-cita (5%)</p>
|
||||
<p class="font-bold text-red-800 text-sm">💼 Cita-cita (9%)</p>
|
||||
<p class="text-xs text-red-700 mt-1">Dicocokkan dengan keywords jurusan secara graduated</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,14 +7,14 @@
|
|||
<title>@yield('title', 'Admin Panel') - SPK Jurusan Polije</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||||
<style>
|
||||
.gradient-maroon { background: linear-gradient(135deg, #5B7B89 0%, #7B9BA5 100%); }
|
||||
.text-maroon { color: #5B7B89; }
|
||||
.border-maroon { border-color: #5B7B89; }
|
||||
.gradient-maroon { background: linear-gradient(135deg, #6B7280 0%, #8B95A5 100%); }
|
||||
.text-maroon { color: #6B7280; }
|
||||
.border-maroon { border-color: #6B7280; }
|
||||
.bg-cream { background-color: #F8FAFC; }
|
||||
.bg-maroon { background-color: #5B7B89; }
|
||||
.hover\:bg-maroon:hover { background-color: #7B9BA5; }
|
||||
.bg-maroon { background-color: #6B7280; }
|
||||
.hover\:bg-maroon:hover { background-color: #8B95A5; }
|
||||
.stat-card { transition: all 0.3s ease; }
|
||||
.stat-card:hover { transform: translateY(-5px); box-shadow: 0 5px 15px rgba(91, 123, 137, 0.1); }
|
||||
.stat-card:hover { transform: translateY(-5px); box-shadow: 0 5px 15px rgba(107, 114, 128, 0.1); }
|
||||
|
||||
/* Sidebar */
|
||||
.sidebar-dark {
|
||||
|
|
@ -27,14 +27,14 @@
|
|||
color: #cbd5e1;
|
||||
}
|
||||
.sidebar-link:hover {
|
||||
background: rgba(91, 123, 137, 0.15);
|
||||
background: rgba(107, 114, 128, 0.12);
|
||||
color: #ffffff;
|
||||
border-left-color: rgba(91, 123, 137, 0.5);
|
||||
border-left-color: rgba(107, 114, 128, 0.5);
|
||||
}
|
||||
.sidebar-link.active {
|
||||
background: linear-gradient(90deg, rgba(91,123,137,0.25) 0%, rgba(91,123,137,0.05) 100%);
|
||||
color: #7dd3fc !important;
|
||||
border-left-color: #7dd3fc;
|
||||
background: linear-gradient(90deg, rgba(107,114,128,0.2) 0%, rgba(107,114,128,0.03) 100%);
|
||||
color: #b0b9c8 !important;
|
||||
border-left-color: #b0b9c8;
|
||||
}
|
||||
.sidebar-link .sidebar-icon {
|
||||
display: inline-flex;
|
||||
|
|
@ -49,11 +49,11 @@
|
|||
transition: all 0.25s ease;
|
||||
}
|
||||
.sidebar-link:hover .sidebar-icon {
|
||||
background: rgba(91, 123, 137, 0.3);
|
||||
background: rgba(107, 114, 128, 0.25);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
.sidebar-link.active .sidebar-icon {
|
||||
background: rgba(125, 211, 252, 0.15);
|
||||
background: rgba(107, 114, 128, 0.15);
|
||||
}
|
||||
.sidebar-section-label {
|
||||
font-size: 10px;
|
||||
|
|
@ -73,13 +73,13 @@
|
|||
.sidebar-brand-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background: linear-gradient(135deg, #5B7B89 0%, #7B9BA5 100%);
|
||||
background: linear-gradient(135deg, #6B7280 0%, #8B95A5 100%);
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 20px;
|
||||
box-shadow: 0 4px 12px rgba(91, 123, 137, 0.3);
|
||||
box-shadow: 0 4px 12px rgba(107, 114, 128, 0.3);
|
||||
}
|
||||
.sidebar-footer {
|
||||
border-top: 1px solid rgba(255,255,255,0.06);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,158 @@
|
|||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container mx-auto px-4 py-8">
|
||||
<div class="max-w-2xl mx-auto">
|
||||
<!-- Header -->
|
||||
<div class="mb-8">
|
||||
<h1 class="text-3xl font-bold text-gray-900">Import Data Alumni</h1>
|
||||
<p class="text-gray-600 mt-2">Unggah file Excel berisi data alumni untuk diimport ke database</p>
|
||||
</div>
|
||||
|
||||
<!-- Success Message -->
|
||||
@if (session('success'))
|
||||
<div class="mb-6 p-4 bg-green-50 border border-green-200 rounded-lg">
|
||||
<div class="flex items-start">
|
||||
<div class="flex-shrink-0">
|
||||
<svg class="h-5 w-5 text-green-400" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<h3 class="text-sm font-medium text-green-800">{{ session('success') }}</h3>
|
||||
@if (session('errors') && count(session('errors')) > 0)
|
||||
<div class="mt-2 text-sm text-green-700">
|
||||
<p class="font-medium">Detail Error (menampilkan max 10):</p>
|
||||
<ul class="list-disc ml-5 mt-1">
|
||||
@foreach (session('errors') as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Error Message -->
|
||||
@if ($errors->any())
|
||||
<div class="mb-6 p-4 bg-red-50 border border-red-200 rounded-lg">
|
||||
<div class="flex items-start">
|
||||
<div class="flex-shrink-0">
|
||||
<svg class="h-5 w-5 text-red-400" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<h3 class="text-sm font-medium text-red-800">Terjadi Error</h3>
|
||||
<ul class="list-disc ml-5 mt-2 text-sm text-red-700">
|
||||
@foreach ($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Upload Form -->
|
||||
<div class="bg-white rounded-lg shadow-md p-6">
|
||||
<form action="{{ route('alumni.import') }}" method="POST" enctype="multipart/form-data" class="space-y-6">
|
||||
@csrf
|
||||
|
||||
<!-- File Input -->
|
||||
<div>
|
||||
<label for="file" class="block text-sm font-medium text-gray-700 mb-2">
|
||||
Pilih File Excel
|
||||
</label>
|
||||
<div class="relative border-2 border-dashed border-gray-300 rounded-lg p-6 text-center hover:border-blue-500 hover:bg-blue-50 transition cursor-pointer">
|
||||
<input type="file" id="file" name="file" accept=".xlsx,.xls,.csv" class="absolute inset-0 w-full h-full opacity-0 cursor-pointer" required>
|
||||
<div class="pointer-events-none">
|
||||
<svg class="mx-auto h-12 w-12 text-gray-400" stroke="currentColor" fill="none" viewBox="0 0 48 48">
|
||||
<path d="M28 8H12a4 4 0 00-4 4v20a4 4 0 004 4h24a4 4 0 004-4V20m-8-12l-4-4m0 0l-4 4m4-4v12" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
<p class="mt-2 text-sm font-medium text-gray-700">
|
||||
<span class="text-blue-600">Klik untuk upload</span> atau drag & drop
|
||||
</p>
|
||||
<p class="text-xs text-gray-500 mt-1">
|
||||
File format: .xlsx, .xls, .csv (max 10MB)
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<p id="fileName" class="mt-2 text-sm text-gray-600"></p>
|
||||
</div>
|
||||
|
||||
<!-- Info Box -->
|
||||
<div class="bg-blue-50 border border-blue-200 rounded-lg p-4">
|
||||
<h4 class="font-semibold text-blue-900 mb-2">📝 Kolom yang Didukung:</h4>
|
||||
<ul class="text-sm text-blue-800 space-y-1">
|
||||
<li>✓ <strong>Wajib:</strong> Nama Alumni, Kelompok Asal</li>
|
||||
<li>✓ <strong>Optional:</strong> NIS, Matematika, Fisika, Kimia, Biologi, Ekonomi, Geografi, Sosiologi, Sejarah, Minat, Cita-Cita, Preferensi Studi, Prestasi, Jurusan Masuk, Tahun Lulus, Catatan</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Submit Button -->
|
||||
<div class="flex gap-4">
|
||||
<button type="submit" class="flex-1 bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded-lg transition">
|
||||
📤 Upload & Import
|
||||
</button>
|
||||
<a href="{{ route('alumni.index') }}" class="flex-1 bg-gray-200 hover:bg-gray-300 text-gray-800 font-medium py-2 px-4 rounded-lg transition text-center">
|
||||
Kembali
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Template Download -->
|
||||
<div class="mt-8 bg-gray-50 rounded-lg p-6">
|
||||
<h3 class="text-lg font-semibold text-gray-900 mb-4">📋 Template Excel</h3>
|
||||
<p class="text-gray-600 mb-4">Gunakan template berikut sebagai panduan struktur file Excel:</p>
|
||||
|
||||
<div class="bg-white rounded overflow-x-auto border border-gray-200">
|
||||
<table class="w-full text-sm">
|
||||
<thead class="bg-gray-100">
|
||||
<tr>
|
||||
<th class="px-4 py-2 text-left">Nama Alumni</th>
|
||||
<th class="px-4 py-2 text-left">NIS</th>
|
||||
<th class="px-4 py-2 text-left">Kelompok</th>
|
||||
<th class="px-4 py-2 text-left">MTK</th>
|
||||
<th class="px-4 py-2 text-left">Fisika</th>
|
||||
<th class="px-4 py-2 text-left">Jurusan</th>
|
||||
<th class="px-4 py-2 text-left">Tahun</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="border-t">
|
||||
<td class="px-4 py-2">Budi Santoso</td>
|
||||
<td class="px-4 py-2">001</td>
|
||||
<td class="px-4 py-2">IPA</td>
|
||||
<td class="px-4 py-2">85</td>
|
||||
<td class="px-4 py-2">82</td>
|
||||
<td class="px-4 py-2">TIF</td>
|
||||
<td class="px-4 py-2">2024</td>
|
||||
</tr>
|
||||
<tr class="border-t bg-gray-50">
|
||||
<td class="px-4 py-2">Siti Nurhaliza</td>
|
||||
<td class="px-4 py-2">002</td>
|
||||
<td class="px-4 py-2">IPS</td>
|
||||
<td class="px-4 py-2">75</td>
|
||||
<td class="px-4 py-2">65</td>
|
||||
<td class="px-4 py-2">AK</td>
|
||||
<td class="px-4 py-2">2024</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- File input change handler -->
|
||||
<script>
|
||||
document.getElementById('file').addEventListener('change', function(e) {
|
||||
const fileName = e.target.files[0]?.name || '';
|
||||
document.getElementById('fileName').textContent = fileName ? `✓ File dipilih: ${fileName}` : '';
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
|
|
@ -1,25 +1,146 @@
|
|||
<x-guest-layout>
|
||||
<div class="mb-4 text-sm text-gray-600">
|
||||
{{ __('Lupa password Anda? Tidak apa-apa. Beri tahu kami alamat email Anda dan kami akan mengirimkan tautan pengaturan ulang password yang akan memungkinkan Anda memilih yang baru.') }}
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Lupa Password - SPK Jurusan Polije</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||||
<style>
|
||||
.gradient-purple {
|
||||
background: linear-gradient(135deg, #9333ea 0%, #6366f1 100%);
|
||||
}
|
||||
.bg-cream {
|
||||
background-color: #F8FAFC;
|
||||
}
|
||||
@keyframes pulse-soft {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.85; }
|
||||
}
|
||||
.animate-pulse-soft {
|
||||
animation: pulse-soft 3s ease-in-out infinite;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-cream">
|
||||
<div class="min-h-screen flex items-center justify-center px-4 py-8">
|
||||
<div class="w-full max-w-md">
|
||||
<!-- Header -->
|
||||
<div class="text-center mb-8">
|
||||
<div class="inline-flex items-center justify-center w-16 h-16 rounded-full bg-purple-100 mb-4">
|
||||
<span class="text-3xl">🔐</span>
|
||||
</div>
|
||||
<h1 class="text-3xl sm:text-4xl font-bold text-gray-900 mb-2">Lupa Password?</h1>
|
||||
<p class="text-gray-600 text-sm sm:text-base">Tenang, kami bantu kamu atur ulang password dengan mudah.</p>
|
||||
</div>
|
||||
|
||||
<!-- Info Box -->
|
||||
<div class="bg-purple-50 border-l-4 border-purple-600 rounded-lg p-4 mb-6">
|
||||
<p class="text-sm text-purple-900">
|
||||
Masukkan email kamu yang terdaftar, dan kami akan mengirimkan tautan untuk mengatur ulang password ke inbox kamu.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Session Status / Success Message -->
|
||||
@if (session('status'))
|
||||
<div class="mb-6 bg-gradient-to-r from-green-50 to-emerald-50 border-l-4 border-green-500 rounded-lg p-5 shadow-lg border-r border-green-300 animate-pulse-soft">
|
||||
<div class="flex items-start gap-3">
|
||||
<span class="text-2xl flex-shrink-0 mt-0.5">✅</span>
|
||||
<div>
|
||||
<h4 class="text-green-900 font-bold text-base">Berhasil!</h4>
|
||||
<p class="text-green-800 text-sm mt-1 leading-relaxed">{{ session('status') }}</p>
|
||||
<p class="text-green-700 text-xs mt-2 font-semibold">📧 Cek email Anda untuk tautan reset password (cek juga folder spam/promotions)</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Error Messages -->
|
||||
@if ($errors->any())
|
||||
<div class="mb-6 bg-gradient-to-r from-red-50 to-pink-50 border-l-4 border-red-500 rounded-lg p-5 shadow-lg border-r border-red-300">
|
||||
<div class="flex items-start gap-3">
|
||||
<span class="text-2xl flex-shrink-0 mt-0.5">❌</span>
|
||||
<div>
|
||||
<h4 class="text-red-900 font-bold text-base">Gagal!</h4>
|
||||
<ul class="text-red-800 text-sm mt-2 space-y-1.5">
|
||||
@foreach ($errors->all() as $error)
|
||||
<li class="flex items-start gap-2">
|
||||
<span class="text-red-500 mt-0.5">•</span>
|
||||
<span>{{ $error }}</span>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Form -->
|
||||
<form method="POST" action="{{ route('password.email') }}" class="bg-white rounded-xl shadow-lg p-8 border-t-4 border-purple-600" onsubmit="handleForgotSubmit(event)">
|
||||
@csrf
|
||||
|
||||
<!-- Email Address -->
|
||||
<div class="mb-6">
|
||||
<label for="email" class="block text-sm font-semibold text-gray-700 mb-2">📧 Email</label>
|
||||
<input
|
||||
id="email"
|
||||
type="email"
|
||||
name="email"
|
||||
value="{{ old('email') ?? request()->query('email', '') }}"
|
||||
required
|
||||
autofocus
|
||||
placeholder="masukkan email kamu"
|
||||
class="w-full px-4 py-3 border-2 border-gray-300 rounded-lg focus:outline-none focus:border-purple-600 focus:ring-2 focus:ring-purple-200 transition text-sm @error('email') border-red-500 @enderror"
|
||||
/>
|
||||
@error('email')
|
||||
<span class="text-red-500 text-sm mt-1 block">⚠️ {{ $message }}</span>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<!-- Submit Button -->
|
||||
<button
|
||||
id="submitBtn"
|
||||
type="submit"
|
||||
class="w-full bg-gradient-to-r from-purple-600 to-indigo-600 text-white font-bold py-3 px-4 rounded-lg hover:shadow-lg active:scale-95 transition text-base mb-4 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
🔗 Kirim Tautan Reset Password
|
||||
</button>
|
||||
|
||||
<!-- Back to Login -->
|
||||
<div class="text-center">
|
||||
<p class="text-gray-600 text-sm">
|
||||
Ingat passwordnya?
|
||||
<a href="{{ route('login') }}" class="text-purple-600 hover:text-purple-700 font-semibold">Kembali ke Login</a>
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Footer Info -->
|
||||
<div class="text-center mt-6 text-xs text-gray-500">
|
||||
<p>💡 Jika email tidak masuk, cek folder spam kamu.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Session Status -->
|
||||
<x-auth-session-status class="mb-4" :status="session('status')" />
|
||||
<script>
|
||||
function handleForgotSubmit(event) {
|
||||
const email = document.getElementById('email').value;
|
||||
const submitBtn = document.getElementById('submitBtn');
|
||||
|
||||
<form method="POST" action="{{ route('password.email') }}">
|
||||
@csrf
|
||||
// Validasi email
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!emailRegex.test(email)) {
|
||||
event.preventDefault();
|
||||
alert('❌ Email tidak valid! Gunakan format yang benar (contoh: nama@gmail.com)');
|
||||
return false;
|
||||
}
|
||||
|
||||
<!-- Email Address -->
|
||||
<div>
|
||||
<x-input-label for="email" :value="__('Email')" />
|
||||
<x-text-input id="email" class="block mt-1 w-full" type="email" name="email" :value="old('email')" required autofocus />
|
||||
<x-input-error :messages="$errors->get('email')" class="mt-2" />
|
||||
</div>
|
||||
// Disable button dan tampilkan loading state
|
||||
submitBtn.disabled = true;
|
||||
submitBtn.textContent = '⏳ Sedang Mengirim...';
|
||||
submitBtn.style.opacity = '0.7';
|
||||
|
||||
<div class="flex items-center justify-end mt-4">
|
||||
<x-primary-button>
|
||||
{{ __('Kirim Tautan Atur Ulang Password') }}
|
||||
</x-primary-button>
|
||||
</div>
|
||||
</form>
|
||||
</x-guest-layout>
|
||||
return true;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -19,11 +19,11 @@
|
|||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
width: 100%;
|
||||
background-color: #5B7B89;
|
||||
background-color: #6B7280;
|
||||
}
|
||||
.left-section {
|
||||
width: 100%;
|
||||
background-color: #5B7B89;
|
||||
background-color: #6B7280;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
|
@ -38,14 +38,14 @@
|
|||
width: 180px;
|
||||
height: 240px;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
border: 2px dashed #FCD34D;
|
||||
border: 2px dashed #C9A961;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 20px;
|
||||
color: #FCD34D;
|
||||
color: #C9A961;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
padding: 15px;
|
||||
|
|
|
|||
|
|
@ -19,11 +19,11 @@
|
|||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
width: 100%;
|
||||
background-color: #5B7B89;
|
||||
background-color: #6B7280;
|
||||
}
|
||||
.left-section {
|
||||
width: 100%;
|
||||
background-color: #5B7B89;
|
||||
background-color: #6B7280;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
|
@ -38,14 +38,14 @@
|
|||
width: 180px;
|
||||
height: 240px;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
border: 2px dashed #FCD34D;
|
||||
border: 2px dashed #C9A961;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 20px;
|
||||
color: #FCD34D;
|
||||
color: #C9A961;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
padding: 0;
|
||||
|
|
@ -73,7 +73,7 @@
|
|||
}
|
||||
.brand-info p {
|
||||
font-size: 16px;
|
||||
color: #FCD34D;
|
||||
color: #C9A961;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
|
@ -191,6 +191,78 @@
|
|||
margin: 3px 0;
|
||||
line-height: 1.6;
|
||||
}
|
||||
/* Forgot Password Lock Alert */
|
||||
.forgot-password-alert {
|
||||
background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%);
|
||||
border: 3px solid #dc2626;
|
||||
border-radius: 12px;
|
||||
padding: 18px;
|
||||
margin-bottom: 24px;
|
||||
box-shadow: 0 4px 15px rgba(220, 38, 38, 0.2);
|
||||
}
|
||||
.forgot-password-alert .alert-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.forgot-password-alert .alert-header span {
|
||||
font-size: 24px;
|
||||
}
|
||||
.forgot-password-alert .alert-header h3 {
|
||||
color: #7f1d1d;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
margin: 0;
|
||||
}
|
||||
.forgot-password-alert .alert-message {
|
||||
color: #991b1b;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.forgot-password-alert .alert-buttons {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex-direction: column;
|
||||
}
|
||||
.forgot-password-alert .btn-forgot {
|
||||
background: linear-gradient(135deg, #dc2626 0%, #b91c1c 100%);
|
||||
color: white;
|
||||
padding: 10px 16px;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
transition: all 0.3s ease;
|
||||
font-size: 14px;
|
||||
}
|
||||
.forgot-password-alert .btn-forgot:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(220, 38, 38, 0.4);
|
||||
}
|
||||
.forgot-password-alert .btn-retry {
|
||||
background-color: #f3f4f6;
|
||||
color: #1f2937;
|
||||
padding: 10px 16px;
|
||||
border: 2px solid #d1d5db;
|
||||
border-radius: 6px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
transition: all 0.3s ease;
|
||||
font-size: 14px;
|
||||
}
|
||||
.forgot-password-alert .btn-retry:hover {
|
||||
background-color: #e5e7eb;
|
||||
border-color: #9ca3af;
|
||||
}
|
||||
/* Tablet and Desktop */
|
||||
@media (min-width: 768px) {
|
||||
.container-wrapper {
|
||||
|
|
@ -264,6 +336,23 @@
|
|||
font-size: 14px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
.forgot-password-alert {
|
||||
padding: 20px;
|
||||
margin-bottom: 24px;
|
||||
border: 3px solid #dc2626;
|
||||
}
|
||||
.forgot-password-alert .alert-header h3 {
|
||||
font-size: 18px;
|
||||
}
|
||||
.forgot-password-alert .alert-message {
|
||||
font-size: 15px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.forgot-password-alert .btn-forgot,
|
||||
.forgot-password-alert .btn-retry {
|
||||
padding: 12px 18px;
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
|
@ -288,7 +377,27 @@
|
|||
<h2 class="form-title">Selamat Datang</h2>
|
||||
<p class="form-subtitle">Masuk untuk melanjutkan</p>
|
||||
|
||||
@if ($errors->any())
|
||||
{{-- Special Alert: Siswa Forgot Password Lock --}}
|
||||
@if ($errors->has('forgot_password') && $errors->has('email'))
|
||||
<div class="forgot-password-alert">
|
||||
<div class="alert-header">
|
||||
<span>🔒</span>
|
||||
<h3>Akun Terkunci Sementara</h3>
|
||||
</div>
|
||||
<div class="alert-message">
|
||||
{{ $errors->first('email') }}
|
||||
</div>
|
||||
<div class="alert-buttons">
|
||||
<a href="{{ route('password.request') }}?email={{ old('email') }}" class="btn-forgot">
|
||||
🔑 Reset Password Sekarang
|
||||
</a>
|
||||
<button type="reset" class="btn-retry" onclick="document.getElementById('email').value=''; document.getElementById('password').value=''; document.getElementById('email').focus();">
|
||||
← Coba Email Lain
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@elseif ($errors->any())
|
||||
{{-- Regular Error Messages --}}
|
||||
<div class="error-alert">
|
||||
@foreach ($errors->all() as $error)
|
||||
<p>• {{ $error }}</p>
|
||||
|
|
|
|||
|
|
@ -19,11 +19,11 @@
|
|||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
width: 100%;
|
||||
background-color: #5B7B89;
|
||||
background-color: #6B7280;
|
||||
}
|
||||
.left-section {
|
||||
width: 100%;
|
||||
background-color: #5B7B89;
|
||||
background-color: #6B7280;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
|
@ -38,14 +38,14 @@
|
|||
width: 180px;
|
||||
height: 240px;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
border: 2px dashed #FCD34D;
|
||||
border: 2px dashed #C9A961;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 20px;
|
||||
color: #FCD34D;
|
||||
color: #C9A961;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
padding: 0;
|
||||
|
|
@ -73,7 +73,7 @@
|
|||
}
|
||||
.brand-info p {
|
||||
font-size: 16px;
|
||||
color: #FCD34D;
|
||||
color: #C9A961;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,51 +1,236 @@
|
|||
<x-guest-layout>
|
||||
<form method="POST" action="{{ route('password.store') }}">
|
||||
@csrf
|
||||
|
||||
<!-- Password Reset Token -->
|
||||
<input type="hidden" name="token" value="{{ $request->route('token') }}">
|
||||
|
||||
<!-- Email Address -->
|
||||
<div>
|
||||
<x-input-label for="email" :value="__('Email')" />
|
||||
<x-text-input id="email" class="block mt-1 w-full" type="email" name="email" :value="old('email', $request->email)" required autofocus autocomplete="username" />
|
||||
<x-input-error :messages="$errors->get('email')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<!-- Password -->
|
||||
<div class="mt-4">
|
||||
<x-input-label for="password" :value="__('Password')" />
|
||||
<div style="position: relative; display: flex; align-items: center;">
|
||||
<input id="password" class="block mt-1 w-full border border-gray-300 rounded-lg shadow-sm focus:border-indigo-500 focus:ring-indigo-500" type="password" name="password" required autocomplete="new-password" placeholder="Enter new password" style="padding-right: 45px;" />
|
||||
<button type="button" style="position: absolute; right: 12px; background: none; border: none; cursor: pointer; color: #5B7B89; font-size: 18px;" onclick="togglePasswordVisibility('password', this)">👁️</button>
|
||||
</div>
|
||||
<x-input-error :messages="$errors->get('password')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<!-- Confirm Password -->
|
||||
<div class="mt-4">
|
||||
<x-input-label for="password_confirmation" :value="__('Confirm Password')" />
|
||||
<div style="position: relative; display: flex; align-items: center;">
|
||||
<input id="password_confirmation" class="block mt-1 w-full border border-gray-300 rounded-lg shadow-sm focus:border-indigo-500 focus:ring-indigo-500" type="password" name="password_confirmation" required autocomplete="new-password" placeholder="Confirm password" style="padding-right: 45px;" />
|
||||
<button type="button" style="position: absolute; right: 12px; background: none; border: none; cursor: pointer; color: #5B7B89; font-size: 18px;" onclick="togglePasswordVisibility('password_confirmation', this)">👁️</button>
|
||||
</div>
|
||||
<x-input-error :messages="$errors->get('password_confirmation')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-end mt-4">
|
||||
<x-primary-button>
|
||||
{{ __('Atur Ulang Password') }}
|
||||
</x-primary-button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
function togglePasswordVisibility(inputId, buttonElement) {
|
||||
const input = document.getElementById(inputId);
|
||||
const isPassword = input.type === 'password';
|
||||
input.type = isPassword ? 'text' : 'password';
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Atur Ulang Password - SPK Jurusan Polije</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||||
<style>
|
||||
.gradient-purple {
|
||||
background: linear-gradient(135deg, #9333ea 0%, #6366f1 100%);
|
||||
}
|
||||
.bg-cream {
|
||||
background-color: #F8FAFC;
|
||||
}
|
||||
@keyframes pulse-soft {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.85; }
|
||||
}
|
||||
.animate-pulse-soft {
|
||||
animation: pulse-soft 3s ease-in-out infinite;
|
||||
}
|
||||
@keyframes slide-down {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
</script>
|
||||
@endpush
|
||||
</x-guest-layout>
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
.animate-slide-down {
|
||||
animation: slide-down 0.3s ease-out;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-cream">
|
||||
<div class="min-h-screen flex items-center justify-center px-4 py-8">
|
||||
<div class="w-full max-w-md">
|
||||
<!-- Header -->
|
||||
<div class="text-center mb-8">
|
||||
<div class="inline-flex items-center justify-center w-16 h-16 rounded-full bg-green-100 mb-4">
|
||||
<span class="text-3xl">🔄</span>
|
||||
</div>
|
||||
<h1 class="text-3xl sm:text-4xl font-bold text-gray-900 mb-2">Atur Ulang Password</h1>
|
||||
<p class="text-gray-600 text-sm sm:text-base">Buat password baru yang kuat untuk akun kamu.</p>
|
||||
</div>
|
||||
|
||||
<!-- Info Box -->
|
||||
<div class="bg-green-50 border-l-4 border-green-600 rounded-lg p-4 mb-6">
|
||||
<p class="text-sm text-green-900">
|
||||
Pilih password yang kuat (minimal 8 karakter) dan pastikan kamu ingat untuk login di lain waktu.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Success Message (if redirected back with message) -->
|
||||
@if (session('status'))
|
||||
<div class="mb-6 bg-gradient-to-r from-green-50 to-emerald-50 border-l-4 border-green-500 rounded-lg p-5 shadow-lg border-r border-green-300 animate-slide-down">
|
||||
<div class="flex items-start gap-3">
|
||||
<span class="text-2xl flex-shrink-0 mt-0.5">✅</span>
|
||||
<div>
|
||||
<h4 class="text-green-900 font-bold text-base">Berhasil!</h4>
|
||||
<p class="text-green-800 text-sm mt-1 leading-relaxed">{{ session('status') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Error Messages -->
|
||||
@if ($errors->any())
|
||||
<div class="mb-6 bg-gradient-to-r from-red-50 to-pink-50 border-l-4 border-red-500 rounded-lg p-5 shadow-lg border-r border-red-300 animate-slide-down">
|
||||
<div class="flex items-start gap-3">
|
||||
<span class="text-2xl flex-shrink-0 mt-0.5">❌</span>
|
||||
<div>
|
||||
<h4 class="text-red-900 font-bold text-base">Ada Kesalahan!</h4>
|
||||
<ul class="text-red-800 text-sm mt-2 space-y-1.5">
|
||||
@foreach ($errors->all() as $error)
|
||||
<li class="flex items-start gap-2">
|
||||
<span class="text-red-500 mt-0.5">•</span>
|
||||
<span>{{ $error }}</span>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
<p class="text-red-700 text-xs mt-3 font-semibold">💡 Pastikan:</p>
|
||||
<ul class="text-red-700 text-xs mt-1 space-y-0.5 ml-2">
|
||||
<li>✓ Password minimal 8 karakter</li>
|
||||
<li>✓ Kedua password sama persis</li>
|
||||
<li>✓ Tidak menggunakan password lama</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Form -->
|
||||
<form method="POST" action="{{ route('password.store') }}" class="bg-white rounded-xl shadow-lg p-8 border-t-4 border-green-600" onsubmit="handleSubmit(event)">
|
||||
@csrf
|
||||
|
||||
<!-- Password Reset Token -->
|
||||
<input type="hidden" name="token" value="{{ $request->route('token') }}">
|
||||
|
||||
<!-- Email Address (Read-only) -->
|
||||
<div class="mb-6">
|
||||
<label for="email" class="block text-sm font-semibold text-gray-700 mb-2">📧 Email</label>
|
||||
<input
|
||||
id="email"
|
||||
type="email"
|
||||
value="{{ $request->email }}"
|
||||
disabled
|
||||
class="w-full px-4 py-3 border-2 border-gray-300 rounded-lg bg-gray-100 text-gray-600 text-sm cursor-not-allowed"
|
||||
/>
|
||||
<input type="hidden" name="email" value="{{ $request->email }}">
|
||||
</div>
|
||||
|
||||
<!-- Password -->
|
||||
<div class="mb-6">
|
||||
<label for="password" class="block text-sm font-semibold text-gray-700 mb-2">🔐 Password Baru</label>
|
||||
<div class="relative">
|
||||
<input
|
||||
id="password"
|
||||
type="password"
|
||||
name="password"
|
||||
required
|
||||
autocomplete="new-password"
|
||||
placeholder="minimal 8 karakter"
|
||||
class="w-full px-4 py-3 border-2 border-gray-300 rounded-lg focus:outline-none focus:border-green-600 focus:ring-2 focus:ring-green-200 transition text-sm pr-12 @error('password') border-red-500 @enderror"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onclick="togglePassword('password', this)"
|
||||
class="absolute right-3 top-3 text-gray-500 hover:text-gray-700 text-xl"
|
||||
>
|
||||
👁️
|
||||
</button>
|
||||
</div>
|
||||
@error('password')
|
||||
<span class="text-red-500 text-sm mt-1 block">⚠️ {{ $message }}</span>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<!-- Confirm Password -->
|
||||
<div class="mb-6">
|
||||
<label for="password_confirmation" class="block text-sm font-semibold text-gray-700 mb-2">✅ Konfirmasi Password</label>
|
||||
<div class="relative">
|
||||
<input
|
||||
id="password_confirmation"
|
||||
type="password"
|
||||
name="password_confirmation"
|
||||
required
|
||||
autocomplete="new-password"
|
||||
placeholder="ulangi password yang sama"
|
||||
class="w-full px-4 py-3 border-2 border-gray-300 rounded-lg focus:outline-none focus:border-green-600 focus:ring-2 focus:ring-green-200 transition text-sm pr-12 @error('password_confirmation') border-red-500 @enderror"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onclick="togglePassword('password_confirmation', this)"
|
||||
class="absolute right-3 top-3 text-gray-500 hover:text-gray-700 text-xl"
|
||||
>
|
||||
👁️
|
||||
</button>
|
||||
</div>
|
||||
@error('password_confirmation')
|
||||
<span class="text-red-500 text-sm mt-1 block">⚠️ {{ $message }}</span>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<!-- Submit Button -->
|
||||
<button
|
||||
id="submitBtn"
|
||||
type="submit"
|
||||
class="w-full bg-gradient-to-r from-green-600 to-emerald-600 text-white font-bold py-3 px-4 rounded-lg hover:shadow-lg active:scale-95 transition text-base mb-4 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
✨ Simpan Password Baru
|
||||
</button>
|
||||
|
||||
<!-- Back to Login -->
|
||||
<div class="text-center">
|
||||
<p class="text-gray-600 text-sm">
|
||||
<a href="{{ route('login') }}" class="text-green-600 hover:text-green-700 font-semibold">Kembali ke Login</a>
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Security Tips -->
|
||||
<div class="mt-6 text-sm text-gray-600">
|
||||
<p class="font-semibold mb-2">💡 Tips Password yang Aman:</p>
|
||||
<ul class="space-y-1 text-xs">
|
||||
<li>✓ Gunakan kombinasi huruf besar, kecil, angka, dan simbol</li>
|
||||
<li>✓ Hindari kata-kata yang mudah ditebak</li>
|
||||
<li>✓ Jangan gunakan informasi pribadi</li>
|
||||
<li>✓ Minimal 8 karakter, semakin panjang semakin aman</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function togglePassword(inputId, button) {
|
||||
const input = document.getElementById(inputId);
|
||||
if (input.type === 'password') {
|
||||
input.type = 'text';
|
||||
button.textContent = '🙈';
|
||||
} else {
|
||||
input.type = 'password';
|
||||
button.textContent = '👁️';
|
||||
}
|
||||
}
|
||||
|
||||
function handleSubmit(event) {
|
||||
const password = document.getElementById('password').value;
|
||||
const passwordConfirmation = document.getElementById('password_confirmation').value;
|
||||
const submitBtn = document.getElementById('submitBtn');
|
||||
|
||||
// Validasi client-side
|
||||
if (password !== passwordConfirmation) {
|
||||
event.preventDefault();
|
||||
alert('❌ Password tidak sama! Pastikan kedua password sama persis.');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (password.length < 8) {
|
||||
event.preventDefault();
|
||||
alert('❌ Password minimal 8 karakter!');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Disable button dan tampilkan loading state
|
||||
submitBtn.disabled = true;
|
||||
submitBtn.textContent = '⏳ Sedang Menyimpan...';
|
||||
submitBtn.style.opacity = '0.7';
|
||||
|
||||
return true;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -8,22 +8,18 @@
|
|||
<p class="text-sm text-gray-500 mt-1">Input data alumni SMA Bima Ambulu</p>
|
||||
</div>
|
||||
|
||||
<!-- Error Summary Alert -->
|
||||
@if($errors->any())
|
||||
<div class="mb-6 p-4 bg-red-50 border border-red-200 rounded-lg">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="text-red-600 text-xl">⚠️</span>
|
||||
<span class="text-red-700 font-bold">Perbaiki kesalahan berikut:</span>
|
||||
</div>
|
||||
<ul class="text-red-600 text-sm space-y-1 ml-8">
|
||||
<div class="bg-red-50 border-l-4 border-red-400 p-4 rounded-lg mb-6">
|
||||
<p class="text-red-800 text-sm font-bold mb-2">❌ Validasi gagal:</p>
|
||||
<ul class="list-disc pl-5 text-sm text-red-700">
|
||||
@foreach($errors->all() as $error)
|
||||
<li>• {{ $error }}</li>
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form action="{{ route('bk.alumni.store') }}" method="POST" class="max-w-2xl" id="alumniForm">
|
||||
<form action="{{ route('bk.alumni.store') }}" method="POST" class="max-w-2xl">
|
||||
@csrf
|
||||
|
||||
<!-- Data Dasar -->
|
||||
|
|
@ -32,14 +28,9 @@
|
|||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Nama Alumni * <span class="text-gray-400 text-xs">(minimal 3 karakter)</span></label>
|
||||
<input type="text" name="nama_alumni" required minlength="3" maxlength="255" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 transition @error('nama_alumni') border-red-500 focus:ring-red-400 @else border-gray-300 focus:ring-maroon @enderror text-sm"
|
||||
value="{{ old('nama_alumni') }}" placeholder="Nama lengkap" oninput="validateAlumniForm()">
|
||||
<div class="flex justify-between items-center mt-1">
|
||||
<span id="namaAlumniError" class="text-red-500 text-xs hidden">⚠️ Nama minimal 3 karakter</span>
|
||||
<span id="namaAlumniValid" class="text-green-500 text-xs hidden">✓ Nama valid</span>
|
||||
</div>
|
||||
@error('nama_alumni') <span class="text-red-500 text-xs block mt-1">{{ $message }}</span> @enderror
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Nama Alumni *</label>
|
||||
<input type="text" name="nama_alumni" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
value="{{ old('nama_alumni') }}" placeholder="Nama lengkap">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">NIS</label>
|
||||
|
|
@ -51,16 +42,11 @@
|
|||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Kelompok Asal *</label>
|
||||
<select name="kelompok_asal" required class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 transition @error('kelompok_asal') border-red-500 focus:ring-red-400 @else border-gray-300 focus:ring-maroon @enderror text-sm" oninput="validateAlumniForm()">
|
||||
<select name="kelompok_asal" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
<option value="">-- Pilih --</option>
|
||||
<option value="IPA" {{ old('kelompok_asal') == 'IPA' ? 'selected' : '' }}>IPA</option>
|
||||
<option value="IPS" {{ old('kelompok_asal') == 'IPS' ? 'selected' : '' }}>IPS</option>
|
||||
</select>
|
||||
<div class="flex justify-between items-center mt-1">
|
||||
<span id="kelompokError" class="text-red-500 text-xs hidden">⚠️ Pilih kelompok asal</span>
|
||||
<span id="kelompokValid" class="text-green-500 text-xs hidden">✓ Pilihan valid</span>
|
||||
</div>
|
||||
@error('kelompok_asal') <span class="text-red-500 text-xs block mt-1">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Minat / Bidang Studi</label>
|
||||
|
|
@ -77,33 +63,33 @@
|
|||
<div class="grid grid-cols-2 md:grid-cols-3 gap-3">
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-700 mb-1">Matematika</label>
|
||||
<input type="number" name="mtk" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon text-sm"
|
||||
value="{{ old('mtk') }}" placeholder="0-100" oninput="validateScore(this)">
|
||||
<input type="number" name="mtk" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
value="{{ old('mtk') }}" placeholder="0-100">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-700 mb-1">Fisika</label>
|
||||
<input type="number" name="fisika" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon text-sm"
|
||||
value="{{ old('fisika') }}" placeholder="0-100" oninput="validateScore(this)">
|
||||
<input type="number" name="fisika" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
value="{{ old('fisika') }}" placeholder="0-100">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-700 mb-1">Kimia</label>
|
||||
<input type="number" name="kimia" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon text-sm"
|
||||
value="{{ old('kimia') }}" placeholder="0-100" oninput="validateScore(this)">
|
||||
<input type="number" name="kimia" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
value="{{ old('kimia') }}" placeholder="0-100">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-700 mb-1">Biologi</label>
|
||||
<input type="number" name="biologi" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon text-sm"
|
||||
value="{{ old('biologi') }}" placeholder="0-100" oninput="validateScore(this)">
|
||||
<input type="number" name="biologi" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
value="{{ old('biologi') }}" placeholder="0-100">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-700 mb-1">Ekonomi</label>
|
||||
<input type="number" name="ekonomi" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon text-sm"
|
||||
value="{{ old('ekonomi') }}" placeholder="0-100" oninput="validateScore(this)">
|
||||
<input type="number" name="ekonomi" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
value="{{ old('ekonomi') }}" placeholder="0-100">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-700 mb-1">Geografi</label>
|
||||
<input type="number" name="geografi" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon text-sm"
|
||||
value="{{ old('geografi') }}" placeholder="0-100" oninput="validateScore(this)">
|
||||
<input type="number" name="geografi" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
value="{{ old('geografi') }}" placeholder="0-100">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -114,14 +100,9 @@
|
|||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Jurusan Masuk ke Polije * <span class="text-gray-400 text-xs">(minimal 3 karakter)</span></label>
|
||||
<input type="text" name="major_masuk" required minlength="3" maxlength="255" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 transition @error('major_masuk') border-red-500 focus:ring-red-400 @else border-gray-300 focus:ring-maroon @enderror text-sm"
|
||||
value="{{ old('major_masuk') }}" placeholder="Jurusan Polije" oninput="validateAlumniForm()">
|
||||
<div class="flex justify-between items-center mt-1">
|
||||
<span id="majorError" class="text-red-500 text-xs hidden">⚠️ Jurusan minimal 3 karakter</span>
|
||||
<span id="majorValid" class="text-green-500 text-xs hidden">✓ Jurusan valid</span>
|
||||
</div>
|
||||
@error('major_masuk') <span class="text-red-500 text-xs block mt-1">{{ $message }}</span> @enderror
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Jurusan Masuk ke Polije *</label>
|
||||
<input type="text" name="major_masuk" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
value="{{ old('major_masuk') }}" placeholder="Jurusan Polije">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Tahun Lulus Polije</label>
|
||||
|
|
@ -131,10 +112,9 @@
|
|||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Catatan <span class="text-gray-400 text-xs">(max 500 karakter)</span></label>
|
||||
<textarea name="catatan" rows="3" maxlength="500" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon text-sm"
|
||||
placeholder="Catatan tambahan (opsional)" oninput="updateCharCount('catatan', 500)">{{ old('catatan') }}</textarea>
|
||||
<span id="catatanCount" class="text-gray-400 text-xs">0/500</span>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Catatan</label>
|
||||
<textarea name="catatan" rows="3" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
placeholder="Catatan tambahan (opsional)">{{ old('catatan') }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -143,75 +123,10 @@
|
|||
<a href="{{ route('bk.alumni') }}" class="px-6 py-2 rounded-lg font-bold bg-gray-300 text-gray-700 hover:bg-gray-400 transition">
|
||||
Batal
|
||||
</a>
|
||||
<button type="submit" class="px-6 py-2 rounded-lg font-bold gradient-maroon text-white hover:opacity-90 transition disabled:opacity-50 disabled:cursor-not-allowed" id="submitButton">
|
||||
<button type="submit" class="px-6 py-2 rounded-lg font-bold gradient-maroon text-white hover:opacity-90 transition">
|
||||
💾 Simpan
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@endsection
|
||||
|
||||
@section('scripts')
|
||||
<script>
|
||||
function updateCharCount(fieldName, max) {
|
||||
const field = document.querySelector(`textarea[name="${fieldName}"]`);
|
||||
const countSpan = document.getElementById(`${fieldName}Count`);
|
||||
countSpan.textContent = `${field.value.length}/${max}`;
|
||||
}
|
||||
|
||||
function validateScore(input) {
|
||||
let value = parseFloat(input.value);
|
||||
if (value > 100) {
|
||||
input.value = '100';
|
||||
} else if (value < 0 && input.value !== '') {
|
||||
input.value = '0';
|
||||
}
|
||||
}
|
||||
|
||||
function validateAlumniForm() {
|
||||
const namaAlumni = document.querySelector('input[name="nama_alumni"]');
|
||||
const major = document.querySelector('input[name="major_masuk"]');
|
||||
const kelompok = document.querySelector('select[name="kelompok_asal"]');
|
||||
const submitButton = document.getElementById('submitButton');
|
||||
|
||||
if (namaAlumni.value.trim().length >= 3) {
|
||||
namaAlumni.classList.remove('border-red-500', 'focus:ring-red-400');
|
||||
namaAlumni.classList.add('border-gray-300', 'focus:ring-maroon');
|
||||
document.getElementById('namaAlumniError').classList.add('hidden');
|
||||
document.getElementById('namaAlumniValid').classList.remove('hidden');
|
||||
} else if (namaAlumni.value.trim().length > 0) {
|
||||
namaAlumni.classList.remove('border-gray-300', 'focus:ring-maroon');
|
||||
namaAlumni.classList.add('border-red-500', 'focus:ring-red-400');
|
||||
document.getElementById('namaAlumniError').classList.remove('hidden');
|
||||
document.getElementById('namaAlumniValid').classList.add('hidden');
|
||||
}
|
||||
|
||||
if (kelompok.value !== '') {
|
||||
document.getElementById('kelompokError').classList.add('hidden');
|
||||
document.getElementById('kelompokValid').classList.remove('hidden');
|
||||
} else {
|
||||
document.getElementById('kelompokError').classList.remove('hidden');
|
||||
document.getElementById('kelompokValid').classList.add('hidden');
|
||||
}
|
||||
|
||||
if (major.value.trim().length >= 3) {
|
||||
major.classList.remove('border-red-500', 'focus:ring-red-400');
|
||||
major.classList.add('border-gray-300', 'focus:ring-maroon');
|
||||
document.getElementById('majorError').classList.add('hidden');
|
||||
document.getElementById('majorValid').classList.remove('hidden');
|
||||
} else if (major.value.trim().length > 0) {
|
||||
major.classList.remove('border-gray-300', 'focus:ring-maroon');
|
||||
major.classList.add('border-red-500', 'focus:ring-red-400');
|
||||
document.getElementById('majorError').classList.remove('hidden');
|
||||
document.getElementById('majorValid').classList.add('hidden');
|
||||
}
|
||||
|
||||
submitButton.disabled = !(namaAlumni.value.trim().length >= 3 && major.value.trim().length >= 3 && kelompok.value !== '');
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
validateAlumniForm();
|
||||
updateCharCount('catatan', 500);
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
|
||||
|
|
|
|||
|
|
@ -8,22 +8,18 @@
|
|||
<p class="text-sm text-gray-500 mt-1">{{ $alumni->nama_alumni }}</p>
|
||||
</div>
|
||||
|
||||
<!-- Error Summary Alert -->
|
||||
@if($errors->any())
|
||||
<div class="mb-6 p-4 bg-red-50 border border-red-200 rounded-lg">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="text-red-600 text-xl">⚠️</span>
|
||||
<span class="text-red-700 font-bold">Perbaiki kesalahan berikut:</span>
|
||||
</div>
|
||||
<ul class="text-red-600 text-sm space-y-1 ml-8">
|
||||
<div class="bg-red-50 border-l-4 border-red-400 p-4 rounded-lg mb-6">
|
||||
<p class="text-red-800 text-sm font-bold mb-2">❌ Validasi gagal:</p>
|
||||
<ul class="list-disc pl-5 text-sm text-red-700">
|
||||
@foreach($errors->all() as $error)
|
||||
<li>• {{ $error }}</li>
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form action="{{ route('bk.alumni.update', $alumni->id) }}" method="POST" class="max-w-2xl" id="alumniForm">
|
||||
<form action="{{ route('bk.alumni.update', $alumni->id) }}" method="POST" class="max-w-2xl">
|
||||
@csrf @method('PUT')
|
||||
|
||||
<!-- Data Dasar -->
|
||||
|
|
@ -32,14 +28,9 @@
|
|||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Nama Alumni * <span class="text-gray-400 text-xs">(minimal 3 karakter)</span></label>
|
||||
<input type="text" name="nama_alumni" required minlength="3" maxlength="255" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 transition @error('nama_alumni') border-red-500 focus:ring-red-400 @else border-gray-300 focus:ring-maroon @enderror text-sm"
|
||||
value="{{ old('nama_alumni', $alumni->nama_alumni) }}" placeholder="Nama lengkap" oninput="validateAlumniForm()">
|
||||
<div class="flex justify-between items-center mt-1">
|
||||
<span id="namaAlumniError" class="text-red-500 text-xs hidden">⚠️ Nama minimal 3 karakter</span>
|
||||
<span id="namaAlumniValid" class="text-green-500 text-xs hidden">✓ Nama valid</span>
|
||||
</div>
|
||||
@error('nama_alumni') <span class="text-red-500 text-xs block mt-1">{{ $message }}</span> @enderror
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Nama Alumni *</label>
|
||||
<input type="text" name="nama_alumni" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
value="{{ old('nama_alumni', $alumni->nama_alumni) }}" placeholder="Nama lengkap">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">NIS</label>
|
||||
|
|
@ -51,16 +42,11 @@
|
|||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Kelompok Asal *</label>
|
||||
<select name="kelompok_asal" required class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 transition @error('kelompok_asal') border-red-500 focus:ring-red-400 @else border-gray-300 focus:ring-maroon @enderror text-sm" oninput="validateAlumniForm()">
|
||||
<select name="kelompok_asal" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm">
|
||||
<option value="">-- Pilih --</option>
|
||||
<option value="IPA" {{ old('kelompok_asal', $alumni->kelompok_asal) == 'IPA' ? 'selected' : '' }}>IPA</option>
|
||||
<option value="IPS" {{ old('kelompok_asal', $alumni->kelompok_asal) == 'IPS' ? 'selected' : '' }}>IPS</option>
|
||||
</select>
|
||||
<div class="flex justify-between items-center mt-1">
|
||||
<span id="kelompokError" class="text-red-500 text-xs hidden">⚠️ Pilih kelompok asal</span>
|
||||
<span id="kelompokValid" class="text-green-500 text-xs hidden">✓ Pilihan valid</span>
|
||||
</div>
|
||||
@error('kelompok_asal') <span class="text-red-500 text-xs block mt-1">{{ $message }}</span> @enderror
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Minat / Bidang Studi</label>
|
||||
|
|
@ -77,33 +63,33 @@
|
|||
<div class="grid grid-cols-2 md:grid-cols-3 gap-3">
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-700 mb-1">Matematika</label>
|
||||
<input type="number" name="mtk" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon text-sm"
|
||||
value="{{ old('mtk', $alumni->mtk) }}" placeholder="0-100" oninput="validateScore(this)">
|
||||
<input type="number" name="mtk" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
value="{{ old('mtk', $alumni->mtk) }}" placeholder="0-100">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-700 mb-1">Fisika</label>
|
||||
<input type="number" name="fisika" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon text-sm"
|
||||
value="{{ old('fisika', $alumni->fisika) }}" placeholder="0-100" oninput="validateScore(this)">
|
||||
<input type="number" name="fisika" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
value="{{ old('fisika', $alumni->fisika) }}" placeholder="0-100">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-700 mb-1">Kimia</label>
|
||||
<input type="number" name="kimia" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon text-sm"
|
||||
value="{{ old('kimia', $alumni->kimia) }}" placeholder="0-100" oninput="validateScore(this)">
|
||||
<input type="number" name="kimia" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
value="{{ old('kimia', $alumni->kimia) }}" placeholder="0-100">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-700 mb-1">Biologi</label>
|
||||
<input type="number" name="biologi" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon text-sm"
|
||||
value="{{ old('biologi', $alumni->biologi) }}" placeholder="0-100" oninput="validateScore(this)">
|
||||
<input type="number" name="biologi" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
value="{{ old('biologi', $alumni->biologi) }}" placeholder="0-100">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-700 mb-1">Ekonomi</label>
|
||||
<input type="number" name="ekonomi" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon text-sm"
|
||||
value="{{ old('ekonomi', $alumni->ekonomi) }}" placeholder="0-100" oninput="validateScore(this)">
|
||||
<input type="number" name="ekonomi" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
value="{{ old('ekonomi', $alumni->ekonomi) }}" placeholder="0-100">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-700 mb-1">Geografi</label>
|
||||
<input type="number" name="geografi" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon text-sm"
|
||||
value="{{ old('geografi', $alumni->geografi) }}" placeholder="0-100" oninput="validateScore(this)">
|
||||
<input type="number" name="geografi" step="0.01" min="0" max="100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
value="{{ old('geografi', $alumni->geografi) }}" placeholder="0-100">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -114,14 +100,9 @@
|
|||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Jurusan Masuk ke Polije * <span class="text-gray-400 text-xs">(minimal 3 karakter)</span></label>
|
||||
<input type="text" name="major_masuk" required minlength="3" maxlength="255" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 transition @error('major_masuk') border-red-500 focus:ring-red-400 @else border-gray-300 focus:ring-maroon @enderror text-sm"
|
||||
value="{{ old('major_masuk', $alumni->major_masuk) }}" placeholder="Jurusan Polije" oninput="validateAlumniForm()">
|
||||
<div class="flex justify-between items-center mt-1">
|
||||
<span id="majorError" class="text-red-500 text-xs hidden">⚠️ Jurusan minimal 3 karakter</span>
|
||||
<span id="majorValid" class="text-green-500 text-xs hidden">✓ Jurusan valid</span>
|
||||
</div>
|
||||
@error('major_masuk') <span class="text-red-500 text-xs block mt-1">{{ $message }}</span> @enderror
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Jurusan Masuk ke Polije *</label>
|
||||
<input type="text" name="major_masuk" required class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
value="{{ old('major_masuk', $alumni->major_masuk) }}" placeholder="Jurusan Polije">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Tahun Lulus Polije</label>
|
||||
|
|
@ -131,10 +112,9 @@
|
|||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Catatan <span class="text-gray-400 text-xs">(max 500 karakter)</span></label>
|
||||
<textarea name="catatan" rows="3" maxlength="500" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-maroon text-sm"
|
||||
placeholder="Catatan tambahan (opsional)" oninput="updateCharCount('catatan', 500)">{{ old('catatan', $alumni->catatan) }}</textarea>
|
||||
<span id="catatanCount" class="text-gray-400 text-xs">0/500</span>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Catatan</label>
|
||||
<textarea name="catatan" rows="3" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:border-maroon text-sm"
|
||||
placeholder="Catatan tambahan (opsional)">{{ old('catatan', $alumni->catatan) }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -143,74 +123,9 @@
|
|||
<a href="{{ route('bk.alumni') }}" class="px-6 py-2 rounded-lg font-bold bg-gray-300 text-gray-700 hover:bg-gray-400 transition">
|
||||
Batal
|
||||
</a>
|
||||
<button type="submit" class="px-6 py-2 rounded-lg font-bold gradient-maroon text-white hover:opacity-90 transition disabled:opacity-50 disabled:cursor-not-allowed" id="submitButton">
|
||||
<button type="submit" class="px-6 py-2 rounded-lg font-bold gradient-maroon text-white hover:opacity-90 transition">
|
||||
💾 Update
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@endsection
|
||||
|
||||
@section('scripts')
|
||||
<script>
|
||||
function updateCharCount(fieldName, max) {
|
||||
const field = document.querySelector(`textarea[name="${fieldName}"]`);
|
||||
const countSpan = document.getElementById(`${fieldName}Count`);
|
||||
countSpan.textContent = `${field.value.length}/${max}`;
|
||||
}
|
||||
|
||||
function validateScore(input) {
|
||||
let value = parseFloat(input.value);
|
||||
if (value > 100) {
|
||||
input.value = '100';
|
||||
} else if (value < 0 && input.value !== '') {
|
||||
input.value = '0';
|
||||
}
|
||||
}
|
||||
|
||||
function validateAlumniForm() {
|
||||
const namaAlumni = document.querySelector('input[name="nama_alumni"]');
|
||||
const major = document.querySelector('input[name="major_masuk"]');
|
||||
const kelompok = document.querySelector('select[name="kelompok_asal"]');
|
||||
const submitButton = document.getElementById('submitButton');
|
||||
|
||||
if (namaAlumni.value.trim().length >= 3) {
|
||||
namaAlumni.classList.remove('border-red-500', 'focus:ring-red-400');
|
||||
namaAlumni.classList.add('border-gray-300', 'focus:ring-maroon');
|
||||
document.getElementById('namaAlumniError').classList.add('hidden');
|
||||
document.getElementById('namaAlumniValid').classList.remove('hidden');
|
||||
} else if (namaAlumni.value.trim().length > 0) {
|
||||
namaAlumni.classList.remove('border-gray-300', 'focus:ring-maroon');
|
||||
namaAlumni.classList.add('border-red-500', 'focus:ring-red-400');
|
||||
document.getElementById('namaAlumniError').classList.remove('hidden');
|
||||
document.getElementById('namaAlumniValid').classList.add('hidden');
|
||||
}
|
||||
|
||||
if (kelompok.value !== '') {
|
||||
document.getElementById('kelompokError').classList.add('hidden');
|
||||
document.getElementById('kelompokValid').classList.remove('hidden');
|
||||
} else {
|
||||
document.getElementById('kelompokError').classList.remove('hidden');
|
||||
document.getElementById('kelompokValid').classList.add('hidden');
|
||||
}
|
||||
|
||||
if (major.value.trim().length >= 3) {
|
||||
major.classList.remove('border-red-500', 'focus:ring-red-400');
|
||||
major.classList.add('border-gray-300', 'focus:ring-maroon');
|
||||
document.getElementById('majorError').classList.add('hidden');
|
||||
document.getElementById('majorValid').classList.remove('hidden');
|
||||
} else if (major.value.trim().length > 0) {
|
||||
major.classList.remove('border-gray-300', 'focus:ring-maroon');
|
||||
major.classList.add('border-red-500', 'focus:ring-red-400');
|
||||
document.getElementById('majorError').classList.remove('hidden');
|
||||
document.getElementById('majorValid').classList.add('hidden');
|
||||
}
|
||||
|
||||
submitButton.disabled = !(namaAlumni.value.trim().length >= 3 && major.value.trim().length >= 3 && kelompok.value !== '');
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
validateAlumniForm();
|
||||
updateCharCount('catatan', 500);
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
|
|
|
|||
|
|
@ -41,60 +41,14 @@
|
|||
|
||||
<!-- Nilai Entry -->
|
||||
<div class="bg-white rounded-lg shadow p-6 mb-6 border-l-4 border-yellow-400">
|
||||
<h3 class="text-lg font-bold text-maroon mb-4">📊 Nilai Saat Entry (Rapor SMA)</h3>
|
||||
<div class="grid grid-cols-2 md:grid-cols-3 gap-4">
|
||||
@if($alumni->kelompok_asal === 'IPA')
|
||||
@if($alumni->mtk)
|
||||
<div class="p-3 bg-blue-50 rounded-lg">
|
||||
<p class="text-xs text-gray-600">Matematika</p>
|
||||
<p class="text-xl font-bold text-blue-600">{{ $alumni->mtk }}</p>
|
||||
</div>
|
||||
@endif
|
||||
@if($alumni->fisika)
|
||||
<div class="p-3 bg-green-50 rounded-lg">
|
||||
<p class="text-xs text-gray-600">Fisika</p>
|
||||
<p class="text-xl font-bold text-green-600">{{ $alumni->fisika }}</p>
|
||||
</div>
|
||||
@endif
|
||||
@if($alumni->kimia)
|
||||
<div class="p-3 bg-purple-50 rounded-lg">
|
||||
<p class="text-xs text-gray-600">Kimia</p>
|
||||
<p class="text-xl font-bold text-purple-600">{{ $alumni->kimia }}</p>
|
||||
</div>
|
||||
@endif
|
||||
@if($alumni->biologi)
|
||||
<div class="p-3 bg-red-50 rounded-lg">
|
||||
<p class="text-xs text-gray-600">Biologi</p>
|
||||
<p class="text-xl font-bold text-red-600">{{ $alumni->biologi }}</p>
|
||||
</div>
|
||||
@endif
|
||||
@else
|
||||
@if($alumni->ekonomi)
|
||||
<div class="p-3 bg-orange-50 rounded-lg">
|
||||
<p class="text-xs text-gray-600">Ekonomi</p>
|
||||
<p class="text-xl font-bold text-orange-600">{{ $alumni->ekonomi }}</p>
|
||||
</div>
|
||||
@endif
|
||||
@if($alumni->geografi)
|
||||
<div class="p-3 bg-indigo-50 rounded-lg">
|
||||
<p class="text-xs text-gray-600">Geografi</p>
|
||||
<p class="text-xl font-bold text-indigo-600">{{ $alumni->geografi }}</p>
|
||||
</div>
|
||||
@endif
|
||||
@if($alumni->sosiologi)
|
||||
<div class="p-3 bg-teal-50 rounded-lg">
|
||||
<p class="text-xs text-gray-600">Sosiologi</p>
|
||||
<p class="text-xl font-bold text-teal-600">{{ $alumni->sosiologi }}</p>
|
||||
</div>
|
||||
@endif
|
||||
@if($alumni->sejarah)
|
||||
<div class="p-3 bg-amber-50 rounded-lg">
|
||||
<p class="text-xs text-gray-600">Sejarah</p>
|
||||
<p class="text-xl font-bold text-amber-600">{{ $alumni->sejarah }}</p>
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
</div>
|
||||
<h3 class="text-lg font-bold text-maroon mb-4">📊 Nilai Rata-Rata (Rapor SMA)</h3>
|
||||
@if($alumni->nilai_rata_rata)
|
||||
<div class="bg-blue-50 p-4 rounded-lg">
|
||||
<p class="text-3xl font-bold text-blue-600">{{ $alumni->nilai_rata_rata }}</p>
|
||||
</div>
|
||||
@else
|
||||
<p class="text-gray-500">-</p>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Hasil -->
|
||||
|
|
|
|||
|
|
@ -45,11 +45,11 @@
|
|||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Deskripsi <span class="text-gray-400 text-xs">(maks 500 karakter)</span></label>
|
||||
<textarea name="deskripsi" rows="3" maxlength="500" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 transition" placeholder="Jelaskan singkat tentang jurusan ini" oninput="updateCharCount('deskripsi', 500); validateJurusanForm()">{{ old('deskripsi') }}</textarea>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Deskripsi <span class="text-gray-400 text-xs">(disarankan detail untuk kebutuhan chatbot)</span></label>
|
||||
<textarea name="deskripsi" rows="3" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 transition" placeholder="Jelaskan detail tentang jurusan ini" oninput="updateCharCount('deskripsi'); validateJurusanForm()">{{ old('deskripsi') }}</textarea>
|
||||
<div class="flex justify-between items-center mt-1">
|
||||
<p class="text-xs text-gray-500">Jelaskan tentang program, fasilitas, dan prospek</p>
|
||||
<span id="descCount" class="text-gray-400 text-xs">0/500</span>
|
||||
<span id="descCount" class="text-gray-400 text-xs">0</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -61,8 +61,8 @@
|
|||
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Preferensi Studi <span class="text-gray-400 text-xs">(pisahkan dengan koma)</span></label>
|
||||
<textarea name="preferensi_studi" rows="2" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 transition" placeholder="Contoh: Sains & Teknologi, Bisnis & Manajemen" oninput="validateJurusanForm()">{{ old('preferensi_studi') }}</textarea>
|
||||
<p class="text-xs text-gray-500 mt-1">Pilihan: Sains & Teknologi | Pertanian & Lingkungan | Kesehatan & Ilmu Hayat | Bisnis & Manajemen | Sosial & Humaniora</p>
|
||||
<textarea name="preferensi_studi" rows="2" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 transition" placeholder="Contoh: Praktik Langsung, DuDi, Project Based, Blended Learning" oninput="validateJurusanForm()">{{ old('preferensi_studi') }}</textarea>
|
||||
<p class="text-xs text-gray-500 mt-1">Pilihan preferensi studi: Praktik Langsung, DuDi, Project Based, Blended Learning</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
|
@ -83,19 +83,19 @@
|
|||
<div class="space-y-3">
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Matematika</label>
|
||||
<input type="number" name="bobot_mtk" value="{{ old('bobot_mtk', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
<input type="number" name="bobot_mapel[ipa][mtk]" value="{{ old('bobot_mapel.ipa.mtk', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Fisika</label>
|
||||
<input type="number" name="bobot_fisika" value="{{ old('bobot_fisika', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
<input type="number" name="bobot_mapel[ipa][fisika]" value="{{ old('bobot_mapel.ipa.fisika', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Kimia</label>
|
||||
<input type="number" name="bobot_kimia" value="{{ old('bobot_kimia', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
<input type="number" name="bobot_mapel[ipa][kimia]" value="{{ old('bobot_mapel.ipa.kimia', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Biologi</label>
|
||||
<input type="number" name="bobot_biologi" value="{{ old('bobot_biologi', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
<input type="number" name="bobot_mapel[ipa][biologi]" value="{{ old('bobot_mapel.ipa.biologi', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -104,19 +104,19 @@
|
|||
<div class="space-y-3">
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Ekonomi</label>
|
||||
<input type="number" name="bobot_ekonomi" value="{{ old('bobot_ekonomi', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
<input type="number" name="bobot_mapel[ips][ekonomi]" value="{{ old('bobot_mapel.ips.ekonomi', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Geografi</label>
|
||||
<input type="number" name="bobot_geografi" value="{{ old('bobot_geografi', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
<input type="number" name="bobot_mapel[ips][geografi]" value="{{ old('bobot_mapel.ips.geografi', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Sosiologi</label>
|
||||
<input type="number" name="bobot_sosiologi" value="{{ old('bobot_sosiologi', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
<input type="number" name="bobot_mapel[ips][sosiologi]" value="{{ old('bobot_mapel.ips.sosiologi', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Sejarah</label>
|
||||
<input type="number" name="bobot_sejarah" value="{{ old('bobot_sejarah', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
<input type="number" name="bobot_mapel[ips][sejarah]" value="{{ old('bobot_mapel.ips.sejarah', '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -139,10 +139,11 @@
|
|||
|
||||
@section('scripts')
|
||||
<script>
|
||||
function updateCharCount(textareaName, max) {
|
||||
function updateCharCount(textareaName) {
|
||||
const textarea = document.querySelector(`textarea[name="${textareaName}"]`);
|
||||
const countSpan = document.getElementById('descCount');
|
||||
countSpan.textContent = `${textarea.value.length}/${max}`;
|
||||
const maxLength = parseInt(textarea.maxLength);
|
||||
countSpan.textContent = maxLength > 0 ? `${textarea.value.length}/${maxLength}` : `${textarea.value.length}`;
|
||||
}
|
||||
|
||||
function validateJurusanForm() {
|
||||
|
|
@ -197,7 +198,7 @@ function validateBobot() {
|
|||
document.addEventListener('DOMContentLoaded', function() {
|
||||
validateJurusanForm();
|
||||
validateBobot();
|
||||
updateCharCount('deskripsi', 500);
|
||||
updateCharCount('deskripsi');
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
|
|
|
|||
|
|
@ -46,11 +46,11 @@
|
|||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Deskripsi <span class="text-gray-400 text-xs">(maks 500 karakter)</span></label>
|
||||
<textarea name="deskripsi" rows="3" maxlength="500" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 transition" placeholder="Jelaskan singkat tentang jurusan ini" oninput="updateCharCount('deskripsi', 500); validateJurusanForm()">{{ old('deskripsi', $jurusan->deskripsi) }}</textarea>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Deskripsi <span class="text-gray-400 text-xs">(disarankan detail untuk kebutuhan chatbot)</span></label>
|
||||
<textarea name="deskripsi" rows="3" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 transition" placeholder="Jelaskan detail tentang jurusan ini" oninput="updateCharCount('deskripsi'); validateJurusanForm()">{{ old('deskripsi', $jurusan->deskripsi) }}</textarea>
|
||||
<div class="flex justify-between items-center mt-1">
|
||||
<p class="text-xs text-gray-500">Jelaskan tentang program, fasilitas, dan prospek</p>
|
||||
<span id="descCount" class="text-gray-400 text-xs">0/500</span>
|
||||
<span id="descCount" class="text-gray-400 text-xs">0</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -69,8 +69,8 @@
|
|||
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-gray-700 mb-2">Preferensi Studi <span class="text-gray-400 text-xs">(pisahkan dengan koma)</span></label>
|
||||
<textarea name="preferensi_studi" rows="2" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 transition" placeholder="Contoh: Sains & Teknologi, Bisnis & Manajemen">{{ old('preferensi_studi', implode(', ', $jurusan->preferensi_studi ?? [])) }}</textarea>
|
||||
<p class="text-xs text-gray-500 mt-1">Pilihan: Sains & Teknologi | Pertanian & Lingkungan | Kesehatan & Ilmu Hayat | Bisnis & Manajemen | Sosial & Humaniora</p>
|
||||
<textarea name="preferensi_studi" rows="2" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 transition" placeholder="Contoh: Praktik Langsung, DuDi, Project Based, Blended Learning">{{ old('preferensi_studi', implode(', ', $jurusan->preferensi_studi ?? [])) }}</textarea>
|
||||
<p class="text-xs text-gray-500 mt-1">Pilihan preferensi studi: Praktik Langsung, DuDi, Project Based, Blended Learning</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
|
@ -83,6 +83,8 @@
|
|||
<!-- Bobot Mata Pelajaran -->
|
||||
@php
|
||||
$bobot = $jurusan->bobot_mapel ?? [];
|
||||
$bobotIpa = data_get($bobot, 'ipa', $bobot);
|
||||
$bobotIps = data_get($bobot, 'ips', $bobot);
|
||||
@endphp
|
||||
<div class="bg-white rounded-lg shadow p-6">
|
||||
<h3 class="text-lg font-bold text-bk mb-4">⚖️ Bobot Mata Pelajaran</h3>
|
||||
|
|
@ -94,19 +96,19 @@
|
|||
<div class="space-y-3">
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Matematika</label>
|
||||
<input type="number" name="bobot_mtk" value="{{ old('bobot_mtk', $bobot['mtk'] ?? '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
<input type="number" name="bobot_mapel[ipa][mtk]" value="{{ old('bobot_mapel.ipa.mtk', data_get($bobotIpa, 'mtk', data_get($bobot, 'mtk', '0.25'))) }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Fisika</label>
|
||||
<input type="number" name="bobot_fisika" value="{{ old('bobot_fisika', $bobot['fisika'] ?? '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
<input type="number" name="bobot_mapel[ipa][fisika]" value="{{ old('bobot_mapel.ipa.fisika', data_get($bobotIpa, 'fisika', data_get($bobot, 'fisika', '0.25'))) }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Kimia</label>
|
||||
<input type="number" name="bobot_kimia" value="{{ old('bobot_kimia', $bobot['kimia'] ?? '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
<input type="number" name="bobot_mapel[ipa][kimia]" value="{{ old('bobot_mapel.ipa.kimia', data_get($bobotIpa, 'kimia', data_get($bobot, 'kimia', '0.25'))) }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Biologi</label>
|
||||
<input type="number" name="bobot_biologi" value="{{ old('bobot_biologi', $bobot['biologi'] ?? '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
<input type="number" name="bobot_mapel[ipa][biologi]" value="{{ old('bobot_mapel.ipa.biologi', data_get($bobotIpa, 'biologi', data_get($bobot, 'biologi', '0.25'))) }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -115,19 +117,19 @@
|
|||
<div class="space-y-3">
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Ekonomi</label>
|
||||
<input type="number" name="bobot_ekonomi" value="{{ old('bobot_ekonomi', $bobot['ekonomi'] ?? '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
<input type="number" name="bobot_mapel[ips][ekonomi]" value="{{ old('bobot_mapel.ips.ekonomi', data_get($bobotIps, 'ekonomi', data_get($bobot, 'ekonomi', '0.25'))) }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Geografi</label>
|
||||
<input type="number" name="bobot_geografi" value="{{ old('bobot_geografi', $bobot['geografi'] ?? '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
<input type="number" name="bobot_mapel[ips][geografi]" value="{{ old('bobot_mapel.ips.geografi', data_get($bobotIps, 'geografi', data_get($bobot, 'geografi', '0.25'))) }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Sosiologi</label>
|
||||
<input type="number" name="bobot_sosiologi" value="{{ old('bobot_sosiologi', $bobot['sosiologi'] ?? '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
<input type="number" name="bobot_mapel[ips][sosiologi]" value="{{ old('bobot_mapel.ips.sosiologi', data_get($bobotIps, 'sosiologi', data_get($bobot, 'sosiologi', '0.25'))) }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-gray-600 mb-1">Sejarah</label>
|
||||
<input type="number" name="bobot_sejarah" value="{{ old('bobot_sejarah', $bobot['sejarah'] ?? '0.25') }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
<input type="number" name="bobot_mapel[ips][sejarah]" value="{{ old('bobot_mapel.ips.sejarah', data_get($bobotIps, 'sejarah', data_get($bobot, 'sejarah', '0.25'))) }}" step="0.05" min="0" max="1" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-400 text-sm" oninput="validateBobot()">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -150,10 +152,11 @@
|
|||
|
||||
@section('scripts')
|
||||
<script>
|
||||
function updateCharCount(textareaName, max) {
|
||||
function updateCharCount(textareaName) {
|
||||
const textarea = document.querySelector(`textarea[name="${textareaName}"]`);
|
||||
const countSpan = document.getElementById('descCount');
|
||||
countSpan.textContent = `${textarea.value.length}/${max}`;
|
||||
const maxLength = parseInt(textarea.maxLength);
|
||||
countSpan.textContent = maxLength > 0 ? `${textarea.value.length}/${maxLength}` : `${textarea.value.length}`;
|
||||
}
|
||||
|
||||
function validateJurusanForm() {
|
||||
|
|
@ -208,7 +211,7 @@ function validateBobot() {
|
|||
document.addEventListener('DOMContentLoaded', function() {
|
||||
validateJurusanForm();
|
||||
validateBobot();
|
||||
updateCharCount('deskripsi', 500);
|
||||
updateCharCount('deskripsi');
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
|
|
|
|||
|
|
@ -97,23 +97,23 @@
|
|||
<p class="text-gray-700 text-sm mb-4">Sistem menggunakan 5 kriteria utama untuk memberikan rekomendasi jurusan yang tepat:</p>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<div class="p-4 bg-blue-50 rounded-lg border-l-4 border-blue-400">
|
||||
<p class="font-bold text-blue-800 text-sm">📝 Nilai Akademik (40%)</p>
|
||||
<p class="font-bold text-blue-800 text-sm">📝 Nilai Akademik (15.6%)</p>
|
||||
<p class="text-xs text-blue-700 mt-1">IPA: MTK, Fisika, Kimia, Biologi<br>IPS: Ekonomi, Geografi, Sosiologi, Sejarah</p>
|
||||
</div>
|
||||
<div class="p-4 bg-green-50 rounded-lg border-l-4 border-green-400">
|
||||
<p class="font-bold text-green-800 text-sm">💡 Minat & Bakat (35%)</p>
|
||||
<p class="font-bold text-green-800 text-sm">💡 Minat & Bakat (45.6%)</p>
|
||||
<p class="text-xs text-green-700 mt-1">Dicocokkan dengan keywords jurusan secara graduated</p>
|
||||
</div>
|
||||
<div class="p-4 bg-yellow-50 rounded-lg border-l-4 border-yellow-400">
|
||||
<p class="font-bold text-yellow-800 text-sm">🎯 Preferensi Studi (15%)</p>
|
||||
<p class="font-bold text-yellow-800 text-sm">🎯 Preferensi Studi (25.6%)</p>
|
||||
<p class="text-xs text-yellow-700 mt-1">Praktik Langsung, DuDi, Project Based, Blended Learning</p>
|
||||
</div>
|
||||
<div class="p-4 bg-purple-50 rounded-lg border-l-4 border-purple-400">
|
||||
<p class="font-bold text-purple-800 text-sm">🏆 Prestasi (5%)</p>
|
||||
<p class="font-bold text-purple-800 text-sm">🏆 Prestasi (4%)</p>
|
||||
<p class="text-xs text-purple-700 mt-1">Prestasi akademik dan non-akademik siswa</p>
|
||||
</div>
|
||||
<div class="p-4 bg-red-50 rounded-lg border-l-4 border-red-400">
|
||||
<p class="font-bold text-red-800 text-sm">💼 Cita-cita (5%)</p>
|
||||
<p class="font-bold text-red-800 text-sm">💼 Cita-cita (9%)</p>
|
||||
<p class="text-xs text-red-700 mt-1">Dicocokkan dengan keywords jurusan secara graduated</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -8,17 +8,17 @@
|
|||
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||||
<style>
|
||||
/* Keep BK theme, but also support admin-style utility classes used by Alumni pages */
|
||||
.gradient-maroon { background: linear-gradient(135deg, #5B7B89 0%, #7B9BA5 100%); }
|
||||
.text-maroon { color: #5B7B89; }
|
||||
.border-maroon { border-color: #5B7B89; }
|
||||
.bg-maroon { background-color: #5B7B89; }
|
||||
.gradient-maroon { background: linear-gradient(135deg, #6B7280 0%, #8B95A5 100%); }
|
||||
.text-maroon { color: #6B7280; }
|
||||
.border-maroon { border-color: #6B7280; }
|
||||
.bg-maroon { background-color: #6B7280; }
|
||||
|
||||
.gradient-bk { background: linear-gradient(135deg, #0f766e 0%, #14b8a6 100%); }
|
||||
.text-bk { color: #0f766e; }
|
||||
.border-bk { border-color: #0f766e; }
|
||||
.gradient-bk { background: linear-gradient(135deg, #5A8A7F 0%, #7BA39A 100%); }
|
||||
.text-bk { color: #5A8A7F; }
|
||||
.border-bk { border-color: #5A8A7F; }
|
||||
.bg-cream { background-color: #F8FAFC; }
|
||||
.stat-card { transition: all 0.3s ease; }
|
||||
.stat-card:hover { transform: translateY(-5px); box-shadow: 0 5px 15px rgba(15, 118, 110, 0.1); }
|
||||
.stat-card:hover { transform: translateY(-5px); box-shadow: 0 5px 15px rgba(90, 138, 127, 0.1); }
|
||||
|
||||
/* Sidebar */
|
||||
.sidebar-dark {
|
||||
|
|
@ -31,14 +31,14 @@
|
|||
color: #cbd5e1;
|
||||
}
|
||||
.sidebar-link:hover {
|
||||
background: rgba(20, 184, 166, 0.12);
|
||||
background: rgba(90, 138, 127, 0.12);
|
||||
color: #ffffff;
|
||||
border-left-color: rgba(20, 184, 166, 0.5);
|
||||
border-left-color: rgba(90, 138, 127, 0.5);
|
||||
}
|
||||
.sidebar-link.active {
|
||||
background: linear-gradient(90deg, rgba(20,184,166,0.2) 0%, rgba(20,184,166,0.03) 100%);
|
||||
color: #5eead4 !important;
|
||||
border-left-color: #5eead4;
|
||||
background: linear-gradient(90deg, rgba(90,138,127,0.2) 0%, rgba(90,138,127,0.03) 100%);
|
||||
color: #a8bfb8 !important;
|
||||
border-left-color: #a8bfb8;
|
||||
}
|
||||
.sidebar-link .sidebar-icon {
|
||||
display: inline-flex;
|
||||
|
|
@ -53,11 +53,11 @@
|
|||
transition: all 0.25s ease;
|
||||
}
|
||||
.sidebar-link:hover .sidebar-icon {
|
||||
background: rgba(20, 184, 166, 0.25);
|
||||
background: rgba(90, 138, 127, 0.25);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
.sidebar-link.active .sidebar-icon {
|
||||
background: rgba(94, 234, 212, 0.15);
|
||||
background: rgba(90, 138, 127, 0.15);
|
||||
}
|
||||
.sidebar-section-label {
|
||||
font-size: 10px;
|
||||
|
|
@ -77,13 +77,13 @@
|
|||
.sidebar-brand-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background: linear-gradient(135deg, #0f766e 0%, #14b8a6 100%);
|
||||
background: linear-gradient(135deg, #5A8A7F 0%, #7BA39A 100%);
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 20px;
|
||||
box-shadow: 0 4px 12px rgba(15, 118, 110, 0.3);
|
||||
box-shadow: 0 4px 12px rgba(90, 138, 127, 0.3);
|
||||
}
|
||||
.sidebar-footer {
|
||||
border-top: 1px solid rgba(255,255,255,0.06);
|
||||
|
|
|
|||
|
|
@ -7,13 +7,13 @@
|
|||
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||||
<style>
|
||||
.gradient-maroon {
|
||||
background: linear-gradient(135deg, #5B7B89 0%, #7B9BA5 100%);
|
||||
background: linear-gradient(135deg, #6B7280 0%, #8B95A5 100%);
|
||||
}
|
||||
.text-maroon {
|
||||
color: #5B7B89;
|
||||
color: #6B7280;
|
||||
}
|
||||
.border-maroon {
|
||||
border-color: #5B7B89;
|
||||
border-color: #6B7280;
|
||||
}
|
||||
.bg-cream {
|
||||
background-color: #F8FAFC;
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
.chat-container {
|
||||
height: 500px;
|
||||
}
|
||||
}
|
||||
}}
|
||||
@media (min-width: 1024px) {
|
||||
.chat-container {
|
||||
height: 600px;
|
||||
|
|
@ -110,7 +110,7 @@
|
|||
<p class="text-xs sm:text-sm text-yellow-300 font-semibold mt-1">Konseling Pemilihan Jurusan Politeknik Negeri Jember</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 sm:gap-4 w-full sm:w-auto">
|
||||
<a href="{{ route('chatbot.index') }}" class="block sm:inline-block flex-1 sm:flex-none text-center bg-white text-maroon font-bold py-2 px-3 sm:px-4 rounded-lg hover:bg-gray-100 transition text-xs sm:text-sm">
|
||||
<a href="{{ url('/chatbot?new=1') }}" class="block sm:inline-block flex-1 sm:flex-none text-center bg-white text-maroon font-bold py-2 px-3 sm:px-4 rounded-lg hover:bg-gray-100 transition text-xs sm:text-sm">
|
||||
Sesi Baru
|
||||
</a>
|
||||
<a href="{{ url('/dashboard') }}" class="block sm:inline-block flex-1 sm:flex-none text-center bg-yellow-400 text-maroon font-bold py-2 px-3 sm:px-4 rounded-lg hover:bg-yellow-300 transition text-xs sm:text-sm">
|
||||
|
|
|
|||
|
|
@ -7,13 +7,13 @@
|
|||
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||||
<style>
|
||||
.gradient-maroon {
|
||||
background: linear-gradient(135deg, #5B7B89 0%, #7B9BA5 100%);
|
||||
background: linear-gradient(135deg, #6B7280 0%, #8B95A5 100%);
|
||||
}
|
||||
.text-maroon {
|
||||
color: #5B7B89;
|
||||
color: #6B7280;
|
||||
}
|
||||
.border-maroon {
|
||||
border-color: #5B7B89;
|
||||
border-color: #6B7280;
|
||||
}
|
||||
.bg-cream {
|
||||
background-color: #F8FAFC;
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
}
|
||||
.card-hover:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 10px 30px rgba(107, 44, 44, 0.2);
|
||||
box-shadow: 0 10px 30px rgba(107, 114, 128, 0.15);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
|
@ -64,179 +64,173 @@
|
|||
</header>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="container mx-auto px-4 sm:px-6 py-6 sm:py-12">
|
||||
<!-- Info Box -->
|
||||
<div class="bg-white border-2 border-maroon rounded-lg p-4 sm:p-6 mb-6 sm:mb-8 shadow-md">
|
||||
<h2 class="text-lg sm:text-xl md:text-2xl font-bold text-maroon mb-2 sm:mb-3">Selamat Datang di Sistem Pemilihan Jurusan</h2>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700 mb-3 sm:mb-4">
|
||||
Memilih jurusan adalah keputusan penting yang akan mempengaruhi karir dan masa depan Anda. Sistem ini dirancang untuk membantu Anda menemukan jurusan kuliah yang paling sesuai dengan profil akademik, minat, gaya belajar, prestasi, dan cita-cita Anda.
|
||||
<div class="w-full px-4 sm:px-6 py-6 sm:py-8">
|
||||
<!-- Hero Section -->
|
||||
<div class="bg-gradient-to-r from-purple-600 to-indigo-600 rounded-xl shadow-xl p-8 sm:p-10 mb-8 text-white">
|
||||
<h2 class="text-3xl sm:text-4xl font-bold mb-3">Temukan Jurusan Impianmu 🎯</h2>
|
||||
<p class="text-purple-100 text-lg mb-4 max-w-3xl">
|
||||
Memilih jurusan adalah salah satu keputusan terpenting dalam hidup. Kami ada di sini untuk membantu kamu menemukan program studi yang benar-benar sesuai dengan potensi, minat, dan impian karirmu. Dengan teknologi AI dan analisis mendalam, kami siap memberikan panduan terbaik.
|
||||
</p>
|
||||
|
||||
<div class="bg-yellow-50 border-l-4 border-yellow-400 p-3 sm:p-4 mb-4 rounded">
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-800">
|
||||
<strong>Bagaimana Sistem Ini Bekerja?</strong> Kami menganalisis 5 faktor utama dalam diri Anda: nilai akademik (40%), minat dan passion (35%), preferensi gaya belajar (15%), prestasi dan pencapaian (5%), serta cita-cita dan rencana karir (5%). Dari analisis mendalam tersebut, sistem memberikan ranking 9 jurusan yang tersedia berdasarkan kesesuaian dengan profil Anda.
|
||||
</p>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4 mt-6">
|
||||
<div class="bg-white bg-opacity-20 rounded-lg p-4 backdrop-blur-sm">
|
||||
<p class="text-3xl font-bold">9</p>
|
||||
<p class="text-purple-100 text-sm">Jurusan</p>
|
||||
</div>
|
||||
<div class="bg-white bg-opacity-20 rounded-lg p-4 backdrop-blur-sm">
|
||||
<p class="text-3xl font-bold">24/7</p>
|
||||
<p class="text-purple-100 text-sm">Konsultasi AI</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700 mb-3 sm:mb-4">
|
||||
<strong>Fitur-Fitur yang Tersedia:</strong>
|
||||
</p>
|
||||
<ul class="text-xs sm:text-sm md:text-base text-gray-700 space-y-2 mb-4">
|
||||
<li class="flex gap-2">
|
||||
<span class="text-maroon">✓</span>
|
||||
<span><strong>Analisis Rekomendasi:</strong> Isi kuesioner singkat dan dapatkan rekomendasi 9 jurusan yang disesuaikan dengan profil Anda</span>
|
||||
</li>
|
||||
<li class="flex gap-2">
|
||||
<span class="text-maroon">✓</span>
|
||||
<span><strong>Konsultasi dengan AI:</strong> Chat dengan konselor BK virtual yang siap menjawab pertanyaan tentang jurusan, prospek karir, dan tips sukses kuliah</span>
|
||||
</li>
|
||||
<li class="flex gap-2">
|
||||
<span class="text-maroon">✓</span>
|
||||
<span><strong>Riwayat Analisis:</strong> Lihat kembali semua analisis dan chat history Anda kapan saja untuk referensi</span>
|
||||
</li>
|
||||
<li class="flex gap-2">
|
||||
<span class="text-maroon">✓</span>
|
||||
<span><strong>Profil Pribadi:</strong> Kelola data diri, foto profil, dan informasi akademik Anda</span>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700 text-italic">
|
||||
💡 <strong>Tips:</strong> Untuk hasil yang akurat, jawab semua pertanyaan dengan jujur dan detail. Semakin detail profil Anda, semakin akurat rekomendasi yang kami berikan.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Main Actions Grid -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 sm:gap-8 mb-6 sm:mb-12">
|
||||
<!-- Quick Action Cards -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8">
|
||||
<!-- Rekomendasi Card -->
|
||||
<div class="card-hover bg-white rounded-lg shadow-lg p-5 sm:p-8 border-l-4 border-blue-500 flex flex-col h-full">
|
||||
<div class="flex items-start gap-3 sm:gap-4 mb-3 sm:mb-4 flex-grow">
|
||||
<div class="text-3xl sm:text-4xl flex-shrink-0">📊</div>
|
||||
<div class="card-hover bg-gradient-to-br from-blue-50 to-blue-100 rounded-xl shadow-lg p-8 border-2 border-blue-300 hover:border-blue-400 transition">
|
||||
<div class="flex items-start gap-4 mb-6">
|
||||
<div class="w-16 h-16 bg-blue-500 rounded-lg flex items-center justify-center text-white text-3xl shadow-md">📊</div>
|
||||
<div>
|
||||
<h3 class="text-lg sm:text-lg md:text-2xl font-bold text-maroon mb-1 sm:mb-2">Analisis Rekomendasi</h3>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">
|
||||
Isi formulir singkat tentang profil Anda. Sistem akan menganalisis dan memberikan rekomendasi dari 9 jurusan yang tersedia.
|
||||
</p>
|
||||
<h3 class="text-2xl font-bold text-blue-900 mb-1">Cari Jurusan Terbaikmu</h3>
|
||||
<p class="text-blue-700">Rekomendasi Khusus</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 sm:mt-6">
|
||||
<a href="{{ url('/rekomendasi') }}" class="block w-full text-center bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 sm:py-3 px-4 sm:px-6 rounded-lg transition duration-200 text-sm sm:text-base">
|
||||
Mulai Analisis Baru
|
||||
</a>
|
||||
</div>
|
||||
<div class="mt-3 sm:mt-4 p-2 sm:p-3 bg-blue-50 rounded-lg">
|
||||
<p class="text-xs sm:text-sm text-blue-800">
|
||||
<strong>Durasi:</strong> 3-5 menit | <strong>Metode:</strong> AI Analysis
|
||||
</p>
|
||||
<p class="text-blue-800 mb-6 leading-relaxed">
|
||||
Jawab beberapa pertanyaan tentang nilai akademik, minat, gaya belajar, dan cita-cita kamu. Sistem kami akan menganalisis profil lengkap kamu dan memberikan rekomendasi jurusan yang paling cocok, lengkap dengan penjelasan alasan kesesuaiannya.
|
||||
</p>
|
||||
<div class="flex items-center justify-between bg-white rounded-lg p-4 mb-6">
|
||||
<span class="text-sm font-semibold text-gray-600">⏱️ Waktu: 3-5 menit</span>
|
||||
<span class="text-sm font-semibold text-blue-600">📈 Akurasi Tinggi</span>
|
||||
</div>
|
||||
<a href="{{ url('/rekomendasi') }}" class="block w-full text-center bg-gradient-to-r from-blue-600 to-blue-700 hover:from-blue-700 hover:to-blue-800 text-white font-bold py-3 px-6 rounded-lg transition duration-300 shadow-md transform hover:scale-105">
|
||||
Mulai Analisis →
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Chatbot Card -->
|
||||
<div class="card-hover bg-white rounded-lg shadow-lg p-5 sm:p-8 border-l-4 border-green-500 flex flex-col h-full">
|
||||
<div class="flex items-start gap-3 sm:gap-4 mb-3 sm:mb-4 flex-grow">
|
||||
<div class="text-3xl sm:text-4xl flex-shrink-0">💬</div>
|
||||
<div class="card-hover bg-gradient-to-br from-green-50 to-green-100 rounded-xl shadow-lg p-8 border-2 border-green-300 hover:border-green-400 transition">
|
||||
<div class="flex items-start gap-4 mb-6">
|
||||
<div class="w-16 h-16 bg-green-500 rounded-lg flex items-center justify-center text-white text-3xl shadow-md">💬</div>
|
||||
<div>
|
||||
<h3 class="text-lg sm:text-lg md:text-2xl font-bold text-maroon mb-1 sm:mb-2">Chat dengan AI</h3>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">
|
||||
Tanya jawab tentang jurusan, kurikulum, prospek karir, dan pertanyaan seputar pemilihan jurusan.
|
||||
</p>
|
||||
<h3 class="text-2xl font-bold text-green-900 mb-1">Tanya Jawab dengan AI</h3>
|
||||
<p class="text-green-700">Konsultan Karir Virtual</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 sm:mt-6">
|
||||
<a href="{{ url('/chatbot') }}" class="block w-full text-center bg-green-600 hover:bg-green-700 text-white font-bold py-2 sm:py-3 px-4 sm:px-6 rounded-lg transition duration-200 text-sm sm:text-base">
|
||||
Mulai Chat
|
||||
</a>
|
||||
<p class="text-green-800 mb-6 leading-relaxed">
|
||||
Ada pertanyaan tentang jurusan tertentu? Penasaran dengan prospek karir? Atau butuh tips sukses masuk kuliah? Chat dengan konselor AI kami yang siap membantu kapan saja. Dapatkan jawaban detail dan rekomendasi personal untuk setiap pertanyaan kamu.
|
||||
</p>
|
||||
<div class="flex items-center justify-between bg-white rounded-lg p-4 mb-6">
|
||||
<span class="text-sm font-semibold text-gray-600">⭐ Respons Cepat</span>
|
||||
<span class="text-sm font-semibold text-green-600">🤖 AI Powered</span>
|
||||
</div>
|
||||
<div class="mt-3 sm:mt-4 p-2 sm:p-3 bg-green-50 rounded-lg">
|
||||
<p class="text-xs sm:text-sm text-green-800">
|
||||
<strong>Fitur:</strong> Tanya jawab dengan AI
|
||||
</p>
|
||||
<a href="{{ url('/chatbot?new=1') }}" class="block w-full text-center bg-gradient-to-r from-green-600 to-green-700 hover:from-green-700 hover:to-green-800 text-white font-bold py-3 px-6 rounded-lg transition duration-300 shadow-md transform hover:scale-105">
|
||||
Mulai Konsultasi →
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Features Grid -->
|
||||
<div class="bg-white rounded-xl shadow-lg p-8 mb-8">
|
||||
<h3 class="text-2xl font-bold text-gray-900 mb-8">Fitur Lengkap untuk Pendampinganmu</h3>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
<div class="text-center p-6 rounded-lg bg-gradient-to-br from-purple-50 to-purple-100 hover:shadow-md transition">
|
||||
<div class="text-4xl mb-3">📋</div>
|
||||
<h4 class="font-bold text-gray-900 mb-2">Rekomendasi Personal</h4>
|
||||
<p class="text-sm text-gray-700">Analisis mendalam berdasarkan profil unik kamu</p>
|
||||
</div>
|
||||
<div class="text-center p-6 rounded-lg bg-gradient-to-br from-blue-50 to-blue-100 hover:shadow-md transition">
|
||||
<div class="text-4xl mb-3">💬</div>
|
||||
<h4 class="font-bold text-gray-900 mb-2">Chat 24/7</h4>
|
||||
<p class="text-sm text-gray-700">Konsultasi kapan saja dengan AI konselor</p>
|
||||
</div>
|
||||
<div class="text-center p-6 rounded-lg bg-gradient-to-br from-green-50 to-green-100 hover:shadow-md transition">
|
||||
<div class="text-4xl mb-3">📚</div>
|
||||
<h4 class="font-bold text-gray-900 mb-2">Info Jurusan</h4>
|
||||
<p class="text-sm text-gray-700">Detail lengkap tentang setiap program studi</p>
|
||||
</div>
|
||||
<div class="text-center p-6 rounded-lg bg-gradient-to-br from-orange-50 to-orange-100 hover:shadow-md transition">
|
||||
<div class="text-4xl mb-3">📊</div>
|
||||
<h4 class="font-bold text-gray-900 mb-2">Riwayat</h4>
|
||||
<p class="text-sm text-gray-700">Simpan & bandingkan hasil analisis sebelumnya</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Info Section -->
|
||||
<div class="bg-white rounded-lg shadow-lg p-5 sm:p-8 mb-6 sm:mb-8">
|
||||
<h3 class="text-lg sm:text-xl md:text-2xl font-bold text-maroon mb-4 sm:mb-6">9 Jurusan Tersedia</h3>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 sm:gap-6">
|
||||
<div class="p-3 sm:p-4 bg-gradient-to-br from-yellow-50 to-orange-50 rounded-lg border border-maroon">
|
||||
<div class="text-2xl sm:text-3xl mb-1 sm:mb-2">🌾</div>
|
||||
<h4 class="font-bold text-sm sm:text-base text-maroon">Produksi Pertanian</h4>
|
||||
<p class="text-xs sm:text-sm text-gray-700 mt-1">Teknik budidaya tanaman modern</p>
|
||||
<!-- Process Section -->
|
||||
<div class="bg-gradient-to-r from-indigo-600 to-purple-600 rounded-xl p-8 text-white mb-8">
|
||||
<h3 class="text-2xl font-bold mb-8">Bagaimana Cara Kerjanya? 🔍</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-6">
|
||||
<div class="text-center">
|
||||
<div class="w-12 h-12 rounded-full bg-white text-indigo-600 font-bold text-xl flex items-center justify-center mx-auto mb-4 shadow-lg">1</div>
|
||||
<h4 class="font-bold mb-2">Isi Kuesioner</h4>
|
||||
<p class="text-indigo-100 text-sm">Jawab pertanyaan tentang nilai, minat, dan impian kamu secara jujur</p>
|
||||
</div>
|
||||
<div class="p-3 sm:p-4 bg-gradient-to-br from-green-50 to-teal-50 rounded-lg border border-maroon">
|
||||
<div class="text-2xl sm:text-3xl mb-1 sm:mb-2">🔬</div>
|
||||
<h4 class="font-bold text-sm sm:text-base text-maroon">Teknologi Pertanian</h4>
|
||||
<p class="text-xs sm:text-sm text-gray-700 mt-1">Inovasi teknologi pertanian</p>
|
||||
<div class="text-center">
|
||||
<div class="w-12 h-12 rounded-full bg-white text-indigo-600 font-bold text-xl flex items-center justify-center mx-auto mb-4 shadow-lg">2</div>
|
||||
<h4 class="font-bold mb-2">Proses Data</h4>
|
||||
<p class="text-indigo-100 text-sm">AI menganalisis profil kamu dengan algoritma machine learning</p>
|
||||
</div>
|
||||
<div class="p-3 sm:p-4 bg-gradient-to-br from-blue-50 to-purple-50 rounded-lg border border-maroon">
|
||||
<div class="text-2xl sm:text-3xl mb-1 sm:mb-2">🐄</div>
|
||||
<h4 class="font-bold text-sm sm:text-base text-maroon">Peternakan</h4>
|
||||
<p class="text-xs sm:text-sm text-gray-700 mt-1">Manajemen peternakan</p>
|
||||
<div class="text-center">
|
||||
<div class="w-12 h-12 rounded-full bg-white text-indigo-600 font-bold text-xl flex items-center justify-center mx-auto mb-4 shadow-lg">3</div>
|
||||
<h4 class="font-bold mb-2">Dapatkan Hasil</h4>
|
||||
<p class="text-indigo-100 text-sm">Terima ranking 9 jurusan dengan skor kesesuaian detail</p>
|
||||
</div>
|
||||
<div class="p-3 sm:p-4 bg-gradient-to-br from-red-50 to-pink-50 rounded-lg border border-maroon">
|
||||
<div class="text-2xl sm:text-3xl mb-1 sm:mb-2">💼</div>
|
||||
<h4 class="font-bold text-sm sm:text-base text-maroon">Manajemen Agribisnis</h4>
|
||||
<p class="text-xs sm:text-sm text-gray-700 mt-1">Bisnis pertanian</p>
|
||||
</div>
|
||||
<div class="p-3 sm:p-4 bg-gradient-to-br from-indigo-50 to-blue-50 rounded-lg border border-maroon">
|
||||
<div class="text-2xl sm:text-3xl mb-1 sm:mb-2">💻</div>
|
||||
<h4 class="font-bold text-sm sm:text-base text-maroon">Teknologi Informasi</h4>
|
||||
<p class="text-xs sm:text-sm text-gray-700 mt-1">Sistem digital</p>
|
||||
</div>
|
||||
<div class="p-3 sm:p-4 bg-gradient-to-br from-amber-50 to-yellow-50 rounded-lg border border-maroon">
|
||||
<div class="text-2xl sm:text-3xl mb-1 sm:mb-2">⚙️</div>
|
||||
<h4 class="font-bold text-sm sm:text-base text-maroon">Teknik</h4>
|
||||
<p class="text-xs sm:text-sm text-gray-700 mt-1">Mesin & sistem teknik</p>
|
||||
</div>
|
||||
<div class="p-3 sm:p-4 bg-gradient-to-br from-rose-50 to-red-50 rounded-lg border border-maroon">
|
||||
<div class="text-2xl sm:text-3xl mb-1 sm:mb-2">⚕️</div>
|
||||
<h4 class="font-bold text-sm sm:text-base text-maroon">Kesehatan</h4>
|
||||
<p class="text-xs sm:text-sm text-gray-700 mt-1">Profesi kesehatan</p>
|
||||
</div>
|
||||
<div class="p-3 sm:p-4 bg-gradient-to-br from-sky-50 to-cyan-50 rounded-lg border border-maroon">
|
||||
<div class="text-2xl sm:text-3xl mb-1 sm:mb-2">🗣️</div>
|
||||
<h4 class="font-bold text-sm sm:text-base text-maroon">Bahasa & Komunikasi</h4>
|
||||
<p class="text-xs sm:text-sm text-gray-700 mt-1">Komunasikan & wisata</p>
|
||||
</div>
|
||||
<div class="p-3 sm:p-4 bg-gradient-to-br from-lime-50 to-green-50 rounded-lg border border-maroon">
|
||||
<div class="text-2xl sm:text-3xl mb-1 sm:mb-2">📊</div>
|
||||
<h4 class="font-bold text-sm sm:text-base text-maroon">Bisnis</h4>
|
||||
<p class="text-xs sm:text-sm text-gray-700 mt-1">Manajemen bisnis</p>
|
||||
<div class="text-center">
|
||||
<div class="w-12 h-12 rounded-full bg-white text-indigo-600 font-bold text-xl flex items-center justify-center mx-auto mb-4 shadow-lg">4</div>
|
||||
<h4 class="font-bold mb-2">Konsultasi Lanjut</h4>
|
||||
<p class="text-indigo-100 text-sm">Diskusikan hasil & pertanyaan lanjut dengan AI konselor</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Features Section -->
|
||||
<div class="bg-white rounded-lg shadow-lg p-5 sm:p-8">
|
||||
<h3 class="text-lg sm:text-xl md:text-2xl font-bold text-maroon mb-4 sm:mb-6">Cara Kerja Sistem</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 sm:gap-6">
|
||||
<div class="flex gap-3 sm:gap-4">
|
||||
<div class="text-2xl sm:text-3xl font-bold text-maroon flex-shrink-0">1</div>
|
||||
<div>
|
||||
<h4 class="font-bold text-sm sm:text-base text-maroon mb-1">Isi Data Diri</h4>
|
||||
<p class="text-xs sm:text-sm text-gray-700">Masukkan nilai akademik, minat, preferensi, prestasi, dan cita-cita</p>
|
||||
</div>
|
||||
<!-- Programs Grid -->
|
||||
<div class="bg-white rounded-xl shadow-lg p-8">
|
||||
<h3 class="text-2xl font-bold text-gray-900 mb-2">Program Studi yang Tersedia</h3>
|
||||
<p class="text-gray-600 mb-8">Jelajahi 9 program studi unggulan kami di Politeknik Negeri Jember</p>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<div class="group p-5 rounded-lg border-2 border-gray-200 hover:border-purple-500 hover:shadow-md transition bg-gradient-to-br from-gray-50 to-white">
|
||||
<div class="text-3xl mb-3">🌾</div>
|
||||
<h4 class="font-bold text-gray-900 group-hover:text-purple-600 transition">Produksi Pertanian</h4>
|
||||
<p class="text-sm text-gray-600 mt-2">Teknik budidaya tanaman modern & berkelanjutan</p>
|
||||
</div>
|
||||
<div class="flex gap-3 sm:gap-4">
|
||||
<div class="text-2xl sm:text-3xl font-bold text-maroon flex-shrink-0">2</div>
|
||||
<div>
|
||||
<h4 class="font-bold text-sm sm:text-base text-maroon mb-1">Analisis Sistem</h4>
|
||||
<p class="text-xs sm:text-sm text-gray-700">Sistem menganalisis data menggunakan algoritma canggih</p>
|
||||
</div>
|
||||
<div class="group p-5 rounded-lg border-2 border-gray-200 hover:border-purple-500 hover:shadow-md transition bg-gradient-to-br from-gray-50 to-white">
|
||||
<div class="text-3xl mb-3">🔬</div>
|
||||
<h4 class="font-bold text-gray-900 group-hover:text-purple-600 transition">Teknologi Pertanian</h4>
|
||||
<p class="text-sm text-gray-600 mt-2">Inovasi teknologi untuk efisiensi pertanian</p>
|
||||
</div>
|
||||
<div class="flex gap-3 sm:gap-4">
|
||||
<div class="text-2xl sm:text-3xl font-bold text-maroon flex-shrink-0">3</div>
|
||||
<div>
|
||||
<h4 class="font-bold text-sm sm:text-base text-maroon mb-1">Hasil Rekomendasi</h4>
|
||||
<p class="text-xs sm:text-sm text-gray-700">Dapatkan rekomendasi 9 jurusan dengan analisis detail</p>
|
||||
</div>
|
||||
<div class="group p-5 rounded-lg border-2 border-gray-200 hover:border-purple-500 hover:shadow-md transition bg-gradient-to-br from-gray-50 to-white">
|
||||
<div class="text-3xl mb-3">🐄</div>
|
||||
<h4 class="font-bold text-gray-900 group-hover:text-purple-600 transition">Peternakan</h4>
|
||||
<p class="text-sm text-gray-600 mt-2">Manajemen & teknologi peternakan terkini</p>
|
||||
</div>
|
||||
<div class="flex gap-3 sm:gap-4">
|
||||
<div class="text-2xl sm:text-3xl font-bold text-maroon flex-shrink-0">4</div>
|
||||
<div>
|
||||
<h4 class="font-bold text-sm sm:text-base text-maroon mb-1">Konsultasi Lanjut</h4>
|
||||
<p class="text-xs sm:text-sm text-gray-700">Gunakan chatbot untuk tanya jawab lebih lanjut</p>
|
||||
</div>
|
||||
<div class="group p-5 rounded-lg border-2 border-gray-200 hover:border-purple-500 hover:shadow-md transition bg-gradient-to-br from-gray-50 to-white">
|
||||
<div class="text-3xl mb-3">💼</div>
|
||||
<h4 class="font-bold text-gray-900 group-hover:text-purple-600 transition">Manajemen Agribisnis</h4>
|
||||
<p class="text-sm text-gray-600 mt-2">Bisnis & manajemen di sektor pertanian</p>
|
||||
</div>
|
||||
<div class="group p-5 rounded-lg border-2 border-gray-200 hover:border-purple-500 hover:shadow-md transition bg-gradient-to-br from-gray-50 to-white">
|
||||
<div class="text-3xl mb-3">💻</div>
|
||||
<h4 class="font-bold text-gray-900 group-hover:text-purple-600 transition">Teknologi Informasi</h4>
|
||||
<p class="text-sm text-gray-600 mt-2">Sistem digital & aplikasi web modern</p>
|
||||
</div>
|
||||
<div class="group p-5 rounded-lg border-2 border-gray-200 hover:border-purple-500 hover:shadow-md transition bg-gradient-to-br from-gray-50 to-white">
|
||||
<div class="text-3xl mb-3">⚙️</div>
|
||||
<h4 class="font-bold text-gray-900 group-hover:text-purple-600 transition">Teknik Mesin</h4>
|
||||
<p class="text-sm text-gray-600 mt-2">Teknik mesin & sistem otomasi industri</p>
|
||||
</div>
|
||||
<div class="group p-5 rounded-lg border-2 border-gray-200 hover:border-purple-500 hover:shadow-md transition bg-gradient-to-br from-gray-50 to-white">
|
||||
<div class="text-3xl mb-3">⚕️</div>
|
||||
<h4 class="font-bold text-gray-900 group-hover:text-purple-600 transition">Kesehatan</h4>
|
||||
<p class="text-sm text-gray-600 mt-2">Program kesehatan & keselamatan kerja</p>
|
||||
</div>
|
||||
<div class="group p-5 rounded-lg border-2 border-gray-200 hover:border-purple-500 hover:shadow-md transition bg-gradient-to-br from-gray-50 to-white">
|
||||
<div class="text-3xl mb-3">🗣️</div>
|
||||
<h4 class="font-bold text-gray-900 group-hover:text-purple-600 transition">Komunikasi & Pariwisata</h4>
|
||||
<p class="text-sm text-gray-600 mt-2">Program komunikasi & industri pariwisata</p>
|
||||
</div>
|
||||
<div class="group p-5 rounded-lg border-2 border-gray-200 hover:border-purple-500 hover:shadow-md transition bg-gradient-to-br from-gray-50 to-white">
|
||||
<div class="text-3xl mb-3">📊</div>
|
||||
<h4 class="font-bold text-gray-900 group-hover:text-purple-600 transition">Akuntansi & Bisnis</h4>
|
||||
<p class="text-sm text-gray-600 mt-2">Akuntansi, keuangan & manajemen bisnis</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,258 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Reset Password - Sistem Pemilihan Jurusan</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background-color: #f3f4f6;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
line-height: 1.6;
|
||||
color: #374151;
|
||||
}
|
||||
.container {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
background-color: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
overflow: hidden;
|
||||
}
|
||||
.header {
|
||||
background: linear-gradient(135deg, #6B7280 0%, #8B95A5 100%);
|
||||
padding: 40px 20px;
|
||||
text-align: center;
|
||||
color: white;
|
||||
}
|
||||
.header h1 {
|
||||
margin: 0;
|
||||
font-size: 32px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
.header p {
|
||||
margin: 8px 0 0 0;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.5px;
|
||||
color: #C9A961;
|
||||
}
|
||||
.content {
|
||||
padding: 40px;
|
||||
}
|
||||
.content h2 {
|
||||
color: #111827;
|
||||
font-size: 24px;
|
||||
margin: 0 0 16px 0;
|
||||
font-weight: 700;
|
||||
}
|
||||
.greeting {
|
||||
color: #4B5563;
|
||||
font-size: 16px;
|
||||
margin-bottom: 20px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.message {
|
||||
background-color: #f0f4f8;
|
||||
border-left: 4px solid #6B7280;
|
||||
padding: 16px;
|
||||
margin: 24px 0;
|
||||
border-radius: 6px;
|
||||
color: #374151;
|
||||
font-size: 15px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
.cta-section {
|
||||
text-align: center;
|
||||
margin: 32px 0;
|
||||
}
|
||||
.cta-button {
|
||||
display: inline-block;
|
||||
background: linear-gradient(135deg, #6B7280 0%, #8B95A5 100%);
|
||||
color: white;
|
||||
padding: 16px 48px;
|
||||
border-radius: 8px;
|
||||
text-decoration: none;
|
||||
font-weight: 700;
|
||||
font-size: 16px;
|
||||
letter-spacing: 1px;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 4px 15px rgba(107, 114, 128, 0.3);
|
||||
}
|
||||
.cta-button:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 20px rgba(107, 114, 128, 0.4);
|
||||
}
|
||||
.steps {
|
||||
background-color: #f9fafb;
|
||||
border: 2px solid #e5e7eb;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
margin: 24px 0;
|
||||
}
|
||||
.steps h3 {
|
||||
color: #111827;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
margin: 0 0 12px 0;
|
||||
}
|
||||
.step {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
margin: 12px 0;
|
||||
color: #374151;
|
||||
font-size: 15px;
|
||||
}
|
||||
.step-number {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
background: linear-gradient(135deg, #6B7280 0%, #8B95A5 100%);
|
||||
color: white;
|
||||
border-radius: 50%;
|
||||
font-weight: 700;
|
||||
font-size: 14px;
|
||||
margin-right: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.step-text {
|
||||
flex: 1;
|
||||
}
|
||||
.warning {
|
||||
background-color: #fef3c7;
|
||||
border-left: 4px solid #f59e0b;
|
||||
padding: 14px;
|
||||
margin: 24px 0;
|
||||
border-radius: 6px;
|
||||
color: #78350f;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
font-weight: 500;
|
||||
}
|
||||
.warning strong {
|
||||
color: #b45309;
|
||||
}
|
||||
.footer {
|
||||
background-color: #f9fafb;
|
||||
border-top: 1px solid #e5e7eb;
|
||||
padding: 24px 40px;
|
||||
color: #6B7280;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.footer p {
|
||||
margin: 8px 0;
|
||||
}
|
||||
.footer strong {
|
||||
color: #374151;
|
||||
}
|
||||
.contact-info {
|
||||
background-color: #f0f4f8;
|
||||
border-radius: 6px;
|
||||
padding: 14px;
|
||||
margin-top: 12px;
|
||||
font-size: 13px;
|
||||
color: #374151;
|
||||
}
|
||||
@media only screen and (max-width: 600px) {
|
||||
body {
|
||||
padding: 10px;
|
||||
}
|
||||
.content {
|
||||
padding: 24px;
|
||||
}
|
||||
.header {
|
||||
padding: 30px 20px;
|
||||
}
|
||||
.header h1 {
|
||||
font-size: 24px;
|
||||
}
|
||||
.cta-button {
|
||||
padding: 14px 32px;
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<!-- Header -->
|
||||
<div class="header">
|
||||
<h1>🔐 POLIJE</h1>
|
||||
<p>Sistem Pemilihan Jurusan</p>
|
||||
</div>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="content">
|
||||
<h2>Halo, {{ $user->name }}! 👋</h2>
|
||||
|
||||
<p class="greeting">
|
||||
Kami menerima permintaan untuk mengatur ulang password akunmu. Jika kamu yang melakukan ini, ikuti langkah-langkah di bawah untuk membuat password baru.
|
||||
</p>
|
||||
|
||||
<div class="message">
|
||||
<strong>⏰ Penting:</strong> Link reset password ini hanya berlaku selama <strong>{{ $expiresIn }} menit</strong>. Jika sudah kadaluarsa, silakan minta link baru di halaman "Lupa Password".
|
||||
</div>
|
||||
|
||||
<!-- CTA Button -->
|
||||
<div class="cta-section">
|
||||
<a href="{{ $resetUrl }}" class="cta-button">🔑 RESET PASSWORD</a>
|
||||
</div>
|
||||
|
||||
<!-- Steps -->
|
||||
<div class="steps">
|
||||
<h3>📋 Langkah-Langkah:</h3>
|
||||
<div class="step">
|
||||
<div class="step-number">1</div>
|
||||
<div class="step-text">Klik tombol <strong>"RESET PASSWORD"</strong> di atas atau copy-paste link ke browser</div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<div class="step-number">2</div>
|
||||
<div class="step-text">Isi form dengan password baru yang kuat (minimal 8 karakter)</div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<div class="step-number">3</div>
|
||||
<div class="step-text">Konfirmasi password baru dengan memasukkan ulang</div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<div class="step-number">4</div>
|
||||
<div class="step-text">Klik tombol <strong>"Simpan Password"</strong></div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<div class="step-number">5</div>
|
||||
<div class="step-text">Login dengan password baru kamu di Sistem Pemilihan Jurusan</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Warning -->
|
||||
<div class="warning">
|
||||
<strong>⚠️ Keamanan:</strong> Jika kamu tidak meminta reset password ini atau tidak mengenali aktivitas ini, abaikan email ini dan segera hubungi admin kami.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer -->
|
||||
<div class="footer">
|
||||
<p><strong>Informasi Penting:</strong></p>
|
||||
<p>
|
||||
• Jangan membagikan link ini kepada siapapun<br>
|
||||
• Link ini hanya untuk reset password, bukan untuk aktivitas lain<br>
|
||||
• Pastikan kamu menggunakan password yang kuat dan unik<br>
|
||||
• Jika ada masalah, hubungi tim dukungan kami
|
||||
</p>
|
||||
<div class="contact-info">
|
||||
<strong>💬 Butuh Bantuan?</strong><br>
|
||||
Jika link tidak berfungsi atau ada pertanyaan, hubungi BK (Bimbingan Konseling) atau admin Sistem Pemilihan Jurusan.
|
||||
</div>
|
||||
<p style="margin-top: 16px; border-top: 1px solid #e5e7eb; padding-top: 12px;">
|
||||
Terima kasih,<br>
|
||||
<strong>Tim Sistem Pemilihan Jurusan Polije</strong>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -7,19 +7,19 @@
|
|||
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||||
<style>
|
||||
.gradient-maroon {
|
||||
background: linear-gradient(135deg, #5B7B89 0%, #7B9BA5 100%);
|
||||
background: linear-gradient(135deg, #6B7280 0%, #8B95A5 100%);
|
||||
}
|
||||
.text-maroon {
|
||||
color: #5B7B89;
|
||||
color: #6B7280;
|
||||
}
|
||||
.border-maroon {
|
||||
border-color: #5B7B89;
|
||||
border-color: #6B7280;
|
||||
}
|
||||
.bg-cream {
|
||||
background-color: #F8FAFC;
|
||||
}
|
||||
.user-message {
|
||||
background-color: #5B7B89;
|
||||
background-color: #6B7280;
|
||||
color: white;
|
||||
border-radius: 12px 12px 0 12px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,13 +7,13 @@
|
|||
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||||
<style>
|
||||
.gradient-maroon {
|
||||
background: linear-gradient(135deg, #5B7B89 0%, #7B9BA5 100%);
|
||||
background: linear-gradient(135deg, #6B7280 0%, #8B95A5 100%);
|
||||
}
|
||||
.text-maroon {
|
||||
color: #5B7B89;
|
||||
color: #6B7280;
|
||||
}
|
||||
.border-maroon {
|
||||
border-color: #5B7B89;
|
||||
border-color: #6B7280;
|
||||
}
|
||||
.bg-cream {
|
||||
background-color: #F8FAFC;
|
||||
|
|
|
|||
|
|
@ -7,30 +7,30 @@
|
|||
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||||
<style>
|
||||
.gradient-maroon {
|
||||
background: linear-gradient(135deg, #5B7B89 0%, #7B9BA5 100%);
|
||||
background: linear-gradient(135deg, #6B7280 0%, #8B95A5 100%);
|
||||
}
|
||||
.text-maroon {
|
||||
color: #5B7B89;
|
||||
color: #6B7280;
|
||||
}
|
||||
.border-maroon {
|
||||
border-color: #5B7B89;
|
||||
border-color: #6B7280;
|
||||
}
|
||||
.bg-cream {
|
||||
background-color: #F8FAFC;
|
||||
}
|
||||
.btn-maroon {
|
||||
background: linear-gradient(135deg, #5B7B89 0%, #7B9BA5 100%);
|
||||
background: linear-gradient(135deg, #6B7280 0%, #8B95A5 100%);
|
||||
color: #fff;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.btn-maroon:hover {
|
||||
opacity: 0.9;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(91, 123, 137, 0.3);
|
||||
box-shadow: 0 4px 12px rgba(107, 114, 128, 0.3);
|
||||
}
|
||||
.input-focus:focus {
|
||||
border-color: #5B7B89;
|
||||
box-shadow: 0 0 0 3px rgba(91, 123, 137, 0.15);
|
||||
border-color: #6B7280;
|
||||
box-shadow: 0 0 0 3px rgba(107, 114, 128, 0.15);
|
||||
outline: none;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -55,193 +55,192 @@
|
|||
</header>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="container mx-auto px-4 sm:px-6 py-6 sm:py-12 max-w-5xl">
|
||||
<div class="container mx-auto px-4 sm:px-6 py-4 sm:py-8 max-w-7xl">
|
||||
|
||||
{{-- Success Message --}}
|
||||
@if (session('status') === 'profile-updated')
|
||||
<div class="bg-green-50 border border-green-300 text-green-800 rounded-lg p-4 mb-6 text-sm">
|
||||
<div class="bg-green-50 border border-green-300 text-green-800 rounded-lg p-3 mb-4 text-sm">
|
||||
✅ Profil berhasil diperbarui!
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- ========== PROFILE HEADER CARD - HORIZONTAL ========== --}}
|
||||
<div class="bg-gradient-to-r from-yellow-400 to-yellow-300 rounded-xl shadow-xl p-8 mb-8 text-gray-800">
|
||||
<div class="flex gap-8 items-center">
|
||||
<div class="bg-gradient-to-r from-yellow-400 to-yellow-300 rounded-xl shadow-xl p-6 mb-6 text-gray-800">
|
||||
<div class="flex gap-6 items-center">
|
||||
<!-- Avatar Section -->
|
||||
<div class="flex-shrink-0">
|
||||
@if($user->foto)
|
||||
<img src="{{ asset($user->foto) }}" alt="Foto Profil" class="w-40 h-40 rounded-2xl object-cover border-4 border-white shadow-lg" id="foto-preview-header">
|
||||
<img src="{{ asset($user->foto) }}" alt="Foto Profil" class="w-32 h-32 rounded-2xl object-cover border-4 border-white shadow-lg" id="foto-preview-header">
|
||||
@else
|
||||
<div class="w-40 h-40 rounded-2xl bg-white bg-opacity-30 flex items-center justify-center text-6xl font-bold text-gray-700" id="foto-placeholder-header">
|
||||
<div class="w-32 h-32 rounded-2xl bg-white bg-opacity-30 flex items-center justify-center text-5xl font-bold text-gray-700" id="foto-placeholder-header">
|
||||
{{ strtoupper(substr($user->name, 0, 1)) }}
|
||||
</div>
|
||||
<img src="#" alt="Foto Profil" class="w-40 h-40 rounded-2xl object-cover border-4 border-white shadow-lg hidden" id="foto-preview-header">
|
||||
<img src="#" alt="Foto Profil" class="w-32 h-32 rounded-2xl object-cover border-4 border-white shadow-lg hidden" id="foto-preview-header">
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Info Section -->
|
||||
<div class="flex-1">
|
||||
<h2 class="text-4xl font-bold mb-6">{{ $user->name }}</h2>
|
||||
<div class="grid grid-cols-2 gap-6">
|
||||
<h2 class="text-3xl font-bold mb-4">{{ $user->name }}</h2>
|
||||
<div class="grid grid-cols-4 gap-4 text-sm">
|
||||
<div>
|
||||
<p class="text-gray-700 text-sm font-semibold opacity-75">NIS</p>
|
||||
<p class="text-2xl font-bold text-gray-800">{{ $user->nis ?? '-' }}</p>
|
||||
<p class="text-gray-700 text-xs font-semibold opacity-75">NIS</p>
|
||||
<p class="text-lg font-bold text-gray-800">{{ $user->nis ?? '-' }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-gray-700 text-sm font-semibold opacity-75">Email</p>
|
||||
<p class="text-lg font-semibold text-gray-800 break-all">{{ $user->email }}</p>
|
||||
<p class="text-gray-700 text-xs font-semibold opacity-75">Email</p>
|
||||
<p class="text-sm font-semibold text-gray-800 break-words">{{ $user->email }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-gray-700 text-sm font-semibold opacity-75">Kelompok</p>
|
||||
<p class="text-gray-700 text-xs font-semibold opacity-75">Kelompok</p>
|
||||
@if($user->kelompok_asal)
|
||||
<span class="inline-block px-4 py-2 rounded-full text-sm font-bold text-white" style="background-color: {{ $user->kelompok_asal == 'IPA' ? '#0369A1' : '#B45309' }};">
|
||||
<span class="inline-block px-3 py-1 rounded-full text-xs font-bold text-white" style="background-color: {{ $user->kelompok_asal == 'IPA' ? '#0369A1' : '#B45309' }};">
|
||||
{{ $user->kelompok_asal }}
|
||||
</span>
|
||||
@else
|
||||
<p class="text-lg font-bold">-</p>
|
||||
<p class="text-sm font-bold">-</p>
|
||||
@endif
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-gray-700 text-sm font-semibold opacity-75">Terdaftar</p>
|
||||
<p class="text-lg font-semibold text-gray-800">{{ $user->created_at->format('d M Y') }}</p>
|
||||
<p class="text-gray-700 text-xs font-semibold opacity-75">Terdaftar</p>
|
||||
<p class="text-sm font-semibold text-gray-800">{{ $user->created_at->format('d M Y') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- ========== INFORMASI PROFIL ========== --}}
|
||||
<div class="bg-white rounded-lg shadow-lg p-6 sm:p-8 mb-6 border-l-4 border-blue-500">
|
||||
<h2 class="text-xl font-bold text-maroon mb-1">📝 Edit Informasi Profil</h2>
|
||||
<p class="text-sm text-gray-500 mb-6">Perbarui data diri dan foto profil Anda.</p>
|
||||
{{-- ========== FORMS CONTAINER - 2 KOLOM ========== --}}
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
|
||||
|
||||
<form method="POST" action="{{ route('profile.update') }}" enctype="multipart/form-data">
|
||||
@csrf
|
||||
@method('patch')
|
||||
{{-- ========== INFORMASI PROFIL ========== --}}
|
||||
<div class="bg-white rounded-lg shadow-lg p-5 border-l-4 border-blue-500">
|
||||
<h2 class="text-lg font-bold text-maroon mb-1">📝 Edit Profil</h2>
|
||||
<p class="text-xs text-gray-500 mb-4">Perbarui data diri Anda.</p>
|
||||
|
||||
{{-- Foto Profil Upload --}}
|
||||
<div class="mb-6">
|
||||
<label class="block text-sm font-semibold text-maroon mb-3">🖼️ Foto Profil Baru</label>
|
||||
<div class="flex items-center gap-6">
|
||||
<div>
|
||||
<input type="file" name="foto" id="foto" accept="image/*" class="text-sm text-gray-600 file:mr-3 file:py-2 file:px-4 file:rounded-lg file:border-0 file:text-sm file:font-semibold file:bg-yellow-100 file:text-yellow-800 hover:file:bg-yellow-200" onchange="previewFoto(this)">
|
||||
<p class="text-xs text-gray-400 mt-2">Format: JPG, PNG, GIF. Maks 2MB.</p>
|
||||
</div>
|
||||
</div>
|
||||
@error('foto')
|
||||
<p class="text-red-600 text-xs mt-1">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
<form method="POST" action="{{ route('profile.update') }}" enctype="multipart/form-data">
|
||||
@csrf
|
||||
@method('patch')
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{{-- Nama --}}
|
||||
<div>
|
||||
<label for="name" class="block text-sm font-semibold text-maroon mb-2">Nama Lengkap</label>
|
||||
<input type="text" id="name" name="name" value="{{ old('name', $user->name) }}" required
|
||||
class="input-focus w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-0">
|
||||
@error('name')
|
||||
{{-- Foto Profil Upload --}}
|
||||
<div class="mb-4">
|
||||
<label class="block text-xs font-semibold text-maroon mb-2">🖼️ Foto Profil</label>
|
||||
<input type="file" name="foto" id="foto" accept="image/*" class="text-xs text-gray-600 file:mr-2 file:py-1 file:px-2 file:rounded file:border-0 file:text-xs file:font-semibold file:bg-yellow-100 file:text-yellow-800 hover:file:bg-yellow-200 w-full" onchange="previewFoto(this)">
|
||||
<p class="text-xs text-gray-400 mt-1">JPG, PNG, GIF. Maks 2MB.</p>
|
||||
@error('foto')
|
||||
<p class="text-red-600 text-xs mt-1">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
{{-- Nama --}}
|
||||
<div class="col-span-2">
|
||||
<label for="name" class="block text-xs font-semibold text-maroon mb-1">Nama Lengkap</label>
|
||||
<input type="text" id="name" name="name" value="{{ old('name', $user->name) }}" required
|
||||
class="input-focus w-full border border-gray-300 rounded px-2 py-1 text-xs focus:ring-0">
|
||||
@error('name')
|
||||
<p class="text-red-600 text-xs mt-0.5">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
{{-- Email --}}
|
||||
<div>
|
||||
<label for="email" class="block text-sm font-semibold text-maroon mb-2">Email</label>
|
||||
<div class="col-span-2">
|
||||
<label for="email" class="block text-xs font-semibold text-maroon mb-1">Email</label>
|
||||
<input type="email" id="email" name="email" value="{{ old('email', $user->email) }}" required
|
||||
class="input-focus w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-0">
|
||||
class="input-focus w-full border border-gray-300 rounded px-2 py-1 text-xs focus:ring-0">
|
||||
@error('email')
|
||||
<p class="text-red-600 text-xs mt-1">{{ $message }}</p>
|
||||
<p class="text-red-600 text-xs mt-0.5">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
{{-- NIS --}}
|
||||
<div>
|
||||
<label for="nis" class="block text-sm font-semibold text-maroon mb-2">NIS (Nomor Induk Siswa)</label>
|
||||
<label for="nis" class="block text-xs font-semibold text-maroon mb-1">NIS</label>
|
||||
<input type="text" id="nis" name="nis" value="{{ old('nis', $user->nis) }}" maxlength="20"
|
||||
class="input-focus w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-0" placeholder="Contoh: 123456">
|
||||
class="input-focus w-full border border-gray-300 rounded px-2 py-1 text-xs focus:ring-0" placeholder="12345678">
|
||||
@error('nis')
|
||||
<p class="text-red-600 text-xs mt-1">{{ $message }}</p>
|
||||
<p class="text-red-600 text-xs mt-0.5">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
{{-- Kelompok Asal --}}
|
||||
<div>
|
||||
<label for="kelompok_asal" class="block text-sm font-semibold text-maroon mb-2">Kelompok Asal</label>
|
||||
<label for="kelompok_asal" class="block text-xs font-semibold text-maroon mb-1">Kelompok</label>
|
||||
<select id="kelompok_asal" name="kelompok_asal"
|
||||
class="input-focus w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-0 bg-white">
|
||||
<option value="">-- Pilih Kelompok --</option>
|
||||
class="input-focus w-full border border-gray-300 rounded px-2 py-1 text-xs focus:ring-0 bg-white">
|
||||
<option value="">Pilih</option>
|
||||
<option value="IPA" {{ old('kelompok_asal', $user->kelompok_asal) === 'IPA' ? 'selected' : '' }}>IPA</option>
|
||||
<option value="IPS" {{ old('kelompok_asal', $user->kelompok_asal) === 'IPS' ? 'selected' : '' }}>IPS</option>
|
||||
</select>
|
||||
@error('kelompok_asal')
|
||||
<p class="text-red-600 text-xs mt-1">{{ $message }}</p>
|
||||
<p class="text-red-600 text-xs mt-0.5">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn-maroon font-bold py-2 px-8 rounded-lg text-sm mt-6">
|
||||
💾 Simpan Perubahan
|
||||
<button type="submit" class="btn-maroon font-bold py-2 px-6 rounded text-xs mt-4 w-full">
|
||||
💾 Simpan
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{{-- ========== UBAH PASSWORD ========== --}}
|
||||
<div class="bg-white rounded-lg shadow-lg p-6 sm:p-8 mb-6 border-l-4 border-green-500">
|
||||
<h2 class="text-xl font-bold text-maroon mb-1">🔐 Ubah Password</h2>
|
||||
<p class="text-sm text-gray-500 mb-6">Pastikan akun Anda menggunakan password yang kuat dan aman.</p>
|
||||
{{-- ========== UBAH PASSWORD ========== --}}
|
||||
<div class="bg-white rounded-lg shadow-lg p-5 border-l-4 border-green-500">
|
||||
<h2 class="text-lg font-bold text-maroon mb-1">🔐 Ubah Password</h2>
|
||||
<p class="text-xs text-gray-500 mb-4">Gunakan password yang kuat dan aman.</p>
|
||||
|
||||
@if (session('status') === 'password-updated')
|
||||
<div class="bg-green-50 border border-green-300 text-green-800 rounded-lg p-4 mb-4 text-sm">
|
||||
✅ Password berhasil diubah!
|
||||
</div>
|
||||
@endif
|
||||
@if (session('status') === 'password-updated')
|
||||
<div class="bg-green-50 border border-green-300 text-green-800 rounded-lg p-3 mb-3 text-xs">
|
||||
✅ Password berhasil diubah!
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form method="POST" action="{{ route('password.update') }}">
|
||||
@csrf
|
||||
@method('put')
|
||||
<form method="POST" action="{{ route('password.update') }}">
|
||||
@csrf
|
||||
@method('put')
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div class="grid grid-cols-1 gap-3">
|
||||
<div>
|
||||
<label for="current_password" class="block text-sm font-semibold text-maroon mb-2">Password Saat Ini</label>
|
||||
<label for="current_password" class="block text-xs font-semibold text-maroon mb-1">Password Saat Ini</label>
|
||||
<div style="position: relative; display: flex; align-items: center;">
|
||||
<input type="password" id="current_password" name="current_password"
|
||||
class="input-focus w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-0" style="padding-right: 45px;">
|
||||
<button type="button" style="position: absolute; right: 12px; background: none; border: none; cursor: pointer; color: #5B7B89; font-size: 18px;" onclick="togglePasswordVisibility('current_password', this)">👁️</button>
|
||||
class="input-focus w-full border border-gray-300 rounded px-2 py-1 text-xs focus:ring-0" style="padding-right: 30px;">
|
||||
<button type="button" style="position: absolute; right: 6px; background: none; border: none; cursor: pointer; color: #5B7B89; font-size: 14px;" onclick="togglePasswordVisibility('current_password', this)">👁️</button>
|
||||
</div>
|
||||
@error('current_password', 'updatePassword')
|
||||
<p class="text-red-600 text-xs mt-1">{{ $message }}</p>
|
||||
<p class="text-red-600 text-xs mt-0.5">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="password" class="block text-sm font-semibold text-maroon mb-2">Password Baru</label>
|
||||
<label for="password" class="block text-xs font-semibold text-maroon mb-1">Password Baru</label>
|
||||
<div style="position: relative; display: flex; align-items: center;">
|
||||
<input type="password" id="password" name="password"
|
||||
class="input-focus w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-0" style="padding-right: 45px;">
|
||||
<button type="button" style="position: absolute; right: 12px; background: none; border: none; cursor: pointer; color: #5B7B89; font-size: 18px;" onclick="togglePasswordVisibility('password', this)">👁️</button>
|
||||
class="input-focus w-full border border-gray-300 rounded px-2 py-1 text-xs focus:ring-0" style="padding-right: 30px;">
|
||||
<button type="button" style="position: absolute; right: 6px; background: none; border: none; cursor: pointer; color: #5B7B89; font-size: 14px;" onclick="togglePasswordVisibility('password', this)">👁️</button>
|
||||
</div>
|
||||
@error('password', 'updatePassword')
|
||||
<p class="text-red-600 text-xs mt-1">{{ $message }}</p>
|
||||
<p class="text-red-600 text-xs mt-0.5">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div class="md:col-span-2">
|
||||
<label for="password_confirmation" class="block text-sm font-semibold text-maroon mb-2">Konfirmasi Password Baru</label>
|
||||
<div>
|
||||
<label for="password_confirmation" class="block text-xs font-semibold text-maroon mb-1">Konfirmasi Password</label>
|
||||
<div style="position: relative; display: flex; align-items: center;">
|
||||
<input type="password" id="password_confirmation" name="password_confirmation"
|
||||
class="input-focus w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-0" style="padding-right: 45px;">
|
||||
<button type="button" style="position: absolute; right: 12px; background: none; border: none; cursor: pointer; color: #5B7B89; font-size: 18px;" onclick="togglePasswordVisibility('password_confirmation', this)">👁️</button>
|
||||
class="input-focus w-full border border-gray-300 rounded px-2 py-1 text-xs focus:ring-0" style="padding-right: 30px;">
|
||||
<button type="button" style="position: absolute; right: 6px; background: none; border: none; cursor: pointer; color: #5B7B89; font-size: 14px;" onclick="togglePasswordVisibility('password_confirmation', this)">👁️</button>
|
||||
</div>
|
||||
@error('password_confirmation', 'updatePassword')
|
||||
<p class="text-red-600 text-xs mt-1">{{ $message }}</p>
|
||||
<p class="text-red-600 text-xs mt-0.5">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="bg-green-600 hover:bg-green-700 text-white font-bold py-2 px-8 rounded-lg text-sm transition mt-6">
|
||||
✓ Ubah Password
|
||||
</button>
|
||||
</form>
|
||||
<button type="submit" class="bg-green-600 hover:bg-green-700 text-white font-bold py-2 px-6 rounded text-xs transition mt-4 w-full">
|
||||
✓ Ubah Password
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -7,19 +7,19 @@
|
|||
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||||
<style>
|
||||
.gradient-maroon {
|
||||
background: linear-gradient(135deg, #5B7B89 0%, #7B9BA5 100%);
|
||||
background: linear-gradient(135deg, #6B7280 0%, #8B95A5 100%);
|
||||
}
|
||||
.text-maroon {
|
||||
color: #5B7B89;
|
||||
color: #6B7280;
|
||||
}
|
||||
.border-maroon {
|
||||
border-color: #5B7B89;
|
||||
border-color: #6B7280;
|
||||
}
|
||||
.bg-cream {
|
||||
background-color: #F8FAFC;
|
||||
}
|
||||
.bg-maroon-light {
|
||||
background-color: rgba(91, 123, 137, 0.1);
|
||||
background-color: rgba(107, 114, 128, 0.1);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
|
@ -40,33 +40,42 @@
|
|||
</header>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="container mx-auto px-4 sm:px-6 py-6 sm:py-12">
|
||||
<!-- Info Box -->
|
||||
<div class="bg-white border-2 border-maroon rounded-lg p-4 sm:p-6 mb-6 sm:mb-8 shadow-md">
|
||||
<h2 class="text-lg sm:text-xl font-bold text-maroon mb-2 sm:mb-3">Hasil Analisis</h2>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">
|
||||
Berikut adalah hasil analisis sistem terhadap profil Anda. Jurusan diurutkan berdasarkan skor kesesuaian dari yang tertinggi.
|
||||
</p>
|
||||
<div class="w-full px-4 sm:px-6 py-6 sm:py-8">
|
||||
<!-- Selamat Section -->
|
||||
<div class="bg-gradient-to-r from-green-600 to-emerald-600 rounded-xl shadow-lg p-8 text-white mb-8">
|
||||
<div class="flex gap-4 items-start">
|
||||
<div class="text-5xl">🎉</div>
|
||||
<div>
|
||||
<h2 class="text-3xl font-bold mb-2">Hasil Analisis Siap!</h2>
|
||||
<p class="text-lg text-green-100 mb-4">
|
||||
Sistem AI kami telah menganalisis profil kamu secara menyeluruh. Berikut adalah 9 program studi yang kami rekomendasikan, diurutkan dari yang paling sesuai dengan potensi dan minat kamu. Setiap jurusan memiliki skor kesesuaian yang menunjukkan tingkat kecocokan dengan profil kamu.
|
||||
</p>
|
||||
<div class="inline-block bg-white bg-opacity-20 rounded-lg px-4 py-2 backdrop-blur-sm">
|
||||
<p class="text-sm font-semibold">💡 Tip: Cek beberapa program teratas dan diskusikan dengan konselor atau orang tua untuk memastikan pilihan terbaik untuk masa depanmu</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ringkasan Input -->
|
||||
<div class="bg-white rounded-lg shadow-lg p-5 sm:p-6 mb-6 sm:mb-8 border-l-4 border-maroon">
|
||||
<h3 class="text-base sm:text-lg font-bold text-maroon mb-3 sm:mb-4">Data Profil Anda</h3>
|
||||
<div class="grid grid-cols-2 md:grid-cols-2 lg:grid-cols-4 gap-2 sm:gap-4">
|
||||
<div class="bg-maroon-light p-3 sm:p-4 rounded-lg">
|
||||
<p class="text-xs sm:text-sm text-gray-600">Nilai Akademik</p>
|
||||
<p class="text-lg sm:text-xl font-bold text-maroon">{{ $katNilai }}</p>
|
||||
<p class="text-xs text-gray-500">Rata-rata: {{ number_format($average, 1) }}</p>
|
||||
<div class="bg-white rounded-xl shadow-lg p-8 mb-8 border-t-4 border-purple-600">
|
||||
<h3 class="text-2xl font-bold text-gray-900 mb-6">📊 Profil Analisismu</h3>
|
||||
<div class="grid grid-cols-2 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<div class="bg-gradient-to-br from-purple-50 to-purple-100 p-5 rounded-lg border border-purple-200">
|
||||
<p class="text-xs font-semibold text-purple-600 mb-2">📚 Nilai Akademik</p>
|
||||
<p class="text-2xl font-bold text-purple-900">{{ number_format($average, 1) }}</p>
|
||||
<p class="text-xs text-purple-700 mt-1">Rata-rata Rapor</p>
|
||||
</div>
|
||||
<div class="bg-yellow-50 p-3 sm:p-4 rounded-lg">
|
||||
<p class="text-xs sm:text-sm text-gray-600">Preferensi Studi</p>
|
||||
<p class="text-sm sm:text-lg font-bold text-maroon">{{ $prefStudi ?? '-' }}</p>
|
||||
<div class="bg-gradient-to-br from-blue-50 to-blue-100 p-5 rounded-lg border border-blue-200">
|
||||
<p class="text-xs font-semibold text-blue-600 mb-2">🎯 Preferensi Studi</p>
|
||||
<p class="text-lg font-bold text-blue-900">{{ $prefStudi ?? '-' }}</p>
|
||||
<p class="text-xs text-blue-700 mt-1">Gaya Belajar</p>
|
||||
</div>
|
||||
<div class="bg-maroon-light p-3 sm:p-4 rounded-lg">
|
||||
<p class="text-xs sm:text-sm text-gray-600">Prestasi</p>
|
||||
<p class="text-sm sm:text-lg font-bold text-maroon">
|
||||
<div class="bg-gradient-to-br from-amber-50 to-amber-100 p-5 rounded-lg border border-amber-200">
|
||||
<p class="text-xs font-semibold text-amber-600 mb-2">🏆 Prestasi</p>
|
||||
<p class="text-lg font-bold text-amber-900">
|
||||
@if(!($isPrestasiFilled ?? true))
|
||||
Tidak Dihitung
|
||||
Belum Ada
|
||||
@elseif($prestasiScore >= 0.8)
|
||||
Tinggi
|
||||
@elseif($prestasiScore >= 0.6)
|
||||
|
|
@ -77,18 +86,22 @@
|
|||
Belum Ada
|
||||
@endif
|
||||
</p>
|
||||
<p class="text-xs text-amber-700 mt-1">Pencapaian</p>
|
||||
</div>
|
||||
<div class="bg-yellow-50 p-3 sm:p-4 rounded-lg">
|
||||
<p class="text-xs sm:text-sm text-gray-600">Skor Nilai</p>
|
||||
<p class="text-sm sm:text-lg font-bold text-maroon">{{ number_format($average, 1) }}%</p>
|
||||
<div class="bg-gradient-to-br from-green-50 to-green-100 p-5 rounded-lg border border-green-200">
|
||||
<p class="text-xs font-semibold text-green-600 mb-2">💯 Skor Nilai</p>
|
||||
<p class="text-2xl font-bold text-green-900">{{ number_format($average, 1) }}%</p>
|
||||
<p class="text-xs text-green-700 mt-1">Nilai Rata-rata</p>
|
||||
</div>
|
||||
<div class="bg-maroon-light p-3 sm:p-4 rounded-lg">
|
||||
</div>
|
||||
<p class="text-xs sm:text-sm text-gray-600">Minat</p>
|
||||
<p class="text-sm sm:text-lg font-bold text-maroon">{{ $minatMapped ?? '-' }}</p>
|
||||
<p class="text-xs text-gray-500 mt-1">Input: {{ ucfirst($minatRaw ?? '-') }}</p>
|
||||
</div>
|
||||
<div class="bg-yellow-50 p-3 sm:p-4 rounded-lg">
|
||||
<p class="text-xs sm:text-sm text-gray-600">Cita-cita</p>
|
||||
<p class="text-sm sm:text-lg font-bold text-maroon">{{ $citaMapped ?? '-' }}</p>
|
||||
<p class="text-xs text-gray-500 mt-1">Input: {{ ucfirst($citaRaw ?? '-') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -175,7 +188,7 @@
|
|||
<div class="space-y-2 sm:space-y-3">
|
||||
<div>
|
||||
<div class="flex justify-between items-center mb-1">
|
||||
<p class="text-xs sm:text-sm font-semibold text-gray-700">Nilai Akademik — P(nilai|H) × w=0.40</p>
|
||||
<p class="text-xs sm:text-sm font-semibold text-gray-700">Nilai Akademik — P(nilai|H) × w=0.156</p>
|
||||
<span class="text-xs sm:text-sm font-bold text-maroon">{{ number_format(($detail['nilai'] ?? 0) * 100, 1) }}%</span>
|
||||
</div>
|
||||
<div class="w-full bg-gray-300 rounded-full h-2">
|
||||
|
|
@ -185,7 +198,7 @@
|
|||
|
||||
<div>
|
||||
<div class="flex justify-between items-center mb-1">
|
||||
<p class="text-xs sm:text-sm font-semibold text-gray-700">Minat & Bakat — P(minat|H) × w=0.35</p>
|
||||
<p class="text-xs sm:text-sm font-semibold text-gray-700">Minat & Bakat — P(minat|H) × w=0.456</p>
|
||||
<span class="text-xs sm:text-sm font-bold text-maroon">{{ number_format(($detail['minat'] ?? 0) * 100, 1) }}%</span>
|
||||
</div>
|
||||
<div class="w-full bg-gray-300 rounded-full h-2">
|
||||
|
|
@ -195,7 +208,7 @@
|
|||
|
||||
<div>
|
||||
<div class="flex justify-between items-center mb-1">
|
||||
<p class="text-xs sm:text-sm font-semibold text-gray-700">Preferensi Studi — P(pref|H) × w=0.15</p>
|
||||
<p class="text-xs sm:text-sm font-semibold text-gray-700">Preferensi Studi — P(pref|H) × w=0.256</p>
|
||||
<span class="text-xs sm:text-sm font-bold text-maroon">{{ number_format(($detail['pref'] ?? 0) * 100, 1) }}%</span>
|
||||
</div>
|
||||
<div class="w-full bg-gray-300 rounded-full h-2">
|
||||
|
|
@ -205,7 +218,7 @@
|
|||
|
||||
<div>
|
||||
<div class="flex justify-between items-center mb-1">
|
||||
<p class="text-xs sm:text-sm font-semibold text-gray-700">Cita-cita — P(cita|H) × w=0.05</p>
|
||||
<p class="text-xs sm:text-sm font-semibold text-gray-700">Cita-cita — P(cita|H) × w=0.090</p>
|
||||
<span class="text-xs sm:text-sm font-bold text-maroon">
|
||||
{{ number_format(($detail['cita'] ?? 0) * 100, 1) }}%
|
||||
</span>
|
||||
|
|
@ -218,7 +231,7 @@
|
|||
<div>
|
||||
<div class="flex justify-between items-center mb-1">
|
||||
<p class="text-xs sm:text-sm font-semibold text-gray-700">
|
||||
Prestasi — P(prestasi|H) × w={{ ($isPrestasiFilled ?? true) ? '0.05' : '0.00' }}
|
||||
Prestasi — P(prestasi|H) × w={{ ($isPrestasiFilled ?? true) ? '0.040' : '0.00' }}
|
||||
</p>
|
||||
<span class="text-xs sm:text-sm font-bold text-maroon">
|
||||
@if(!($isPrestasiFilled ?? true))
|
||||
|
|
@ -326,7 +339,7 @@
|
|||
<p class="text-xs sm:text-sm font-bold text-gray-700 mb-3">Scoring per Kriteria:</p>
|
||||
<div class="space-y-2">
|
||||
<div class="flex justify-between items-center text-xs">
|
||||
<span class="text-gray-600">📊 Nilai (40%)</span>
|
||||
<span class="text-gray-600">📊 Nilai (15.6%)</span>
|
||||
<span class="font-semibold text-maroon">{{ number_format(($rec['detail']['nilai'] ?? 0) * 100, 1) }}%</span>
|
||||
</div>
|
||||
<div class="w-full bg-gray-200 rounded h-1.5">
|
||||
|
|
@ -334,7 +347,7 @@
|
|||
</div>
|
||||
|
||||
<div class="flex justify-between items-center text-xs mt-2">
|
||||
<span class="text-gray-600">❤️ Minat (35%)</span>
|
||||
<span class="text-gray-600">❤️ Minat (45.6%)</span>
|
||||
<span class="font-semibold text-maroon">{{ number_format(($rec['detail']['minat'] ?? 0) * 100, 1) }}%</span>
|
||||
</div>
|
||||
<div class="w-full bg-gray-200 rounded h-1.5">
|
||||
|
|
@ -342,7 +355,7 @@
|
|||
</div>
|
||||
|
||||
<div class="flex justify-between items-center text-xs mt-2">
|
||||
<span class="text-gray-600">🎓 Preferensi (15%)</span>
|
||||
<span class="text-gray-600">🎓 Preferensi (25.6%)</span>
|
||||
<span class="font-semibold text-maroon">{{ number_format(($rec['detail']['pref'] ?? 0) * 100, 1) }}%</span>
|
||||
</div>
|
||||
<div class="w-full bg-gray-200 rounded h-1.5">
|
||||
|
|
@ -425,7 +438,7 @@
|
|||
Ingin tahu mengapa jurusan <strong>{{ $hasilAkhir[0]['jurusan'] ?? '' }}</strong> direkomendasikan?
|
||||
Konsultasikan dengan AI Konselor BK Virtual untuk penjelasan detail berdasarkan profil Anda.
|
||||
</p>
|
||||
<a href="{{ route('chatbot.index', ['rec' => session('last_recommendation_id')]) }}" class="inline-block gradient-maroon text-white font-bold py-2 sm:py-3 px-4 sm:px-6 rounded-lg hover:opacity-90 transition duration-200 text-sm sm:text-base">
|
||||
<a href="{{ route('chatbot.index', ['rec' => $recommendationId]) }}" class="inline-block gradient-maroon text-white font-bold py-2 sm:py-3 px-4 sm:px-6 rounded-lg hover:opacity-90 transition duration-200 text-sm sm:text-base">
|
||||
💬 Tanya AI: "Mengapa jurusan ini cocok untukku?"
|
||||
</a>
|
||||
</div>
|
||||
|
|
@ -445,7 +458,7 @@
|
|||
<!-- Info Metode -->
|
||||
<div class="mt-6 sm:mt-8 p-3 sm:p-4 bg-white rounded-lg border border-gray-200 shadow-sm">
|
||||
<p class="text-xs sm:text-sm text-gray-600">
|
||||
<strong>Metode:</strong> Sistem menggunakan algoritma Weighted Naive Bayes dengan 4 fitur berbobot: Nilai Akademik (w=0.40), Minat (w=0.35), Cita-cita (w=0.15), Prestasi (w=0.10). Jika prestasi tidak diisi, atribut prestasi tidak dihitung (w=0.00) dan bobot atribut lain dinormalisasi. Rumus: P(H|X) ∝ P(H) × ∏ P(Xi|H)<sup>wi</sup>, kemudian dinormalisasi menggunakan softmax.
|
||||
<strong>Metode:</strong> Sistem menggunakan algoritma Weighted Naive Bayes dengan 5 fitur berbobot: Nilai Akademik (w=0.156), Minat (w=0.456), Preferensi Studi (w=0.256), Cita-cita (w=0.090), Prestasi (w=0.040). Jika prestasi tidak diisi, atribut prestasi tidak dihitung (w=0.00) dan bobot atribut lain dinormalisasi. Rumus: P(H|X) ∝ P(H) × ∏ P(Xi|H)<sup>wi</sup>, kemudian dinormalisasi menggunakan softmax.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,20 +7,20 @@
|
|||
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||||
<style>
|
||||
.gradient-maroon {
|
||||
background: linear-gradient(135deg, #5B7B89 0%, #7B9BA5 100%);
|
||||
background: linear-gradient(135deg, #6B7280 0%, #8B95A5 100%);
|
||||
}
|
||||
.text-maroon {
|
||||
color: #5B7B89;
|
||||
color: #6B7280;
|
||||
}
|
||||
.border-maroon {
|
||||
border-color: #5B7B89;
|
||||
border-color: #6B7280;
|
||||
}
|
||||
.bg-cream {
|
||||
background-color: #F8FAFC;
|
||||
}
|
||||
.focus-maroon:focus {
|
||||
border-color: #5B7B89;
|
||||
box-shadow: 0 0 0 3px rgba(91, 123, 137, 0.1);
|
||||
border-color: #6B7280;
|
||||
box-shadow: 0 0 0 3px rgba(107, 114, 128, 0.1);
|
||||
}
|
||||
.input-error {
|
||||
border-color: #ef4444 !important;
|
||||
|
|
@ -77,30 +77,47 @@
|
|||
</header>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="container mx-auto px-4 sm:px-6 py-6 sm:py-12">
|
||||
<!-- Info Box -->
|
||||
<div class="bg-white border-2 border-maroon rounded-lg p-4 sm:p-6 mb-6 sm:mb-8 shadow-md">
|
||||
<h2 class="text-lg sm:text-xl font-bold text-maroon mb-2 sm:mb-3">Petunjuk Pengisian</h2>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700 mb-2">
|
||||
Silakan isi data berikut dengan jujur agar sistem dapat memberikan rekomendasi yang akurat.
|
||||
<div class="w-full px-4 sm:px-6 py-6 sm:py-8">
|
||||
<!-- Hero Intro -->
|
||||
<div class="bg-gradient-to-r from-blue-600 to-purple-600 rounded-xl shadow-lg p-8 sm:p-10 mb-8 text-white">
|
||||
<h2 class="text-3xl sm:text-4xl font-bold mb-3 sm:mb-4">Kuis Cerdas Menemukan Jurusanmu 🚀</h2>
|
||||
<p class="text-base sm:text-lg text-blue-100 mb-4 sm:mb-6 leading-relaxed">
|
||||
Kami akan mengajukan beberapa pertanyaan untuk mengenal lebih dalam tentang profil akademis, minat, gaya belajar, prestasi, dan impian karirmu. Jawab dengan jujur dan sedetail mungkin - informasi ini akan membantu sistem AI kami memberikan rekomendasi yang paling akurat untuk masa depan gemilangmu.
|
||||
</p>
|
||||
<p class="text-xs sm:text-sm text-gray-600 mb-2">
|
||||
Perhitungan menggunakan algoritma <strong>Naive Bayes berbobot</strong> berdasarkan 5 atribut input: <strong>nilai akademik (40%)</strong>, <strong>minat (35%)</strong>, <strong>preferensi studi lanjutan (15%)</strong>, <strong>cita-cita (5%)</strong>, dan <strong>prestasi (5%)</strong>.
|
||||
</p>
|
||||
<p class="text-xs sm:text-sm text-gray-600">
|
||||
Sistem akan menganalisis data Anda dan menampilkan ranking <strong>9 jurusan</strong> yang tersedia di Politeknik Negeri Jember.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Form Card -->
|
||||
<div class="bg-white rounded-lg shadow-lg p-5 sm:p-8 border-l-4 border-maroon">
|
||||
<div class="flex flex-col sm:flex-row items-start sm:items-center gap-3 sm:gap-4 mb-4 sm:mb-6">
|
||||
<div class="w-12 h-12 sm:w-14 sm:h-14 rounded-lg bg-yellow-100 flex items-center justify-center text-2xl flex-shrink-0">📝</div>
|
||||
<div>
|
||||
<h2 class="text-lg sm:text-xl md:text-2xl font-bold text-maroon">Formulir Data Profil</h2>
|
||||
<p class="text-xs sm:text-sm text-gray-600">Jawab pertanyaan berikut untuk mendapatkan rekomendasi jurusan.</p>
|
||||
<div class="grid grid-cols-3 gap-4 mt-6">
|
||||
<div class="bg-white bg-opacity-20 rounded-lg p-4 backdrop-blur-sm text-center">
|
||||
<p class="text-3xl font-bold">⏱️</p>
|
||||
<p class="text-sm text-blue-100 mt-1">3-5 Menit</p>
|
||||
</div>
|
||||
<div class="bg-white bg-opacity-20 rounded-lg p-4 backdrop-blur-sm text-center">
|
||||
<p class="text-3xl font-bold">✅</p>
|
||||
<p class="text-sm text-blue-100 mt-1">Mudah & Cepat</p>
|
||||
</div>
|
||||
<div class="bg-white bg-opacity-20 rounded-lg p-4 backdrop-blur-sm text-center">
|
||||
<p class="text-3xl font-bold">🎯</p>
|
||||
<p class="text-sm text-blue-100 mt-1">Hasil Akurat</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tips Card -->
|
||||
<div class="bg-amber-50 border-l-4 border-amber-400 rounded-lg p-6 sm:p-8 mb-8 shadow-sm">
|
||||
<div class="flex gap-4">
|
||||
<div class="text-3xl flex-shrink-0">💡</div>
|
||||
<div>
|
||||
<h3 class="font-bold text-amber-900 mb-3 text-lg">Tips Agar Hasil Lebih Akurat</h3>
|
||||
<ul class="text-sm text-amber-800 space-y-2">
|
||||
<li>✓ Jawab semua pertanyaan dengan jujur dan sebenar-benarnya</li>
|
||||
<li>✓ Jangan terburu-buru - pikirkan jawaban dengan matang</li>
|
||||
<li>✓ Nilai yang kamu masukkan sebaiknya merupakan rata-rata atau nilai terbaik dari rapor</li>
|
||||
<li>✓ Pilih opsi yang benar-benar mewakili minat dan preferensi kamu</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Form Card -->
|
||||
<div class="bg-white rounded-xl shadow-lg p-8 sm:p-10 border-t-4 border-purple-600">
|
||||
|
||||
@if ($errors->any())
|
||||
<div class="bg-red-50 border-l-4 border-red-500 p-4 sm:p-5 rounded-lg mb-6 shadow-md animate-pulse">
|
||||
|
|
@ -125,9 +142,9 @@
|
|||
{{-- ============================================ --}}
|
||||
{{-- KRITERIA 1: NILAI MATA PELAJARAN --}}
|
||||
{{-- ============================================ --}}
|
||||
<div class="p-4 sm:p-5 rounded-lg border-2 border-gray-200 bg-gray-50">
|
||||
<h3 class="font-bold text-maroon text-base sm:text-lg mb-1 sm:mb-2">1. Nilai Mata Pelajaran <span class="text-red-500">*</span></h3>
|
||||
<p class="text-xs text-gray-600 mb-3 sm:mb-4">
|
||||
<div class="p-6 rounded-lg border-2 border-gray-200 bg-gray-50">
|
||||
<h3 class="font-bold text-lg sm:text-xl text-purple-700 mb-2">1️⃣ Nilai Mata Pelajaran <span class="text-red-500">*</span></h3>
|
||||
<p class="text-sm text-gray-600 mb-4">
|
||||
@if(isset($student) && $student->kelompok_asal == 'IPA')
|
||||
Siswa <strong>IPA</strong> — Masukkan nilai rapor (0-100): <strong>Matematika, Fisika, Kimia, Biologi</strong>.
|
||||
@else
|
||||
|
|
@ -137,35 +154,35 @@
|
|||
|
||||
@if(isset($student) && $student->kelompok_asal == 'IPA')
|
||||
{{-- SISWA IPA: Matematika, Fisika, Kimia, Biologi --}}
|
||||
<div class="grid grid-cols-2 lg:grid-cols-4 gap-2 sm:gap-3">
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<div class="input-wrapper">
|
||||
<label for="mtk" class="block text-xs sm:text-sm font-semibold text-gray-700 mb-1">Matematika <span class="text-red-500">*</span></label>
|
||||
<label for="mtk" class="block text-sm font-semibold text-gray-700 mb-2">Matematika <span class="text-red-500">*</span></label>
|
||||
<input id="mtk" type="number" name="mtk" min="0" max="100" value="{{ old('mtk') }}" placeholder="Nilai: 85" required
|
||||
class="block w-full px-3 sm:px-4 py-2 border border-gray-300 rounded-lg focus-maroon focus:outline-none text-sm transition-colors @error('mtk') input-error @enderror">
|
||||
class="block w-full px-4 py-2 border border-gray-300 rounded-lg focus-maroon focus:outline-none text-sm transition-colors @error('mtk') input-error @enderror">
|
||||
@error('mtk')
|
||||
<span class="validation-message text-red-600">⚠️ {{ $message }}</span>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="input-wrapper">
|
||||
<label for="fisika" class="block text-xs sm:text-sm font-semibold text-gray-700 mb-1">Fisika <span class="text-red-500">*</span></label>
|
||||
<label for="fisika" class="block text-sm font-semibold text-gray-700 mb-2">Fisika <span class="text-red-500">*</span></label>
|
||||
<input id="fisika" type="number" name="fisika" min="0" max="100" value="{{ old('fisika') }}" placeholder="Nilai: 78" required
|
||||
class="block w-full px-3 sm:px-4 py-2 border border-gray-300 rounded-lg focus-maroon focus:outline-none text-sm transition-colors @error('fisika') input-error @enderror">
|
||||
class="block w-full px-4 py-2 border border-gray-300 rounded-lg focus-maroon focus:outline-none text-sm transition-colors @error('fisika') input-error @enderror">
|
||||
@error('fisika')
|
||||
<span class="validation-message text-red-600">⚠️ {{ $message }}</span>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="input-wrapper">
|
||||
<label for="kimia" class="block text-xs sm:text-sm font-semibold text-gray-700 mb-1">Kimia <span class="text-red-500">*</span></label>
|
||||
<label for="kimia" class="block text-sm font-semibold text-gray-700 mb-2">Kimia <span class="text-red-500">*</span></label>
|
||||
<input id="kimia" type="number" name="kimia" min="0" max="100" value="{{ old('kimia') }}" placeholder="Nilai: 72" required
|
||||
class="block w-full px-3 sm:px-4 py-2 border border-gray-300 rounded-lg focus-maroon focus:outline-none text-sm transition-colors @error('kimia') input-error @enderror">
|
||||
class="block w-full px-4 py-2 border border-gray-300 rounded-lg focus-maroon focus:outline-none text-sm transition-colors @error('kimia') input-error @enderror">
|
||||
@error('kimia')
|
||||
<span class="validation-message text-red-600">⚠️ {{ $message }}</span>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="input-wrapper">
|
||||
<label for="biologi" class="block text-xs sm:text-sm font-semibold text-gray-700 mb-1">Biologi <span class="text-red-500">*</span></label>
|
||||
<label for="biologi" class="block text-sm font-semibold text-gray-700 mb-2">Biologi <span class="text-red-500">*</span></label>
|
||||
<input id="biologi" type="number" name="biologi" min="0" max="100" value="{{ old('biologi') }}" placeholder="Nilai: 80" required
|
||||
class="block w-full px-3 sm:px-4 py-2 border border-gray-300 rounded-lg focus-maroon focus:outline-none text-sm transition-colors @error('biologi') input-error @enderror">
|
||||
class="block w-full px-4 py-2 border border-gray-300 rounded-lg focus-maroon focus:outline-none text-sm transition-colors @error('biologi') input-error @enderror">
|
||||
@error('biologi')
|
||||
<span class="validation-message text-red-600">⚠️ {{ $message }}</span>
|
||||
@enderror
|
||||
|
|
@ -173,35 +190,35 @@ class="block w-full px-3 sm:px-4 py-2 border border-gray-300 rounded-lg focus-ma
|
|||
</div>
|
||||
@else
|
||||
{{-- SISWA IPS: Ekonomi, Geografi, Sosiologi, Sejarah --}}
|
||||
<div class="grid grid-cols-2 lg:grid-cols-4 gap-2 sm:gap-3">
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<div class="input-wrapper">
|
||||
<label for="ekonomi" class="block text-xs sm:text-sm font-semibold text-gray-700 mb-1">Ekonomi <span class="text-red-500">*</span></label>
|
||||
<label for="ekonomi" class="block text-sm font-semibold text-gray-700 mb-2">Ekonomi <span class="text-red-500">*</span></label>
|
||||
<input id="ekonomi" type="number" name="ekonomi" min="0" max="100" value="{{ old('ekonomi') }}" placeholder="Nilai: 82" required
|
||||
class="block w-full px-3 sm:px-4 py-2 border border-gray-300 rounded-lg focus-maroon focus:outline-none text-sm transition-colors @error('ekonomi') input-error @enderror">
|
||||
class="block w-full px-4 py-2 border border-gray-300 rounded-lg focus-maroon focus:outline-none text-sm transition-colors @error('ekonomi') input-error @enderror">
|
||||
@error('ekonomi')
|
||||
<span class="validation-message text-red-600">⚠️ {{ $message }}</span>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="input-wrapper">
|
||||
<label for="geografi" class="block text-xs sm:text-sm font-semibold text-gray-700 mb-1">Geografi <span class="text-red-500">*</span></label>
|
||||
<label for="geografi" class="block text-sm font-semibold text-gray-700 mb-2">Geografi <span class="text-red-500">*</span></label>
|
||||
<input id="geografi" type="number" name="geografi" min="0" max="100" value="{{ old('geografi') }}" placeholder="Nilai: 76" required
|
||||
class="block w-full px-3 sm:px-4 py-2 border border-gray-300 rounded-lg focus-maroon focus:outline-none text-sm transition-colors @error('geografi') input-error @enderror">
|
||||
class="block w-full px-4 py-2 border border-gray-300 rounded-lg focus-maroon focus:outline-none text-sm transition-colors @error('geografi') input-error @enderror">
|
||||
@error('geografi')
|
||||
<span class="validation-message text-red-600">⚠️ {{ $message }}</span>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="input-wrapper">
|
||||
<label for="sosiologi" class="block text-xs sm:text-sm font-semibold text-gray-700 mb-1">Sosiologi <span class="text-red-500">*</span></label>
|
||||
<label for="sosiologi" class="block text-sm font-semibold text-gray-700 mb-2">Sosiologi <span class="text-red-500">*</span></label>
|
||||
<input id="sosiologi" type="number" name="sosiologi" min="0" max="100" value="{{ old('sosiologi') }}" placeholder="Nilai: 74" required
|
||||
class="block w-full px-3 sm:px-4 py-2 border border-gray-300 rounded-lg focus-maroon focus:outline-none text-sm transition-colors @error('sosiologi') input-error @enderror">
|
||||
class="block w-full px-4 py-2 border border-gray-300 rounded-lg focus-maroon focus:outline-none text-sm transition-colors @error('sosiologi') input-error @enderror">
|
||||
@error('sosiologi')
|
||||
<span class="validation-message text-red-600">⚠️ {{ $message }}</span>
|
||||
@enderror
|
||||
</div>
|
||||
<div class="input-wrapper">
|
||||
<label for="sejarah" class="block text-xs sm:text-sm font-semibold text-gray-700 mb-1">Sejarah <span class="text-red-500">*</span></label>
|
||||
<label for="sejarah" class="block text-sm font-semibold text-gray-700 mb-2">Sejarah <span class="text-red-500">*</span></label>
|
||||
<input id="sejarah" type="number" name="sejarah" min="0" max="100" value="{{ old('sejarah') }}" placeholder="Nilai: 70" required
|
||||
class="block w-full px-3 sm:px-4 py-2 border border-gray-300 rounded-lg focus-maroon focus:outline-none text-sm transition-colors @error('sejarah') input-error @enderror">
|
||||
class="block w-full px-4 py-2 border border-gray-300 rounded-lg focus-maroon focus:outline-none text-sm transition-colors @error('sejarah') input-error @enderror">
|
||||
@error('sejarah')
|
||||
<span class="validation-message text-red-600">⚠️ {{ $message }}</span>
|
||||
@enderror
|
||||
|
|
@ -210,18 +227,18 @@ class="block w-full px-3 sm:px-4 py-2 border border-gray-300 rounded-lg focus-ma
|
|||
@endif
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 sm:gap-6">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{{-- ============================================ --}}
|
||||
{{-- KRITERIA 2: MINAT SISWA --}}
|
||||
{{-- ============================================ --}}
|
||||
<div class="p-4 sm:p-5 rounded-lg border-2 border-gray-200 bg-gray-50">
|
||||
<h3 class="font-bold text-maroon text-base sm:text-lg mb-1 sm:mb-2">2. Minat Siswa <span class="text-red-500">*</span></h3>
|
||||
<p class="text-xs text-gray-600 mb-3 sm:mb-4">Tuliskan bidang atau kegiatan yang Anda minati / sukai.</p>
|
||||
<div class="p-6 rounded-lg border-2 border-gray-200 bg-gray-50">
|
||||
<h3 class="font-bold text-lg sm:text-xl text-blue-700 mb-2">2️⃣ Minat Siswa <span class="text-red-500">*</span></h3>
|
||||
<p class="text-sm text-gray-600 mb-4">Tuliskan bidang atau kegiatan yang Anda minati / sukai.</p>
|
||||
<div class="input-wrapper">
|
||||
<label for="minat" class="block text-xs sm:text-sm font-semibold text-gray-700 mb-1">Bidang Minat</label>
|
||||
<label for="minat" class="block text-sm font-semibold text-gray-700 mb-2">Bidang Minat</label>
|
||||
<input id="minat" type="text" name="minat" value="{{ old('minat') }}" placeholder="Contoh: coding, komputer, bisnis, pertanian"
|
||||
class="block w-full px-3 sm:px-4 py-2 border border-gray-300 rounded-lg focus-maroon focus:outline-none text-sm transition-colors @error('minat') input-error @enderror" required>
|
||||
<p class="text-xs text-gray-500 mt-1">Pisahkan dengan koma jika lebih dari satu minat</p>
|
||||
class="block w-full px-4 py-2 border border-gray-300 rounded-lg focus-maroon focus:outline-none text-sm transition-colors @error('minat') input-error @enderror" required>
|
||||
<p class="text-xs text-gray-500 mt-2">Pisahkan dengan koma jika lebih dari satu minat</p>
|
||||
@error('minat')
|
||||
<span class="validation-message text-red-600">⚠️ {{ $message }}</span>
|
||||
@enderror
|
||||
|
|
@ -231,14 +248,12 @@ class="block w-full px-3 sm:px-4 py-2 border border-gray-300 rounded-lg focus-ma
|
|||
{{-- ============================================ --}}
|
||||
{{-- KRITERIA 3: PREFERENSI STUDI LANJUTAN --}}
|
||||
{{-- ============================================ --}}
|
||||
<div class="p-4 sm:p-5 rounded-lg border-2 border-gray-200 bg-gray-50">
|
||||
<h3 class="font-bold text-maroon text-base sm:text-lg mb-1 sm:mb-2">3. Preferensi Studi Lanjutan <span class="text-red-500">*</span></h3>
|
||||
<p class="text-xs text-gray-600 mb-3 sm:mb-4">
|
||||
Pilih rumpun jurusan Politeknik Negeri Jember yang paling sesuai dengan minat studi lanjutan Anda.
|
||||
</p>
|
||||
<div class="p-6 rounded-lg border-2 border-gray-200 bg-gray-50">
|
||||
<h3 class="font-bold text-lg sm:text-xl text-green-700 mb-2">3️⃣ Preferensi Studi Lanjutan <span class="text-red-500">*</span></h3>
|
||||
<p class="text-sm text-gray-600 mb-4">Pilih rumpun jurusan Politeknik Negeri Jember yang paling sesuai.</p>
|
||||
<div class="input-wrapper">
|
||||
<label for="pref_studi" class="block text-xs sm:text-sm font-semibold text-gray-700 mb-1">Arah Rumpun Jurusan Tujuan</label>
|
||||
<select id="pref_studi" name="pref_studi" class="block w-full px-3 sm:px-4 py-2 border border-gray-300 rounded-lg focus-maroon focus:outline-none text-sm transition-colors @error('pref_studi') input-error @enderror" required>
|
||||
<label for="pref_studi" class="block text-sm font-semibold text-gray-700 mb-2">Arah Rumpun Jurusan Tujuan</label>
|
||||
<select id="pref_studi" name="pref_studi" class="block w-full px-4 py-2 border border-gray-300 rounded-lg focus-maroon focus:outline-none text-sm transition-colors @error('pref_studi') input-error @enderror" required>
|
||||
<option value="">-- Pilih Arah Rumpun Jurusan --</option>
|
||||
<option value="Sains & Teknologi" {{ old('pref_studi') == 'Sains & Teknologi' ? 'selected' : '' }}>Sains & Teknologi (contoh: TI, Teknik)</option>
|
||||
<option value="Pertanian & Lingkungan" {{ old('pref_studi') == 'Pertanian & Lingkungan' ? 'selected' : '' }}>Pertanian & Lingkungan (contoh: Produksi/Teknologi Pertanian)</option>
|
||||
|
|
@ -246,7 +261,7 @@ class="block w-full px-3 sm:px-4 py-2 border border-gray-300 rounded-lg focus-ma
|
|||
<option value="Bisnis & Manajemen" {{ old('pref_studi') == 'Bisnis & Manajemen' ? 'selected' : '' }}>Bisnis & Manajemen (contoh: Akuntansi, Manajemen Agribisnis)</option>
|
||||
<option value="Sosial & Humaniora" {{ old('pref_studi') == 'Sosial & Humaniora' ? 'selected' : '' }}>Sosial & Humaniora (contoh: Bahasa, Komunikasi, Pariwisata)</option>
|
||||
</select>
|
||||
<p class="text-xs text-gray-500 mt-1">Pilih rumpun yang paling menggambarkan jurusan Polije yang ingin Anda tuju setelah lulus.</p>
|
||||
<p class="text-xs text-gray-500 mt-2">Pilih rumpun yang paling menggambarkan jurusan Polije yang ingin Anda tuju.</p>
|
||||
@error('pref_studi')
|
||||
<span class="validation-message text-red-600">⚠️ {{ $message }}</span>
|
||||
@enderror
|
||||
|
|
@ -256,14 +271,14 @@ class="block w-full px-3 sm:px-4 py-2 border border-gray-300 rounded-lg focus-ma
|
|||
{{-- ============================================ --}}
|
||||
{{-- KRITERIA 4: CITA-CITA / PREFERENSI KARIR --}}
|
||||
{{-- ============================================ --}}
|
||||
<div class="p-4 sm:p-5 rounded-lg border-2 border-gray-200 bg-gray-50">
|
||||
<h3 class="font-bold text-maroon text-base sm:text-lg mb-1 sm:mb-2">4. Cita-cita / Preferensi Karir <span class="text-red-500">*</span></h3>
|
||||
<p class="text-xs text-gray-600 mb-3 sm:mb-4">Tuliskan profesi atau karir yang Anda impikan.</p>
|
||||
<div class="p-6 rounded-lg border-2 border-gray-200 bg-gray-50">
|
||||
<h3 class="font-bold text-lg sm:text-xl text-orange-700 mb-2">4️⃣ Cita-cita / Preferensi Karir <span class="text-red-500">*</span></h3>
|
||||
<p class="text-sm text-gray-600 mb-4">Tuliskan profesi atau karir yang Anda impikan.</p>
|
||||
<div class="input-wrapper">
|
||||
<label for="cita_cita" class="block text-xs sm:text-sm font-semibold text-gray-700 mb-1">Cita-cita</label>
|
||||
<label for="cita_cita" class="block text-sm font-semibold text-gray-700 mb-2">Cita-cita</label>
|
||||
<input id="cita_cita" type="text" name="cita_cita" value="{{ old('cita_cita') }}" placeholder="Contoh: programmer, dokter, pengusaha"
|
||||
class="block w-full px-3 sm:px-4 py-2 border border-gray-300 rounded-lg focus-maroon focus:outline-none text-sm transition-colors @error('cita_cita') input-error @enderror" required>
|
||||
<p class="text-xs text-gray-500 mt-1">Bisa lebih dari satu, pisahkan dengan koma</p>
|
||||
class="block w-full px-4 py-2 border border-gray-300 rounded-lg focus-maroon focus:outline-none text-sm transition-colors @error('cita_cita') input-error @enderror" required>
|
||||
<p class="text-xs text-gray-500 mt-2">Bisa lebih dari satu, pisahkan dengan koma</p>
|
||||
@error('cita_cita')
|
||||
<span class="validation-message text-red-600">⚠️ {{ $message }}</span>
|
||||
@enderror
|
||||
|
|
@ -273,14 +288,14 @@ class="block w-full px-3 sm:px-4 py-2 border border-gray-300 rounded-lg focus-ma
|
|||
{{-- ============================================ --}}
|
||||
{{-- KRITERIA 5: PRESTASI AKADEMIK / NON-AKADEMIK --}}
|
||||
{{-- ============================================ --}}
|
||||
<div class="p-4 sm:p-5 rounded-lg border-2 border-gray-200 bg-gray-50">
|
||||
<h3 class="font-bold text-maroon text-base sm:text-lg mb-1 sm:mb-2">5. Prestasi Akademik / Non-Akademik</h3>
|
||||
<p class="text-xs text-gray-600 mb-3 sm:mb-4">Tuliskan prestasi yang pernah diraih (opsional).</p>
|
||||
<div class="p-6 rounded-lg border-2 border-gray-200 bg-gray-50">
|
||||
<h3 class="font-bold text-lg sm:text-xl text-red-700 mb-2">5️⃣ Prestasi (Opsional)</h3>
|
||||
<p class="text-sm text-gray-600 mb-4">Tuliskan prestasi yang pernah diraih (opsional).</p>
|
||||
<div class="input-wrapper">
|
||||
<label for="prestasi" class="block text-xs sm:text-sm font-semibold text-gray-700 mb-1">Prestasi</label>
|
||||
<label for="prestasi" class="block text-sm font-semibold text-gray-700 mb-2">Prestasi</label>
|
||||
<input id="prestasi" type="text" name="prestasi" value="{{ old('prestasi') }}" placeholder="Contoh: Juara 1 olimpiade MTK, sertifikat web design"
|
||||
class="block w-full px-3 sm:px-4 py-2 border border-gray-300 rounded-lg focus-maroon focus:outline-none text-sm transition-colors @error('prestasi') input-error @enderror">
|
||||
<p class="text-xs text-gray-500 mt-1">Kosongkan jika belum ada prestasi</p>
|
||||
class="block w-full px-4 py-2 border border-gray-300 rounded-lg focus-maroon focus:outline-none text-sm transition-colors @error('prestasi') input-error @enderror">
|
||||
<p class="text-xs text-gray-500 mt-2">Kosongkan jika belum ada prestasi</p>
|
||||
@error('prestasi')
|
||||
<span class="validation-message text-red-600">⚠️ {{ $message }}</span>
|
||||
@enderror
|
||||
|
|
@ -289,14 +304,14 @@ class="block w-full px-3 sm:px-4 py-2 border border-gray-300 rounded-lg focus-ma
|
|||
</div>
|
||||
|
||||
<!-- Submit Button -->
|
||||
<div class="mt-4 sm:mt-6 p-3 sm:p-4 rounded-lg bg-gradient-to-r from-yellow-50 to-yellow-100 border border-yellow-200 text-center">
|
||||
<p class="text-xs sm:text-sm text-gray-600 mb-3 sm:mb-4">
|
||||
⏳ Setelah menekan tombol, sistem akan menganalisis data Anda dan menampilkan ranking 9 jurusan.
|
||||
<div class="mt-8 p-6 rounded-lg bg-gradient-to-r from-yellow-50 to-yellow-100 border-l-4 border-yellow-400 shadow-sm">
|
||||
<p class="text-sm text-gray-700 mb-4 leading-relaxed">
|
||||
⏳ Setelah menekan tombol, sistem akan menganalisis data Anda dengan algoritma Naive Bayes dan menampilkan ranking 9 jurusan Politeknik Negeri Jember yang paling sesuai dengan profil kamu.
|
||||
</p>
|
||||
<button type="submit" class="w-full gradient-maroon text-white font-bold py-2 sm:py-3 px-4 sm:px-6 rounded-lg hover:opacity-90 active:scale-95 transition duration-200 text-sm sm:text-base shadow-lg disabled:opacity-50 disabled:cursor-not-allowed">
|
||||
<button type="submit" class="w-full bg-gradient-to-r from-purple-600 to-indigo-600 text-white font-bold py-3 px-6 rounded-lg hover:shadow-lg active:scale-95 transition duration-200 text-base shadow-lg disabled:opacity-50 disabled:cursor-not-allowed">
|
||||
✨ Lihat Rekomendasi Jurusan
|
||||
</button>
|
||||
<p class="text-xs sm:text-sm text-gray-500 mt-3">Pastikan semua data terisi dengan benar sebelum melanjutkan</p>
|
||||
<p class="text-xs sm:text-sm text-gray-600 mt-3 text-center">Pastikan semua data terisi dengan benar sebelum melanjutkan</p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
|
@ -346,10 +361,23 @@ class="block w-full px-3 sm:px-4 py-2 border border-gray-300 rounded-lg focus-ma
|
|||
@endif
|
||||
|
||||
<!-- Info Metode -->
|
||||
<div class="mt-6 sm:mt-8 p-3 sm:p-4 bg-white rounded-lg border border-gray-200 shadow-sm">
|
||||
<p class="text-xs sm:text-sm text-gray-600">
|
||||
<strong>Metode:</strong> Sistem menggunakan Graduated Scoring dengan 5 kriteria: Nilai Akademik (40%), Minat & Bakat (35%), Preferensi Studi (15%), Cita-cita (5%), Prestasi (5%).
|
||||
</p>
|
||||
<div class="mt-8 sm:mt-12 p-6 rounded-lg bg-blue-50 border-l-4 border-blue-400 shadow-sm">
|
||||
<div class="flex gap-4">
|
||||
<div class="text-3xl flex-shrink-0">🤖</div>
|
||||
<div>
|
||||
<h3 class="font-bold text-blue-900 mb-2 text-lg">Tentang Sistem Rekomendasi Kami</h3>
|
||||
<p class="text-sm text-blue-800 leading-relaxed">
|
||||
<strong>Metode:</strong> Sistem menggunakan Weighted Naive Bayes dengan 5 kriteria:
|
||||
</p>
|
||||
<ul class="text-sm text-blue-800 mt-3 space-y-1 ml-4">
|
||||
<li>📚 Nilai Akademik (15.6%)</li>
|
||||
<li>💡 Minat & Bakat (45.6%)</li>
|
||||
<li>🎯 Preferensi Studi (25.6%)</li>
|
||||
<li>🚀 Cita-cita (9%)</li>
|
||||
<li>🏆 Prestasi (4%)</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -7,17 +7,20 @@
|
|||
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
||||
<style>
|
||||
.gradient-maroon {
|
||||
background: linear-gradient(135deg, #5B7B89 0%, #7B9BA5 100%);
|
||||
background: linear-gradient(135deg, #9333ea 0%, #6366f1 100%);
|
||||
}
|
||||
.text-maroon {
|
||||
color: #5B7B89;
|
||||
color: #9333ea;
|
||||
}
|
||||
.border-maroon {
|
||||
border-color: #5B7B89;
|
||||
border-color: #9333ea;
|
||||
}
|
||||
.bg-cream {
|
||||
background-color: #F8FAFC;
|
||||
}
|
||||
.gradient-button {
|
||||
background: linear-gradient(135deg, #9333ea 0%, #6366f1 100%);
|
||||
}
|
||||
.mobile-menu-toggle {
|
||||
display: none;
|
||||
}
|
||||
|
|
@ -32,7 +35,7 @@
|
|||
top: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: linear-gradient(135deg, #5B7B89 0%, #7B9BA5 100%);
|
||||
background: linear-gradient(135deg, #9333ea 0%, #6366f1 100%);
|
||||
padding: 1rem 1.5rem;
|
||||
gap: 0.5rem;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
||||
|
|
@ -46,43 +49,43 @@
|
|||
</head>
|
||||
<body class="bg-cream">
|
||||
<header class="gradient-maroon text-white shadow-lg sticky top-0 z-50">
|
||||
<div class="container mx-auto px-4 sm:px-6 py-4 flex justify-between items-center relative">
|
||||
<div class="w-full px-4 sm:px-6 py-4 flex justify-between items-center relative">
|
||||
<div>
|
||||
<h1 class="text-xl sm:text-2xl md:text-3xl font-bold">Sistem Pemilihan Jurusan</h1>
|
||||
<p class="text-xs sm:text-sm text-gray-200 font-semibold mt-1">Pilih Jurusan yang Tepat.</p>
|
||||
<h1 class="text-xl sm:text-2xl md:text-3xl font-bold">SPK Jurusan Polije</h1>
|
||||
<p class="text-xs sm:text-sm text-purple-100 font-semibold mt-1">Temukan Jurusan Terbaik Untukmu</p>
|
||||
</div>
|
||||
<button class="mobile-menu-toggle text-white text-2xl" id="menuToggle">☰</button>
|
||||
<div class="mobile-menu md:flex md:space-x-4 md:items-center" id="mobileMenu">
|
||||
@if (Route::has('login'))
|
||||
<a href="{{ route('login') }}" class="bg-yellow-400 text-maroon font-bold py-2 px-6 rounded-lg hover:bg-yellow-300 transition text-sm sm:text-base text-center block md:inline-block">Login</a>
|
||||
<a href="{{ route('register') }}" class="border-2 border-yellow-400 text-yellow-300 font-bold py-2 px-6 rounded-lg hover:bg-yellow-400 hover:text-maroon transition text-sm sm:text-base text-center block md:inline-block">Daftar</a>
|
||||
<a href="{{ route('login') }}" class="bg-white text-purple-700 font-bold py-2 px-6 rounded-lg hover:bg-purple-50 transition text-sm sm:text-base text-center block md:inline-block shadow-md">Login</a>
|
||||
<a href="{{ route('register') }}" class="border-2 border-white text-white font-bold py-2 px-6 rounded-lg hover:bg-white hover:text-purple-700 transition text-sm sm:text-base text-center block md:inline-block">Daftar</a>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section class="py-8 sm:py-12 md:py-16 gradient-maroon text-white">
|
||||
<div class="container mx-auto px-4 sm:px-6">
|
||||
<div class="w-full px-4 sm:px-6">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 md:gap-12 items-center">
|
||||
<div>
|
||||
<h2 class="text-3xl sm:text-4xl md:text-5xl font-bold mb-4 sm:mb-6">Tentukan Pilihan Jurusan dengan Bijak</h2>
|
||||
<p class="text-sm sm:text-base md:text-lg mb-3 sm:mb-4 text-yellow-100">
|
||||
Selamat datang, siswa SMA Bima Ambulu. Memilih jurusan di Politeknik Negeri Jember adalah keputusan penting yang mempengaruhi masa depan. Sistem ini membantu Anda menentukan pilihan jurusan yang sesuai dengan kemampuan dan minat.
|
||||
<p class="text-sm sm:text-base md:text-lg mb-3 sm:mb-4 text-purple-100 leading-relaxed">
|
||||
Selamat datang di Sistem Pemilihan Jurusan Politeknik Negeri Jember! Memilih jurusan adalah keputusan penting yang menentukan masa depan karirmu. Kami membantu kamu menemukan jurusan yang paling sesuai dengan kemampuan akademis, minat, dan impian karir.
|
||||
</p>
|
||||
<p class="text-sm sm:text-base md:text-lg mb-6 sm:mb-8 text-yellow-100">
|
||||
Sistem menganalisis 5 aspek utama untuk memberikan rekomendasi jurusan Politeknik Negeri Jember (Polije) yang akurat dan personal.
|
||||
<p class="text-sm sm:text-base md:text-lg mb-6 sm:mb-8 text-purple-100 leading-relaxed">
|
||||
Sistem kami menganalisis 5 aspek utama dari profilmu untuk memberikan rekomendasi jurusan yang akurat, terpercaya, dan personal hanya untuk kamu.
|
||||
</p>
|
||||
<div class="flex flex-col sm:flex-row gap-3 sm:gap-4">
|
||||
<a href="{{ route('login') }}" class="inline-block bg-yellow-400 text-maroon font-bold py-2 sm:py-3 px-6 sm:px-8 rounded-lg hover:bg-yellow-300 transition text-sm sm:text-base text-center">Mulai Analisis</a>
|
||||
<a href="{{ route('login') }}" class="inline-block bg-white text-purple-700 font-bold py-3 sm:py-4 px-8 sm:px-10 rounded-lg hover:shadow-lg hover:bg-purple-50 transition text-sm sm:text-base text-center shadow-md">Mulai Analisis</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-center">
|
||||
<div class="bg-white rounded-lg p-6 sm:p-8 shadow-2xl w-full max-w-sm text-center text-maroon">
|
||||
<div class="text-5xl sm:text-6xl mb-4">✨</div>
|
||||
<h3 class="text-xl sm:text-2xl font-bold mb-3 sm:mb-4">9 Kategori Jurusan</h3>
|
||||
<p class="text-xs sm:text-sm text-gray-600 mb-4 sm:mb-6">Pilihan jurusan Politeknik Negeri Jember dari berbagai bidang: pertanian, teknologi, kesehatan, hingga bisnis</p>
|
||||
<div class="bg-yellow-100 rounded-lg p-4">
|
||||
<p class="text-xs sm:text-sm font-semibold">Temukan Ranking Jurusan yang Paling Cocok buat Kamu</p>
|
||||
<div class="bg-white rounded-xl p-8 sm:p-10 shadow-2xl w-full max-w-sm text-center border-t-4 border-purple-600">
|
||||
<div class="text-6xl sm:text-7xl mb-4">🚀</div>
|
||||
<h3 class="text-2xl sm:text-3xl font-bold mb-3 sm:mb-4 text-purple-700">9 Pilihan Jurusan</h3>
|
||||
<p class="text-sm text-gray-600 mb-6 leading-relaxed">Dari berbagai bidang: Pertanian, Teknologi, Kesehatan, Bisnis, dan Humaniora. Setiap dengan peluang karir yang menjanjikan.</p>
|
||||
<div class="bg-purple-100 rounded-lg p-4 border-l-4 border-purple-600">
|
||||
<p class="text-sm font-semibold text-purple-900">💡 Dapatkan ranking jurusan yang unik sesuai profilmu</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -92,23 +95,24 @@
|
|||
|
||||
<!-- MENGAPA SISTEM INI PENTING -->
|
||||
<section class="py-8 sm:py-12 md:py-16 bg-white">
|
||||
<div class="container mx-auto px-4 sm:px-6">
|
||||
<h2 class="text-2xl sm:text-3xl md:text-4xl font-bold text-center text-maroon mb-8 sm:mb-12">Mengapa Perlu Menggunakan Sistem Ini?</h2>
|
||||
<div class="w-full px-4 sm:px-6">
|
||||
<h2 class="text-2xl sm:text-3xl md:text-4xl font-bold text-center text-purple-700 mb-3 sm:mb-4">Mengapa Menggunakan Sistem Ini?</h2>
|
||||
<p class="text-center text-gray-600 mb-8 sm:mb-12 max-w-2xl mx-auto">Sistem kami dirancang khusus untuk membantu siswa membuat keputusan yang tepat dan percaya diri dalam memilih jurusan.</p>
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 sm:gap-8">
|
||||
<div class="p-6 sm:p-8 bg-cream rounded-xl border-2 border-maroon shadow-md">
|
||||
<div class="text-4xl sm:text-5xl mb-3 sm:mb-4">🤖</div>
|
||||
<h3 class="text-lg sm:text-xl font-bold text-maroon mb-2 sm:mb-3">Analisis Berbasis Data</h3>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Menggunakan pendekatan berbasis data untuk menganalisis profil akademik dan non-akademik secara detail</p>
|
||||
<div class="p-8 rounded-xl bg-gradient-to-br from-blue-50 to-blue-100 border-2 border-blue-300 shadow-md hover:shadow-lg transition">
|
||||
<div class="text-5xl mb-4">🤖</div>
|
||||
<h3 class="text-lg font-bold text-blue-900 mb-3">AI yang Terpercaya</h3>
|
||||
<p class="text-sm text-blue-800 leading-relaxed">Menggunakan Naive Bayes algorithm untuk analisis data yang akurat dan terukur</p>
|
||||
</div>
|
||||
<div class="p-6 sm:p-8 bg-cream rounded-xl border-2 border-maroon shadow-md">
|
||||
<div class="text-4xl sm:text-5xl mb-3 sm:mb-4">🎯</div>
|
||||
<h3 class="text-lg sm:text-xl font-bold text-maroon mb-2 sm:mb-3">Pendekatan Menyeluruh</h3>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Tidak hanya berdasarkan nilai, tetapi juga minat, preferensi studi lanjutan, cita-cita karir, dan prestasi</p>
|
||||
<div class="p-8 rounded-xl bg-gradient-to-br from-green-50 to-green-100 border-2 border-green-300 shadow-md hover:shadow-lg transition">
|
||||
<div class="text-5xl mb-4">🎯</div>
|
||||
<h3 class="text-lg font-bold text-green-900 mb-3">Pendekatan Holistik</h3>
|
||||
<p class="text-sm text-green-800 leading-relaxed">Menganalisis 5 aspek: nilai akademik, minat, preferensi, cita-cita, dan prestasi</p>
|
||||
</div>
|
||||
<div class="p-6 sm:p-8 bg-cream rounded-xl border-2 border-maroon shadow-md">
|
||||
<div class="text-4xl sm:text-5xl mb-3 sm:mb-4">💡</div>
|
||||
<h3 class="text-lg sm:text-xl font-bold text-maroon mb-2 sm:mb-3">Rekomendasi Akurat</h3>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Membantu Anda memilih jurusan dengan lebih yakin berdasarkan data yang objektif</p>
|
||||
<div class="p-8 rounded-xl bg-gradient-to-br from-purple-50 to-purple-100 border-2 border-purple-300 shadow-md hover:shadow-lg transition">
|
||||
<div class="text-5xl mb-4">✨</div>
|
||||
<h3 class="text-lg font-bold text-purple-900 mb-3">Hasil Akurat</h3>
|
||||
<p class="text-sm text-purple-800 leading-relaxed">Dapatkan ranking jurusan dengan skor kecocokan yang detail dan penjelasan mendalam</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -116,53 +120,53 @@
|
|||
|
||||
|
||||
<!-- 5 FAKTOR KEPUTUSAN -->
|
||||
<section class="py-8 sm:py-12 md:py-16 bg-cream">
|
||||
<div class="container mx-auto px-4 sm:px-6">
|
||||
<h2 class="text-2xl sm:text-3xl md:text-4xl font-bold text-center text-maroon mb-3 sm:mb-4">5 Aspek yang Dianalisis Sistem</h2>
|
||||
<p class="text-center text-xs sm:text-sm md:text-base text-gray-700 mb-8 sm:mb-12 max-w-3xl mx-auto">Sistem ini menganalisis 5 aspek penting dalam profil Anda untuk memberikan rekomendasi jurusan yang tepat dan personal.</p>
|
||||
<section class="py-8 sm:py-12 md:py-16 bg-gray-50">
|
||||
<div class="w-full px-4 sm:px-6">
|
||||
<h2 class="text-2xl sm:text-3xl md:text-4xl font-bold text-center text-purple-700 mb-3 sm:mb-4">5 Aspek yang Dianalisis Sistem</h2>
|
||||
<p class="text-center text-gray-700 mb-8 sm:mb-12 max-w-3xl mx-auto">Sistem kami menganalisis 5 aspek penting dari profilmu untuk memberikan rekomendasi yang akurat dan personal.</p>
|
||||
<div class="max-w-4xl mx-auto space-y-4 sm:space-y-6">
|
||||
<div class="bg-white p-5 sm:p-8 rounded-lg border-l-4 border-maroon shadow-md hover:shadow-lg transition">
|
||||
<div class="bg-white p-6 sm:p-8 rounded-lg border-l-4 border-purple-600 shadow-md hover:shadow-lg transition">
|
||||
<div class="flex flex-col sm:flex-row items-start gap-4 sm:gap-6">
|
||||
<div class="text-2xl sm:text-3xl font-bold text-yellow-400 bg-maroon rounded-full w-12 h-12 sm:w-16 sm:h-16 flex items-center justify-center flex-shrink-0">1</div>
|
||||
<div class="text-3xl font-bold text-white bg-purple-600 rounded-full w-14 h-14 sm:w-16 sm:h-16 flex items-center justify-center flex-shrink-0">1</div>
|
||||
<div>
|
||||
<h3 class="text-lg sm:text-xl md:text-2xl font-bold text-maroon mb-1 sm:mb-2">📚 Nilai Akademik (Bobot 40%)</h3>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Nilai Anda pada mata pelajaran utama (IPA atau IPS) menunjukkan kemampuan dasar untuk sukses di jurusan tertentu</p>
|
||||
<h3 class="text-xl sm:text-2xl font-bold text-purple-700 mb-2">📚 Nilai Akademik (15.6%)</h3>
|
||||
<p class="text-sm text-gray-700 leading-relaxed">Nilai Anda pada mata pelajaran utama (IPA atau IPS) menunjukkan kemampuan dasar dan potensi untuk sukses di jurusan tertentu</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white p-5 sm:p-8 rounded-lg border-l-4 border-maroon shadow-md hover:shadow-lg transition">
|
||||
<div class="bg-white p-6 sm:p-8 rounded-lg border-l-4 border-blue-600 shadow-md hover:shadow-lg transition">
|
||||
<div class="flex flex-col sm:flex-row items-start gap-4 sm:gap-6">
|
||||
<div class="text-2xl sm:text-3xl font-bold text-yellow-400 bg-maroon rounded-full w-12 h-12 sm:w-16 sm:h-16 flex items-center justify-center flex-shrink-0">2</div>
|
||||
<div class="text-3xl font-bold text-white bg-blue-600 rounded-full w-14 h-14 sm:w-16 sm:h-16 flex items-center justify-center flex-shrink-0">2</div>
|
||||
<div>
|
||||
<h3 class="text-lg sm:text-xl md:text-2xl font-bold text-maroon mb-1 sm:mb-2">❤️ Minat & Passion (Bobot 35%)</h3>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Minat Anda terhadap bidang atau kegiatan tertentu sangat menentukan keberhasilan dalam perkuliahan</p>
|
||||
<h3 class="text-xl sm:text-2xl font-bold text-blue-700 mb-2">💡 Minat & Passion (45.6%)</h3>
|
||||
<p class="text-sm text-gray-700 leading-relaxed">Minat Anda terhadap bidang atau kegiatan tertentu sangat menentukan motivasi dan kesuksesan Anda dalam perkuliahan</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white p-5 sm:p-8 rounded-lg border-l-4 border-maroon shadow-md hover:shadow-lg transition">
|
||||
<div class="bg-white p-6 sm:p-8 rounded-lg border-l-4 border-green-600 shadow-md hover:shadow-lg transition">
|
||||
<div class="flex flex-col sm:flex-row items-start gap-4 sm:gap-6">
|
||||
<div class="text-2xl sm:text-3xl font-bold text-yellow-400 bg-maroon rounded-full w-12 h-12 sm:w-16 sm:h-16 flex items-center justify-center flex-shrink-0">3</div>
|
||||
<div class="text-3xl font-bold text-white bg-green-600 rounded-full w-14 h-14 sm:w-16 sm:h-16 flex items-center justify-center flex-shrink-0">3</div>
|
||||
<div>
|
||||
<h3 class="text-lg sm:text-xl md:text-2xl font-bold text-maroon mb-1 sm:mb-2">🎓 Preferensi Studi Lanjutan (Bobot 15%)</h3>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Pilihan rumpun bidang studi (Sains & Teknologi, Pertanian, Kesehatan, Bisnis, atau Sosial & Humaniora) yang sesuai dengan kecenderungan dan prospek karir Anda</p>
|
||||
<h3 class="text-xl sm:text-2xl font-bold text-green-700 mb-2">🎯 Preferensi Studi Lanjutan (25.6%)</h3>
|
||||
<p class="text-sm text-gray-700 leading-relaxed">Pilihan rumpun bidang studi yang sesuai dengan kecenderungan akademis dan prospek karir jangka panjang Anda</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white p-5 sm:p-8 rounded-lg border-l-4 border-maroon shadow-md hover:shadow-lg transition">
|
||||
<div class="bg-white p-6 sm:p-8 rounded-lg border-l-4 border-amber-600 shadow-md hover:shadow-lg transition">
|
||||
<div class="flex flex-col sm:flex-row items-start gap-4 sm:gap-6">
|
||||
<div class="text-2xl sm:text-3xl font-bold text-yellow-400 bg-maroon rounded-full w-12 h-12 sm:w-16 sm:h-16 flex items-center justify-center flex-shrink-0">4</div>
|
||||
<div class="text-3xl font-bold text-white bg-amber-600 rounded-full w-14 h-14 sm:w-16 sm:h-16 flex items-center justify-center flex-shrink-0">4</div>
|
||||
<div>
|
||||
<h3 class="text-lg sm:text-xl md:text-2xl font-bold text-maroon mb-1 sm:mb-2">🚀 Impian dan Tujuan Karir (Bobot 5%)</h3>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Cita-cita dan target karir Anda membantu mencocokkan pilihan jurusan dengan jalur profesional yang diinginkan</p>
|
||||
<h3 class="text-xl sm:text-2xl font-bold text-amber-700 mb-2">🚀 Cita-Cita & Tujuan Karir (9%)</h3>
|
||||
<p class="text-sm text-gray-700 leading-relaxed">Target karir dan impian profesional Anda membantu kami mencocokkan jurusan dengan jalur karir yang Anda inginkan</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white p-5 sm:p-8 rounded-lg border-l-4 border-maroon shadow-md hover:shadow-lg transition">
|
||||
<div class="bg-white p-6 sm:p-8 rounded-lg border-l-4 border-red-600 shadow-md hover:shadow-lg transition">
|
||||
<div class="flex flex-col sm:flex-row items-start gap-4 sm:gap-6">
|
||||
<div class="text-2xl sm:text-3xl font-bold text-yellow-400 bg-maroon rounded-full w-12 h-12 sm:w-16 sm:h-16 flex items-center justify-center flex-shrink-0">5</div>
|
||||
<div class="text-3xl font-bold text-white bg-red-600 rounded-full w-14 h-14 sm:w-16 sm:h-16 flex items-center justify-center flex-shrink-0">5</div>
|
||||
<div>
|
||||
<h3 class="text-lg sm:text-xl md:text-2xl font-bold text-maroon mb-1 sm:mb-2">🏆 Prestasi dan Kegiatan (Bobot 5%)</h3>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Pencapaian dalam kompetisi akademik maupun kegiatan non-akademik menunjukkan potensi dan dedikasi</p>
|
||||
<h3 class="text-xl sm:text-2xl font-bold text-red-700 mb-2">🏆 Prestasi & Kegiatan (4%)</h3>
|
||||
<p class="text-sm text-gray-700 leading-relaxed">Pencapaian dalam kompetisi akademik maupun kegiatan non-akademik menunjukkan potensi, dedikasi, dan kepemimpinan</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -172,124 +176,124 @@
|
|||
|
||||
<!-- UNGGULAN FITUR -->
|
||||
<section class="py-8 sm:py-12 md:py-16 bg-white">
|
||||
<div class="container mx-auto px-4 sm:px-6">
|
||||
<h2 class="text-2xl sm:text-3xl md:text-4xl font-bold text-center text-maroon mb-3 sm:mb-4">Unggulan Fitur Sistem</h2>
|
||||
<p class="text-center text-xs sm:text-sm md:text-base text-gray-700 mb-8 sm:mb-12 max-w-3xl mx-auto">Sistem ini dilengkapi dengan fitur-fitur canggih untuk memberikan pengalaman terbaik dalam memilih jurusan.</p>
|
||||
<div class="w-full px-4 sm:px-6">
|
||||
<h2 class="text-2xl sm:text-3xl md:text-4xl font-bold text-center text-purple-700 mb-3 sm:mb-4">Fitur Unggulan Sistem</h2>
|
||||
<p class="text-center text-gray-600 mb-8 sm:mb-12 max-w-3xl mx-auto">Dilengkapi dengan berbagai fitur canggih untuk memberikan pengalaman terbaik dalam menemukan jurusan impianmu.</p>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 sm:gap-8">
|
||||
<div class="bg-cream p-6 sm:p-8 rounded-lg border-2 border-maroon shadow-md hover:shadow-lg transition">
|
||||
<div class="text-4xl sm:text-5xl mb-4">🤖</div>
|
||||
<h3 class="text-lg sm:text-xl font-bold text-maroon mb-2 sm:mb-3">Algoritma Naive Bayes</h3>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Menggunakan algoritma machine learning terkini untuk memberikan rekomendasi yang akurat dan terpercaya</p>
|
||||
<div class="bg-gradient-to-br from-purple-50 to-purple-100 p-8 rounded-xl border-2 border-purple-300 shadow-md hover:shadow-lg transition">
|
||||
<div class="text-5xl mb-4">🤖</div>
|
||||
<h3 class="text-lg font-bold text-purple-900 mb-3">AI Berbasis Data</h3>
|
||||
<p class="text-sm text-purple-800">Algoritma Naive Bayes terpercaya untuk analisis akurat dan rekomendasi yang dapat dipertanggungjawabkan</p>
|
||||
</div>
|
||||
<div class="bg-cream p-6 sm:p-8 rounded-lg border-2 border-maroon shadow-md hover:shadow-lg transition">
|
||||
<div class="text-4xl sm:text-5xl mb-4">📊</div>
|
||||
<h3 class="text-lg sm:text-xl font-bold text-maroon mb-2 sm:mb-3">Analisis Multi-Faktor</h3>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Menganalisis 5 aspek penting: nilai akademik, minat, preferensi studi, cita-cita, dan prestasi</p>
|
||||
<div class="bg-gradient-to-br from-blue-50 to-blue-100 p-8 rounded-xl border-2 border-blue-300 shadow-md hover:shadow-lg transition">
|
||||
<div class="text-5xl mb-4">📊</div>
|
||||
<h3 class="text-lg font-bold text-blue-900 mb-3">Analisis Komprehensif</h3>
|
||||
<p class="text-sm text-blue-800">5 aspek penting: akademik, minat, preferensi, cita-cita, dan prestasi untuk gambaran lengkap</p>
|
||||
</div>
|
||||
<div class="bg-cream p-6 sm:p-8 rounded-lg border-2 border-maroon shadow-md hover:shadow-lg transition">
|
||||
<div class="text-4xl sm:text-5xl mb-4">✨</div>
|
||||
<h3 class="text-lg sm:text-xl font-bold text-maroon mb-2 sm:mb-3">Rekomendasi Personal</h3>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Setiap siswa mendapat rekomendasi ranking jurusan yang unik sesuai dengan profil individual mereka</p>
|
||||
<div class="bg-gradient-to-br from-green-50 to-green-100 p-8 rounded-xl border-2 border-green-300 shadow-md hover:shadow-lg transition">
|
||||
<div class="text-5xl mb-4">✨</div>
|
||||
<h3 class="text-lg font-bold text-green-900 mb-3">Rekomendasi Personal</h3>
|
||||
<p class="text-sm text-green-800">Ranking jurusan unik khusus untukmu berdasarkan profil individual dan data real-time</p>
|
||||
</div>
|
||||
<div class="bg-cream p-6 sm:p-8 rounded-lg border-2 border-maroon shadow-md hover:shadow-lg transition">
|
||||
<div class="text-4xl sm:text-5xl mb-4">📝</div>
|
||||
<h3 class="text-lg sm:text-xl font-bold text-maroon mb-2 sm:mb-3">Riwayat Rekomendasi</h3>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Lacak semua rekomendasi yang telah dilakukan sebelumnya dan lihat perubahan scoring dari waktu ke waktu</p>
|
||||
<div class="bg-gradient-to-br from-amber-50 to-amber-100 p-8 rounded-xl border-2 border-amber-300 shadow-md hover:shadow-lg transition">
|
||||
<div class="text-5xl mb-4">📝</div>
|
||||
<h3 class="text-lg font-bold text-amber-900 mb-3">Riwayat Lengkap</h3>
|
||||
<p class="text-sm text-amber-800">Lacak semua analisis sebelumnya dan lihat perkembangan scoring dari waktu ke waktu</p>
|
||||
</div>
|
||||
<div class="bg-cream p-6 sm:p-8 rounded-lg border-2 border-maroon shadow-md hover:shadow-lg transition">
|
||||
<div class="text-4xl sm:text-5xl mb-4">💬</div>
|
||||
<h3 class="text-lg sm:text-xl font-bold text-maroon mb-2 sm:mb-3">Chatbot AI</h3>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Dapatkan konsultasi dan bimbingan dari chatbot berbasis AI yang siap membantu 24/7</p>
|
||||
<div class="bg-gradient-to-br from-red-50 to-red-100 p-8 rounded-xl border-2 border-red-300 shadow-md hover:shadow-lg transition">
|
||||
<div class="text-5xl mb-4">💬</div>
|
||||
<h3 class="text-lg font-bold text-red-900 mb-3">Chatbot Konsultasi</h3>
|
||||
<p class="text-sm text-red-800">Konsultasi dengan AI chatbot 24/7 untuk pertanyaan seputar jurusan dan karir</p>
|
||||
</div>
|
||||
<div class="bg-cream p-6 sm:p-8 rounded-lg border-2 border-maroon shadow-md hover:shadow-lg transition">
|
||||
<div class="text-4xl sm:text-5xl mb-4">👁️</div>
|
||||
<h3 class="text-lg sm:text-xl font-bold text-maroon mb-2 sm:mb-3">Monitoring Guru BK</h3>
|
||||
<p class="text-xs sm:text-sm md:text-base text-gray-700">Guru BK dapat memantau progress siswa dan memberikan bimbingan tambahan secara real-time</p>
|
||||
<div class="bg-gradient-to-br from-indigo-50 to-indigo-100 p-8 rounded-xl border-2 border-indigo-300 shadow-md hover:shadow-lg transition">
|
||||
<div class="text-5xl mb-4">👨🏫</div>
|
||||
<h3 class="text-lg font-bold text-indigo-900 mb-3">Monitoring Guru BK</h3>
|
||||
<p class="text-sm text-indigo-800">Guru BK dapat memantau progress siswa dan memberikan bimbingan tambahan real-time</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 9 JURUSAN TERSEDIA -->
|
||||
<section class="py-8 sm:py-12 md:py-16 bg-cream">
|
||||
<div class="container mx-auto px-4 sm:px-6">
|
||||
<h2 class="text-2xl sm:text-3xl md:text-4xl font-bold text-center text-maroon mb-3 sm:mb-4">9 Kategori Jurusan yang Bisa Dipilih</h2>
|
||||
<p class="text-center text-xs sm:text-sm md:text-base text-gray-700 mb-8 sm:mb-12 max-w-3xl mx-auto">Tersedia banyak pilihan jurusan dari berbagai bidang. Sistem ini akan menganalisis profil Anda dan merekomendasikan jurusan yang paling sesuai berdasarkan nilai, minat, dan potensi.</p>
|
||||
<section class="py-8 sm:py-12 md:py-16 bg-gray-50">
|
||||
<div class="w-full px-4 sm:px-6">
|
||||
<h2 class="text-2xl sm:text-3xl md:text-4xl font-bold text-center text-purple-700 mb-3 sm:mb-4">9 Pilihan Jurusan Polije</h2>
|
||||
<p class="text-center text-gray-600 mb-8 sm:mb-12 max-w-3xl mx-auto">Tersedia berbagai pilihan jurusan dari bidang pertanian, teknologi, kesehatan, bisnis, hingga humaniora. Temukan jurusan yang paling cocok untukmu.</p>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 sm:gap-6">
|
||||
<div class="bg-white border-2 border-maroon rounded-lg shadow-lg hover:shadow-xl transition p-5 sm:p-6">
|
||||
<div class="text-3xl sm:text-4xl mb-3">🌾</div>
|
||||
<h3 class="text-base sm:text-lg md:text-xl font-bold text-maroon mb-2">Produksi Pertanian</h3>
|
||||
<p class="text-xs sm:text-sm text-gray-700">Cocok buat yang suka bercocok tanam dan ingin meningkatkan hasil pertanian dengan metode modern.</p>
|
||||
<div class="bg-white border-t-4 border-purple-600 rounded-lg shadow-md hover:shadow-lg hover:-translate-y-1 transition p-6">
|
||||
<div class="text-4xl mb-3">🌾</div>
|
||||
<h3 class="text-lg font-bold text-purple-700 mb-2">Produksi Pertanian</h3>
|
||||
<p class="text-sm text-gray-700">Cocok untuk yang suka bercocok tanam dan ingin meningkatkan hasil dengan metode modern.</p>
|
||||
</div>
|
||||
<div class="bg-white border-2 border-maroon rounded-lg shadow-lg hover:shadow-xl transition p-5 sm:p-6">
|
||||
<div class="text-3xl sm:text-4xl mb-3">🔬</div>
|
||||
<h3 class="text-base sm:text-lg md:text-xl font-bold text-maroon mb-2">Teknologi Pertanian</h3>
|
||||
<p class="text-xs sm:text-sm text-gray-700">Belajar teknologi terkini untuk inovasi pertanian yang lebih berkelanjutan.</p>
|
||||
<div class="bg-white border-t-4 border-blue-600 rounded-lg shadow-md hover:shadow-lg hover:-translate-y-1 transition p-6">
|
||||
<div class="text-4xl mb-3">🔬</div>
|
||||
<h3 class="text-lg font-bold text-blue-700 mb-2">Teknologi Pertanian</h3>
|
||||
<p class="text-sm text-gray-700">Belajar teknologi terkini untuk inovasi pertanian yang berkelanjutan dan efisien.</p>
|
||||
</div>
|
||||
<div class="bg-white border-2 border-maroon rounded-lg shadow-lg hover:shadow-xl transition p-5 sm:p-6">
|
||||
<div class="text-3xl sm:text-4xl mb-3">🐄</div>
|
||||
<h3 class="text-base sm:text-lg md:text-xl font-bold text-maroon mb-2">Peternakan</h3>
|
||||
<p class="text-xs sm:text-sm text-gray-700">Mengelola dan mengembangkan usaha peternakan secara profesional.</p>
|
||||
<div class="bg-white border-t-4 border-green-600 rounded-lg shadow-md hover:shadow-lg hover:-translate-y-1 transition p-6">
|
||||
<div class="text-4xl mb-3">🐄</div>
|
||||
<h3 class="text-lg font-bold text-green-700 mb-2">Peternakan</h3>
|
||||
<p class="text-sm text-gray-700">Mengelola dan mengembangkan usaha peternakan dengan standar industri profesional.</p>
|
||||
</div>
|
||||
<div class="bg-white border-2 border-maroon rounded-lg shadow-lg hover:shadow-xl transition p-5 sm:p-6">
|
||||
<div class="text-3xl sm:text-4xl mb-3">💼</div>
|
||||
<h3 class="text-base sm:text-lg md:text-xl font-bold text-maroon mb-2">Manajemen Agribisnis</h3>
|
||||
<p class="text-xs sm:text-sm text-gray-700">Ideal buat yang ingin jadi entrepreneur atau manajer bisnis di bidang pertanian.</p>
|
||||
<div class="bg-white border-t-4 border-amber-600 rounded-lg shadow-md hover:shadow-lg hover:-translate-y-1 transition p-6">
|
||||
<div class="text-4xl mb-3">💼</div>
|
||||
<h3 class="text-lg font-bold text-amber-700 mb-2">Manajemen Agribisnis</h3>
|
||||
<p class="text-sm text-gray-700">Ideal untuk entrepreneur dan manajer bisnis yang tertarik di bidang pertanian modern.</p>
|
||||
</div>
|
||||
<div class="bg-white border-2 border-maroon rounded-lg shadow-lg hover:shadow-xl transition p-5 sm:p-6">
|
||||
<div class="text-3xl sm:text-4xl mb-3">💻</div>
|
||||
<h3 class="text-base sm:text-lg md:text-xl font-bold text-maroon mb-2">Teknologi Informasi</h3>
|
||||
<p class="text-xs sm:text-sm text-gray-700">Buat yang suka coding, bikin aplikasi, dan terjun ke dunia digital.</p>
|
||||
<div class="bg-white border-t-4 border-red-600 rounded-lg shadow-md hover:shadow-lg hover:-translate-y-1 transition p-6">
|
||||
<div class="text-4xl mb-3">💻</div>
|
||||
<h3 class="text-lg font-bold text-red-700 mb-2">Teknologi Informasi</h3>
|
||||
<p class="text-sm text-gray-700">Buat yang suka coding, bikin aplikasi, dan ingin terjun ke dunia teknologi digital.</p>
|
||||
</div>
|
||||
<div class="bg-white border-2 border-maroon rounded-lg shadow-lg hover:shadow-xl transition p-5 sm:p-6">
|
||||
<div class="text-3xl sm:text-4xl mb-3">⚙️</div>
|
||||
<h3 class="text-base sm:text-lg md:text-xl font-bold text-maroon mb-2">Teknik</h3>
|
||||
<p class="text-xs sm:text-sm text-gray-700">Cocok untuk yang suka mesin, desain teknik, dan sistem manufaktur.</p>
|
||||
<div class="bg-white border-t-4 border-orange-600 rounded-lg shadow-md hover:shadow-lg hover:-translate-y-1 transition p-6">
|
||||
<div class="text-4xl mb-3">⚙️</div>
|
||||
<h3 class="text-lg font-bold text-orange-700 mb-2">Teknik</h3>
|
||||
<p class="text-sm text-gray-700">Cocok untuk yang suka mesin, desain teknik, dan sistem manufaktur modern.</p>
|
||||
</div>
|
||||
<div class="bg-white border-2 border-maroon rounded-lg shadow-lg hover:shadow-xl transition p-5 sm:p-6">
|
||||
<div class="text-3xl sm:text-4xl mb-3">⚕️</div>
|
||||
<h3 class="text-base sm:text-lg md:text-xl font-bold text-maroon mb-2">Kesehatan</h3>
|
||||
<p class="text-xs sm:text-sm text-gray-700">Untuk yang ingin berkarir di bidang kesehatan dengan keterampilan praktis tinggi.</p>
|
||||
<div class="bg-white border-t-4 border-pink-600 rounded-lg shadow-md hover:shadow-lg hover:-translate-y-1 transition p-6">
|
||||
<div class="text-4xl mb-3">⚕️</div>
|
||||
<h3 class="text-lg font-bold text-pink-700 mb-2">Kesehatan</h3>
|
||||
<p class="text-sm text-gray-700">Untuk yang ingin berkarir di bidang kesehatan dengan keterampilan praktis tinggi.</p>
|
||||
</div>
|
||||
<div class="bg-white border-2 border-maroon rounded-lg shadow-lg hover:shadow-xl transition p-5 sm:p-6">
|
||||
<div class="text-3xl sm:text-4xl mb-3">🗣️</div>
|
||||
<h3 class="text-base sm:text-lg md:text-xl font-bold text-maroon mb-2">Bahasa, Komunikasi, dan Pariwisata</h3>
|
||||
<p class="text-xs sm:text-sm text-gray-700">Buat yang suka berkomunikasi, hospitality, dan dunia pariwisata.</p>
|
||||
<div class="bg-white border-t-4 border-cyan-600 rounded-lg shadow-md hover:shadow-lg hover:-translate-y-1 transition p-6">
|
||||
<div class="text-4xl mb-3">🗣️</div>
|
||||
<h3 class="text-lg font-bold text-cyan-700 mb-2">Bahasa & Pariwisata</h3>
|
||||
<p class="text-sm text-gray-700">Buat yang suka berkomunikasi, hospitality, dan dunia pariwisata internasional.</p>
|
||||
</div>
|
||||
<div class="bg-white border-2 border-maroon rounded-lg shadow-lg hover:shadow-xl transition p-5 sm:p-6">
|
||||
<div class="text-3xl sm:text-4xl mb-3">📊</div>
|
||||
<h3 class="text-base sm:text-lg md:text-xl font-bold text-maroon mb-2">Bisnis</h3>
|
||||
<p class="text-xs sm:text-sm text-gray-700">Jalan menuju karir sebagai pemimpin bisnis atau profesional manajemen.</p>
|
||||
<div class="bg-white border-t-4 border-indigo-600 rounded-lg shadow-md hover:shadow-lg hover:-translate-y-1 transition p-6">
|
||||
<div class="text-4xl mb-3">📊</div>
|
||||
<h3 class="text-lg font-bold text-indigo-700 mb-2">Bisnis</h3>
|
||||
<p class="text-sm text-gray-700">Jalan menuju karir sebagai pemimpin bisnis dan profesional manajemen terkemuka.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- HOW IT WORKS -->
|
||||
<section id="how-it-works" class="py-8 sm:py-12 md:py-16 bg-cream">
|
||||
<div class="container mx-auto px-4 sm:px-6">
|
||||
<h2 class="text-2xl sm:text-3xl md:text-4xl font-bold text-center text-maroon mb-3 sm:mb-4">Cara Menggunakan Sistem</h2>
|
||||
<p class="text-center text-xs sm:text-sm md:text-base text-gray-700 mb-8 sm:mb-12 max-w-3xl mx-auto">Empat langkah mudah untuk menemukan rekomendasi jurusan yang paling sesuai dengan profil dan impian Anda.</p>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 sm:gap-6">
|
||||
<section id="how-it-works" class="py-8 sm:py-12 md:py-16 bg-white">
|
||||
<div class="w-full px-4 sm:px-6">
|
||||
<h2 class="text-2xl sm:text-3xl md:text-4xl font-bold text-center text-purple-700 mb-3 sm:mb-4">Empat Langkah Mudah</h2>
|
||||
<p class="text-center text-gray-600 mb-8 sm:mb-12 max-w-3xl mx-auto">Proses yang sederhana namun powerful untuk menemukan rekomendasi jurusan yang paling sesuai dengan profil dan impian Anda.</p>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6 sm:gap-8">
|
||||
<div class="text-center">
|
||||
<div class="bg-maroon text-white rounded-full w-16 h-16 sm:w-20 sm:h-20 mx-auto mb-3 sm:mb-4 flex items-center justify-center text-2xl sm:text-3xl font-bold">1</div>
|
||||
<h3 class="text-base sm:text-lg md:text-xl font-bold text-maroon mb-2 sm:mb-3">Daftar Akun</h3>
|
||||
<p class="text-xs sm:text-sm text-gray-700">Buat akun menggunakan email, NIS, dan data diri</p>
|
||||
<div class="bg-gradient-to-br from-purple-600 to-indigo-600 text-white rounded-full w-16 h-16 sm:w-20 sm:h-20 mx-auto mb-4 sm:mb-6 flex items-center justify-center text-2xl sm:text-3xl font-bold shadow-lg">1</div>
|
||||
<h3 class="text-lg font-bold text-purple-700 mb-3">Buat Akun</h3>
|
||||
<p class="text-sm text-gray-600 leading-relaxed">Daftar dengan email, NIS, dan data diri lengkap Anda</p>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<div class="bg-maroon text-white rounded-full w-16 h-16 sm:w-20 sm:h-20 mx-auto mb-3 sm:mb-4 flex items-center justify-center text-2xl sm:text-3xl font-bold">2</div>
|
||||
<h3 class="text-base sm:text-lg md:text-xl font-bold text-maroon mb-2 sm:mb-3">Isi Data</h3>
|
||||
<p class="text-xs sm:text-sm text-gray-700">Lengkapi 5 aspek penting pada profil Anda</p>
|
||||
<div class="bg-gradient-to-br from-blue-600 to-purple-600 text-white rounded-full w-16 h-16 sm:w-20 sm:h-20 mx-auto mb-4 sm:mb-6 flex items-center justify-center text-2xl sm:text-3xl font-bold shadow-lg">2</div>
|
||||
<h3 class="text-lg font-bold text-blue-700 mb-3">Isi Kuis</h3>
|
||||
<p class="text-sm text-gray-600 leading-relaxed">Jawab 5 aspek penting tentang akademik, minat, dan aspirasi</p>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<div class="bg-maroon text-white rounded-full w-16 h-16 sm:w-20 sm:h-20 mx-auto mb-3 sm:mb-4 flex items-center justify-center text-2xl sm:text-3xl font-bold">3</div>
|
||||
<h3 class="text-base sm:text-lg md:text-xl font-bold text-maroon mb-2 sm:mb-3">Proses AI</h3>
|
||||
<p class="text-xs sm:text-sm text-gray-700">Sistem memproses data Anda dengan algoritma yang terstruktur</p>
|
||||
<div class="bg-gradient-to-br from-green-600 to-emerald-600 text-white rounded-full w-16 h-16 sm:w-20 sm:h-20 mx-auto mb-4 sm:mb-6 flex items-center justify-center text-2xl sm:text-3xl font-bold shadow-lg">3</div>
|
||||
<h3 class="text-lg font-bold text-green-700 mb-3">Analisis AI</h3>
|
||||
<p class="text-sm text-gray-600 leading-relaxed">Sistem memproses data dengan algoritma Naive Bayes canggih</p>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<div class="bg-maroon text-white rounded-full w-16 h-16 sm:w-20 sm:h-20 mx-auto mb-3 sm:mb-4 flex items-center justify-center text-2xl sm:text-3xl font-bold">4</div>
|
||||
<h3 class="text-base sm:text-lg md:text-xl font-bold text-maroon mb-2 sm:mb-3">Lihat Hasil</h3>
|
||||
<p class="text-xs sm:text-sm text-gray-700">Dapatkan ranking jurusan dengan skor kecocokan detail</p>
|
||||
<div class="bg-gradient-to-br from-amber-600 to-orange-600 text-white rounded-full w-16 h-16 sm:w-20 sm:h-20 mx-auto mb-4 sm:mb-6 flex items-center justify-center text-2xl sm:text-3xl font-bold shadow-lg">4</div>
|
||||
<h3 class="text-lg font-bold text-amber-700 mb-3">Lihat Hasil</h3>
|
||||
<p class="text-sm text-gray-600 leading-relaxed">Dapatkan ranking 9 jurusan dengan skor dan analisis detail</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -297,43 +301,45 @@
|
|||
|
||||
<!-- CALL TO ACTION -->
|
||||
<section class="py-8 sm:py-12 md:py-16 gradient-maroon text-white">
|
||||
<div class="container mx-auto px-4 sm:px-6 text-center">
|
||||
<h2 class="text-2xl sm:text-3xl md:text-4xl font-bold mb-4 sm:mb-6">Temukan Jurusan Polije yang Paling Cocok</h2>
|
||||
<p class="text-sm sm:text-base md:text-lg mb-6 sm:mb-8 text-yellow-100 max-w-2xl mx-auto">Gunakan sistem ini untuk memperoleh rekomendasi jurusan Politeknik Negeri Jember yang akurat berdasarkan nilai, minat, dan cita-cita Anda.</p>
|
||||
<div class="flex flex-col sm:flex-row gap-3 sm:gap-4 justify-center">
|
||||
<a href="{{ route('register') }}" class="inline-block bg-yellow-400 text-maroon font-bold py-2 sm:py-3 px-6 sm:px-10 rounded-lg hover:bg-yellow-300 transition text-sm sm:text-base text-center">Daftar Sekarang</a>
|
||||
<a href="{{ route('login') }}" class="inline-block border-2 border-yellow-400 text-yellow-300 font-bold py-2 sm:py-3 px-6 sm:px-10 rounded-lg hover:bg-yellow-400 hover:text-maroon transition text-sm sm:text-base text-center">Login</a>
|
||||
<div class="w-full px-4 sm:px-6 text-center">
|
||||
<h2 class="text-2xl sm:text-3xl md:text-4xl font-bold mb-4 sm:mb-6">Mulai Temukan Jurusan Impianmu</h2>
|
||||
<p class="text-sm sm:text-base md:text-lg mb-8 sm:mb-10 text-purple-100 max-w-2xl mx-auto leading-relaxed">Jangan biarkan pilihan jurusan menjadi keputusan buru-buru. Gunakan sistem kami yang telah terbukti akurat untuk menemukan jurusan Politeknik Negeri Jember yang paling sesuai dengan potensi dan impianmu.</p>
|
||||
<div class="flex flex-col sm:flex-row gap-4 sm:gap-6 justify-center">
|
||||
<a href="{{ route('register') }}" class="inline-block bg-white text-purple-700 font-bold py-3 sm:py-4 px-8 sm:px-12 rounded-lg hover:shadow-lg hover:bg-purple-50 transition text-base shadow-lg">Daftar Sekarang</a>
|
||||
<a href="{{ route('login') }}" class="inline-block border-2 border-white text-white font-bold py-3 sm:py-4 px-8 sm:px-12 rounded-lg hover:bg-white hover:text-purple-700 transition text-base">Login</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FOOTER -->
|
||||
<footer class="gradient-maroon text-white py-8 sm:py-12">
|
||||
<div class="container mx-auto px-4 sm:px-6 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6 sm:gap-8">
|
||||
<div>
|
||||
<h3 class="text-base sm:text-lg font-bold text-yellow-400 mb-3 sm:mb-4">Untuk Siswa SMA Bima Ambulu</h3>
|
||||
<p class="text-xs sm:text-sm text-yellow-100">Sistem ini dikembangkan khusus untuk membantu siswa SMA Bima Ambulu menemukan jurusan Politeknik Negeri Jember yang paling sesuai dengan minat dan kemampuan.</p>
|
||||
<div class="w-full px-4 sm:px-6">
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6 sm:gap-8 max-w-5xl mx-auto mb-8">
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-white mb-3 sm:mb-4">Tentang Sistem</h3>
|
||||
<p class="text-sm text-purple-100 leading-relaxed">SPK Jurusan adalah sistem pendukung keputusan berbasis AI yang membantu siswa menemukan jurusan yang paling sesuai dengan profil akademis, minat, dan aspirasi karir mereka.</p>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-white mb-3 sm:mb-4">Kontak</h3>
|
||||
<ul class="text-sm text-purple-100 space-y-2">
|
||||
<li><strong>Email:</strong> <a href="mailto:info@spkjurusan.com" class="hover:text-white">info@spkjurusan.com</a></li>
|
||||
<li><strong>Telepon:</strong> (0331) 123456</li>
|
||||
<li><strong>Lokasi:</strong> <span class="block text-xs">Politeknik Negeri Jember<br/>Jawa Timur, Indonesia</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-white mb-3 sm:mb-4">Menu</h3>
|
||||
<ul class="text-sm text-purple-100 space-y-2">
|
||||
<li><a href="{{ route('login') }}" class="hover:text-white transition">Login</a></li>
|
||||
<li><a href="{{ route('register') }}" class="hover:text-white transition">Daftar</a></li>
|
||||
<li><a href="#how-it-works" class="hover:text-white transition">Cara Pakai</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-base sm:text-lg font-bold text-yellow-400 mb-3 sm:mb-4">Kontak SMA Bima Ambulu</h3>
|
||||
<ul class="text-xs sm:text-sm text-yellow-100 space-y-1 sm:space-y-2">
|
||||
<li><strong>Email:</strong> <a href="mailto:smabima@gmail.com" class="hover:text-yellow-300">smabima@gmail.com</a></li>
|
||||
<li><strong>Telepon:</strong> (0331) 123456</li>
|
||||
<li><strong>Lokasi:</strong> <span class="block text-xs">Jl. Pendidikan No. 1<br/>Ambulu, Jember, Jawa Timur</span></li>
|
||||
</ul>
|
||||
<div class="border-t border-purple-400 pt-6 text-center text-sm text-purple-100">
|
||||
<p>© 2026 SPK Jurusan Polije - Semua Hak Dilindungi</p>
|
||||
<p class="mt-2 text-xs text-purple-200">Membantu Siswa Menemukan Jurusan yang Tepat untuk Masa Depan Cemerlang</p>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-base sm:text-lg font-bold text-yellow-400 mb-3 sm:mb-4">Menu</h3>
|
||||
<ul class="text-xs sm:text-sm text-yellow-100 space-y-1 sm:space-y-2">
|
||||
<li><a href="{{ route('login') }}" class="hover:text-yellow-300">Login</a></li>
|
||||
<li><a href="{{ route('register') }}" class="hover:text-yellow-300">Daftar Sekarang</a></li>
|
||||
<li><a href="#how-it-works" class="hover:text-yellow-300">Cara Pakai</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="border-t border-yellow-300 mt-6 sm:mt-8 pt-4 sm:pt-6 text-center text-xs sm:text-sm text-yellow-100">
|
||||
<p>© 2026 Sistem Pemilihan Jurusan</p>
|
||||
<p class="mt-1 sm:mt-2">Membantu Siswa SMA Bima Ambulu Memilih Jurusan Politeknik Negeri Jember yang Tepat</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,14 @@
|
|||
});
|
||||
|
||||
Route::get('/dashboard', function () {
|
||||
return view('dashboard');
|
||||
$user = Auth::user();
|
||||
$recommendationCount = $user ? \App\Models\Recommendation::where('user_id', $user->id)->count() : 0;
|
||||
$chatCount = $user ? \App\Models\ChatHistory::where('user_id', $user->id)->count() : 0;
|
||||
|
||||
return view('dashboard', [
|
||||
'recommendationCount' => $recommendationCount,
|
||||
'chatCount' => $chatCount
|
||||
]);
|
||||
})->middleware(['auth', 'verified', 'roleRedirect'])->name('dashboard');
|
||||
|
||||
Route::middleware('auth')->group(function () {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,29 @@ export default {
|
|||
fontFamily: {
|
||||
sans: ['Figtree', ...defaultTheme.fontFamily.sans],
|
||||
},
|
||||
colors: {
|
||||
// Soft, eye-friendly color palette
|
||||
'slate': {
|
||||
50: '#F8FAFC',
|
||||
100: '#F1F5F9',
|
||||
200: '#E2E8F0',
|
||||
300: '#CBD5E1',
|
||||
400: '#94A3B8',
|
||||
500: '#64748B',
|
||||
600: '#475569',
|
||||
700: '#334155',
|
||||
},
|
||||
'stone': {
|
||||
50: '#FAFAF9',
|
||||
100: '#F5F5F4',
|
||||
200: '#E7E5E4',
|
||||
300: '#D6D3D1',
|
||||
400: '#A8A29E',
|
||||
500: '#78716C',
|
||||
600: '#57534E',
|
||||
700: '#44403C',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
require 'vendor/autoload.php';
|
||||
require 'bootstrap/app.php';
|
||||
|
||||
$app = require_once 'bootstrap/app.php';
|
||||
$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class);
|
||||
$kernel->bootstrap();
|
||||
|
||||
use App\Models\Alumni;
|
||||
|
||||
$alumni = Alumni::select('nama_alumni', 'kelompok_asal', 'nilai_rata_rata', 'major_masuk')->limit(5)->get();
|
||||
|
||||
echo "=== ALUMNI DATA ===\n\n";
|
||||
foreach($alumni as $a) {
|
||||
echo $a->nama_alumni . " | " . $a->kelompok_asal . " | " . $a->nilai_rata_rata . " | " . $a->major_masuk . "\n";
|
||||
}
|
||||
|
||||
echo "\nTotal Alumni: " . Alumni::count() . "\n";
|
||||
echo "With nilai_rata_rata: " . Alumni::whereNotNull('nilai_rata_rata')->count() . "\n";
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
require 'vendor/autoload.php';
|
||||
$app = require_once 'bootstrap/app.php';
|
||||
$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
|
||||
|
||||
use App\Models\Alumni;
|
||||
|
||||
$count = Alumni::count();
|
||||
$alumni = Alumni::latest()->take(5)->get(['nama_alumni', 'minat', 'cita_cita', 'preferensi_studi', 'major_masuk']);
|
||||
|
||||
echo "Total Alumni in Database: $count\n\n";
|
||||
echo "=== Last 5 Imported Alumni ===\n";
|
||||
foreach ($alumni as $a) {
|
||||
echo "- {$a->nama_alumni}\n Minat: {$a->minat}\n Cita-cita: {$a->cita_cita}\n Preferensi: {$a->preferensi_studi}\n Major Masuk: {$a->major_masuk}\n\n";
|
||||
}
|
||||
?>
|
||||
Loading…
Reference in New Issue