Compare commits

..

10 Commits

Author SHA1 Message Date
gitaysn 0770f9dd6e gatau 2025-06-27 01:25:16 +07:00
gitaysn 1365a65409 update 2025-06-17 20:19:21 +07:00
gitaysn 45115b3367 Update master.blade.php 2025-06-08 16:32:22 +07:00
HANIF FEBRIANSYAH da5aa3bdd8
Merge pull request #3 from hanzhighmekaniq/main
Naaanti
2025-06-06 13:35:34 +07:00
HANIF FEBRIANSYAH a55372b36c Naaanti 2025-06-06 13:33:31 +07:00
gitaysn 75eec90d30 insyallah fix 2025-06-01 15:37:32 +07:00
HANIF FEBRIANSYAH 5f533f279b
Merge pull request #2 from hanzhighmekaniq/main
Perbaikan
2025-05-27 16:06:36 +07:00
HANIF FEBRIANSYAH 9bb045671f Perbaikan 2025-05-27 12:43:35 +07:00
gitaysn d31dc31bce iya 2025-05-26 15:48:44 +07:00
gitaysn 1ba7bd9e4a kurang 2025-05-26 05:40:47 +07:00
94 changed files with 5253 additions and 2278 deletions

View File

@ -22,7 +22,7 @@ class AuthController extends Controller
$credentials = $request->only('username', 'password');
if (Auth::attempt($credentials)) {
return redirect()->route('dashboard');
return redirect()->route('admin.dashboard');
}
return back()->withErrors(['login' => 'Username atau password salah.']);

View File

@ -20,6 +20,19 @@ class DashboardController extends Controller
$totalKriteria = Kriteria::count();
$totalSubKriteria = Subkriteria::count();
return view("admin.pages.dashboard.index", compact("totalPakaian", "totalKriteria", "totalSubKriteria"));
// Dapatkan jumlah penilaian berdasarkan kriteria
$dataPenilaianPerKriteria = Kriteria::with('subKriteria.penilaians')->get()->map(function ($kriteria) {
return [
'label' => $kriteria->nama_kriteria, // sesuaikan jika nama kolomnya ini
'jumlah' => $kriteria->subKriteria->sum(fn($sub) => $sub->penilaians->count())
];
});
return view('admin.pages.dashboard.index', compact(
'totalKriteria',
'totalSubKriteria',
'totalPakaian',
'dataPenilaianPerKriteria'
));
}
}

View File

@ -0,0 +1,39 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
use App\Http\Controllers\Controller;
class ForgotUsernameController extends Controller
{
// Tampilkan form lupa username
public function showForm()
{
return view('admin.pages.auth.forgot-username');
}
// Proses kirim username ke email
public function sendUsername(Request $request)
{
$request->validate([
'email' => 'required|email|exists:users,email',
]);
$user = User::where('email', $request->email)->first();
if (!$user) {
return back()->withErrors(['email' => 'Email tidak ditemukan.']);
}
Mail::send('emails.username-reminder', ['user' => $user], function ($message) use ($user) {
$message->to($user->email);
$message->subject('Pengingat Username Anda');
});
return back()->with('status', 'Username telah dikirim ke email Anda.');
}
}

View File

@ -1,35 +0,0 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\QuizHistory;
use Illuminate\Http\Request;
// ... other use
class RiwayatController extends Controller
{
public function index(Request $request)
{
$perPage = $request->get('per_page', 5); // Ambil dari query string, default 10
$riwayat = QuizHistory::orderBy('created_at', 'desc')
->paginate($perPage)
->withQueryString(); // penting agar per_page tetap ada saat klik pagination
return view('admin.pages.riwayat.index', compact('riwayat'));
}
public function destroy($id)
{
try {
$riwayat = QuizHistory::findOrFail($id);
$riwayat->delete();
return redirect()->back()->with('success', 'Riwayat berhasil dihapus.');
} catch (\Exception $e) {
return redirect()->back()->with('error', 'Gagal menghapus riwayat.');
}
}
}

View File

@ -2,168 +2,368 @@
namespace App\Http\Controllers\Landingpage;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\DataAlternatif;
use App\Models\Pakaian;
use App\Models\Kriteria;
use App\Models\QuizHistory;
use App\Models\Subkriteria;
use App\Models\SubKriteria;
use Illuminate\Support\Arr;
use Illuminate\Http\Request;
use App\Models\DataAlternatif;
use App\Models\PenilaianPakaian;
use Illuminate\Support\Facades\Log;
use App\Http\Controllers\Controller;
class HomeController extends Controller
{
public function index()
{
$kriteria = Kriteria::with('subkriteria')->get();
// Mengambil semua subkriteria beserta relasi kriterianya, lalu mengelompokkan berdasarkan nama kriteria
$subKriteria = SubKriteria::with('kriteria')->get()->groupBy(function ($item) {
return $item->kriteria->nama_kriteria;
});
return view('landingpage.home', [
'skorAkhir' => $this->getSkorAkhirByJenis('Dress'),
'blouseSkorAkhir' => $this->getSkorAkhirByJenis('Blouse'),
'cardiganSkorAkhir' => $this->getSkorAkhirByJenis('Cardigan'),
'rokSkorAkhir' => $this->getSkorAkhirByJenis('Rok'),
'celanaSkorAkhir' => $this->getSkorAkhirByJenis('Celana'),
'kriteria' => $kriteria
// Mengambil semua data pakaian beserta relasi ke subkriteria
$pakaians = Pakaian::with('subKriterias')->get();
return view('landingpage.master', [
'subKriteria' => $subKriteria,
'pakaians' => $pakaians
]);
}
public function dress() { return $this->showJenisPakaian('Dress'); }
public function blouse() { return $this->showJenisPakaian('Blouse'); }
public function cardigan() { return $this->showJenisPakaian('Cardigan'); }
public function rok() { return $this->showJenisPakaian('Rok'); }
public function celana() { return $this->showJenisPakaian('Celana'); }
private function showJenisPakaian($jenis, $preferensi = [])
public function prosesRekomendasi(Request $request)
{
$skorAkhir = $this->getSkorAkhirByJenis($jenis, $preferensi);
$alternatif = DataAlternatif::whereHas('penilaian.subkriteria', fn($q) => $q->where('nama_subkriteria', $jenis))->get();
$kriteria = Kriteria::with('subkriteria')->get();
// Memproses input pengguna dari form
$userInput = $this->processUserInput($request->input('sub_kriteria', []));
return view('landingpage.rekomendasi', compact('alternatif', 'kriteria', 'jenis', 'skorAkhir', 'preferensi'));
// Jika tidak ada input yang valid, tampilkan pesan error
if (empty($userInput)) {
return $this->returnNoResults('Silakan pilih minimal satu kriteria.');
}
// \Log::debug('User Input:', $userInput);
// Mengambil data subkriteria berdasarkan input user
$selectedSubkriteria = SubKriteria::whereIn('id', collect($userInput)->flatten())
->get()
->keyBy('id');
// Menyusun input berdasarkan jenis kriteria
$criteriaInputs = $this->extractCriteriaInputs($userInput, $selectedSubkriteria);
// Filter ketat berdasarkan input wajib
$filteredClothing = $this->applyStrictFiltering($criteriaInputs);
// Jika tidak ada hasil setelah filter, tampilkan pesan
if ($filteredClothing->isEmpty()) {
return $this->returnNoResults('Tidak ada pakaian yang sesuai dengan kriteria yang Anda pilih.');
}
// Hitung rekomendasi menggunakan metode SAW
$recommendations = $this->calculateRecommendations($filteredClothing, $userInput);
return view('landingpage.hasil', compact('recommendations'));
}
private function getSkorAkhirByJenis($jenis, $preferensi = [])
/**
* Process and validate user input
*/
private function processUserInput(array $userInput): array
{
$alternatif = DataAlternatif::with(['penilaian.subkriteria', 'penilaian.kriteria'])
->whereHas('penilaian.subkriteria', function ($query) use ($jenis) {
$query->where('nama_subkriteria', $jenis);
})
$processedInput = [];
foreach ($userInput as $kriteria_id => $subkriteria) {
$subkriteriaArray = (array) $subkriteria;
// Buang nilai kosong dan pastikan hanya angka yang valid
$cleanedSubkriteria = array_filter($subkriteriaArray, function($value) {
return !empty($value) && is_numeric($value);
});
// Simpan hanya jika ada nilai yang valid
if (!empty($cleanedSubkriteria)) {
$processedInput[$kriteria_id] = array_map('intval', $cleanedSubkriteria);
}
}
return $processedInput;
}
/**
* Extract and organize criteria inputs
*/
private function extractCriteriaInputs(array $userInput, $selectedSubkriteria): array
{
$inputs = [
'warna' => $userInput[1] ?? [], // Criteria 1: Color
'harga' => $userInput[2] ?? [], // Criteria 2: Price
'jenis_pakaian' => $userInput[3] ?? [], // Criteria 3: Clothing Type
'jenis_acara' => $userInput[4] ?? [], // Criteria 4: Event Type
'lokasi' => $userInput[5] ?? [] // Criteria 5: Location
];
// Jika kriteria harga dipilih, hitung rentang harga min dan max
if (!empty($inputs['harga'])) {
$hargaRanges = $selectedSubkriteria->only($inputs['harga']);
$inputs['harga_min'] = $hargaRanges->min('min_value');
$inputs['harga_max'] = $hargaRanges->max('max_value');
}
// \Log::debug("Extracted Criteria Inputs:", $inputs);
return $inputs;
}
/**
* Apply strict filtering based on mandatory criteria
*/
private function applyStrictFiltering(array $criteriaInputs)
{
$query = Pakaian::with(['penilaian.subkriteria.kriteria']);
// Filter berdasarkan jenis pakaian (wajib)
if (!empty($criteriaInputs['jenis_pakaian'])) {
// \Log::debug('Applying clothing type filter:', $criteriaInputs['jenis_pakaian']);
$query->whereHas('penilaian.subkriteria', function ($q) use ($criteriaInputs) {
$q->where('kriteria_id', 3)
->whereIn('id', $criteriaInputs['jenis_pakaian']);
});
}
// Filter berdasarkan harga jika ada
if (isset($criteriaInputs['harga_min']) && isset($criteriaInputs['harga_max'])) {
// \Log::debug("Applying price filter: {$criteriaInputs['harga_min']} - {$criteriaInputs['harga_max']}");
$query->whereHas('penilaian.subkriteria', function ($q) use ($criteriaInputs) {
$q->where('kriteria_id', 2)
->where('min_value', '<=', $criteriaInputs['harga_max'])
->where('max_value', '>=', $criteriaInputs['harga_min']);
});
}
$filteredClothing = $query->get();
// Validasi hasil filter agar benar-benar sesuai
$this->validateFilterResults($filteredClothing, $criteriaInputs);
// \Log::debug('Filtered clothing count: ' . $filteredClothing->count());
return $filteredClothing;
}
/**
* Validate that filtering worked correctly
*/
private function validateFilterResults($clothing, array $criteriaInputs): void
{
if (!empty($criteriaInputs['jenis_pakaian'])) {
foreach ($clothing as $item) {
$clothingTypeAssessment = $item->penilaian
->where('subkriteria.kriteria_id', 3)
->first();
if (!$clothingTypeAssessment ||
!in_array($clothingTypeAssessment->sub_kriteria_id, $criteriaInputs['jenis_pakaian'])) {
// \Log::error("❌ Filter validation failed for clothing: {$item->nama}");
}
}
}
}
/**
* Calculate recommendations using SAW method
*/
private function calculateRecommendations($clothing, array $userInput): \Illuminate\Support\Collection
{
// Ambil data kriteria dan bobotnya
$criteria = Kriteria::with('subkriteria')
->whereIn('id', [1, 2, 3, 4, 5])
->orderByDesc('bobot') // Order by weight (highest first)
->get();
$kriteria = Kriteria::with('subkriteria')->get();
$skorAkhir = [];
// Susun decision matrix
$decisionMatrix = $this->buildDecisionMatrix($clothing, $criteria, $userInput);
foreach ($alternatif as $alt) {
$total = 0;
foreach ($kriteria as $k) {
$penilaian = $alt->penilaian->where('kriteria_id', $k->id)->first();
if (!$penilaian) continue;
// Hitung nilai normalisasi (min & max)
$normalizationValues = $this->calculateNormalizationValues($decisionMatrix, $criteria);
$nilaiAlt = $penilaian->subkriteria->nilai;
$nilaiPref = $preferensi[$this->mapKriteriaKey($k->nama_kriteria)]['nilai'] ?? $nilaiAlt;
// Hitung skor preferensi
$results = $this->calculatePreferenceScores(
$clothing,
$decisionMatrix,
$criteria,
$normalizationValues,
$userInput
);
$normalisasi = 1 - abs($nilaiAlt - $nilaiPref);
$total += $normalisasi * $k->bobot;
}
// Urutkan hasil berdasarkan skor
$recommendations = collect($results)
->sortByDesc('score')
->values();
$skorAkhir[] = [
'alternatif' => $alt,
'skor' => round($total, 3),
];
}
$this->logFinalRecommendations($recommendations);
usort($skorAkhir, fn($a, $b) => $b['skor'] <=> $a['skor']);
return $skorAkhir;
return $recommendations;
}
private function mapKriteriaKey($nama)
/**
* Build decision matrix for each clothing item
*/
private function buildDecisionMatrix($clothing, $criteria, array $userInput): array
{
$nama = strtolower($nama);
return match ($nama) {
'harga', 'cost' => 'harga',
'jenis pakaian' => 'jenis',
'warna pakaian' => 'warna',
'lokasi acara' => 'lokasi',
'cuaca acara' => 'cuaca',
'jenis acara' => 'acara',
default => str_replace(' ', '_', $nama),
};
}
$matrix = [];
public function simpankuisionerdanrekomendasi(Request $request)
{
try {
$validated = $request->validate([
'jenis_acara' => 'required|string',
'harga' => 'required|string',
'jenis_pakaian' => 'required|string',
'warna' => 'required|string',
'cuaca' => 'required|string',
'lokasi' => 'required|string',
]);
foreach ($clothing as $item) {
$matrix[$item->id] = [];
// Kumpulkan preferensi untuk diproses
$jawaban = [
'jenis_acara' => $validated['jenis_acara'],
'harga' => $validated['harga'],
'warna' => $validated['warna'],
'cuaca' => $validated['cuaca'],
'lokasi' => $validated['lokasi'],
];
foreach ($criteria as $criterion) {
$userSubIds = $userInput[$criterion->id] ?? [];
$preferensi = $this->prosesPreferensiBerdasarkanSubkriteria($jawaban);
$skorAkhir = $this->getSkorAkhirByJenis($validated['jenis_pakaian'], $preferensi);
if (empty($userSubIds)) {
continue; // Skip criteria not selected by user
}
// Simpan ke database
$quizHistory = new QuizHistory();
$quizHistory->data_kuisioner = json_encode($jawaban);
$quizHistory->hasil_rekomendasi = json_encode($skorAkhir);
$quizHistory->save();
// Ambil penilaian yang sesuai
$matchingAssessments = $item->penilaian->filter(function ($assessment) use ($userSubIds) {
return in_array($assessment->sub_kriteria_id, $userSubIds);
});
return $this->showJenisPakaian($validated['jenis_pakaian'], $preferensi);
if ($matchingAssessments->isNotEmpty()) {
// Gunakan nilai rata-rata (kecuali jenis pakaian, cukup satu)
$value = ($criterion->id == 3)
? $matchingAssessments->first()->nilai
: $matchingAssessments->avg('nilai');
} catch (\Exception $e) {
Log::error('Error simpan kuis: ' . $e->getMessage());
return back()->with('error', 'Terjadi kesalahan. Silakan coba lagi.');
}
}
$matrix[$item->id][$criterion->id] = $value;
private function prosesPreferensiBerdasarkanSubkriteria($jawaban)
{
$preferensi = [];
foreach ($jawaban as $nama_kriteria => $nama_subkriteria) {
$kriteria = Kriteria::where('nama_kriteria', $nama_kriteria)->first();
$subkriteria = Subkriteria::where('nama_subkriteria', $nama_subkriteria)
->where('kriteria_id', $kriteria->id ?? null)
->first();
if ($kriteria && $subkriteria) {
$key = $this->mapKriteriaKey($kriteria->nama_kriteria);
$preferensi[$key] = [
'value' => $subkriteria->nama_subkriteria,
'nilai' => $subkriteria->nilai,
'bobot' => $kriteria->bobot
];
if ($key === 'harga') {
$preferensi[$key]['range'] = $subkriteria->nama_subkriteria;
// \Log::debug("Item {$item->id} - Criterion {$criterion->id}: {$value}");
}
}
}
return $preferensi;
return $matrix;
}
// Menampilkan form kuis
public function showKuis($jenis = 'Dress')
/**
* Calculate min/max values for normalization
*/
private function calculateNormalizationValues(array $decisionMatrix, $criteria): array
{
$kriteria = Kriteria::with(['subkriteria' => function($query) {
$query->orderBy('nilai', 'desc');
}])->get();
$values = ['max' => [], 'min' => []];
return view('landingpage.pilihpakaian', compact('kriteria', 'jenis'));
foreach ($criteria as $criterion) {
$criterionValues = collect($decisionMatrix)
->pluck($criterion->id)
->filter(function($value) {
return $value !== null && $value > 0;
});
if ($criterionValues->isNotEmpty()) {
$values['max'][$criterion->id] = $criterionValues->max();
$values['min'][$criterion->id] = $criterionValues->min();
} else {
// Fallback values
$values['max'][$criterion->id] = 1;
$values['min'][$criterion->id] = 1;
}
// \Log::debug("Criterion {$criterion->id} normalization - Max: {$values['max'][$criterion->id]}, Min: {$values['min'][$criterion->id]}");
}
return $values;
}
/**
* Calculate final preference scores using SAW method
*/
private function calculatePreferenceScores($clothing, array $decisionMatrix, $criteria, array $normValues, array $userInput): array
{
$results = [];
foreach ($clothing as $item) {
$preferenceScore = 0;
$totalWeight = 0;
foreach ($criteria as $criterion) {
$userSubIds = $userInput[$criterion->id] ?? [];
if (empty($userSubIds) || !isset($decisionMatrix[$item->id][$criterion->id])) {
continue;
}
$value = $decisionMatrix[$item->id][$criterion->id];
if ($value <= 0) continue;
// Normalisasi nilai sesuai jenis kriteria (benefit atau cost)
$normalizedValue = $this->normalizeValue(
$value,
$normValues['max'][$criterion->id],
$normValues['min'][$criterion->id],
$criterion->jenis
);
// Hitung skor kontribusi berdasarkan bobot
$weight = $criterion->bobot;
$contribution = $normalizedValue * $weight;
$preferenceScore += $contribution;
$totalWeight += $weight;
// \Log::debug("Item {$item->id} - Criterion {$criterion->id}: Value={$value}, Normalized={$normalizedValue}, Weight={$weight}, Contribution={$contribution}");
}
// Ambil nama jenis pakaian untuk ditampilkan
$clothingType = $item->penilaian
->firstWhere('subkriteria.kriteria_id', 3)
?->subkriteria->nama ?? 'Lainnya';
$results[] = [
'pakaian' => $item,
'score' => round($preferenceScore, 4),
'jenis_pakaian' => $clothingType,
'total_weight' => $totalWeight
];
// \Log::debug("📊 Final Score - Item {$item->id} ({$item->nama}): {$preferenceScore}");
}
return $results;
}
/**
* Normalize value based on criterion type (BENEFIT/COST)
*/
private function normalizeValue(float $value, float $max, float $min, string $type): float
{
if ($type === 'COST') {
return $value > 0 ? $min / $value : 0;
} else {
return $max > 0 ? $value / $max : 0;
}
}
/**
* Log final recommendations
*/
private function logFinalRecommendations($recommendations): void
{
// \Log::debug('🏆 FINAL RECOMMENDATIONS:');
foreach ($recommendations as $index => $item) {
$rank = $index + 1;
// \Log::debug("{$rank}. {$item['pakaian']->nama} - Score: {$item['score']} - Type: {$item['jenis_pakaian']}");
}
}
/**
* Return view with no results message
*/
private function returnNoResults(string $message)
{
return view('landingpage.hasil', [
'recommendations' => collect([]),
'message' => $message
]);
}
}

View File

@ -2,9 +2,12 @@
namespace App\Http\Controllers;
use App\Models\Kriteria;
use App\Models\Pakaian;
use App\Models\Kriteria;
use App\Models\SubKriteria;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
class PakaianController extends Controller
{
@ -31,11 +34,14 @@ class PakaianController extends Controller
/**
* Show the form for creating a new resource.
*/
public function create()
{
//
$kriterias = Kriteria::with('subKriteria')->get(); // load kriteria + sub_kriterias
return view('admin.pages.pakaian.create', compact('kriterias'));
}
/**
* Store a newly created resource in storage.
*/
@ -45,23 +51,68 @@ class PakaianController extends Controller
'nama_pakaian' => 'required|string|max:255',
'harga' => 'required|numeric',
'img' => 'nullable|image|max:2048',
'deskripsi' => 'nullable|string|max:1000',
'sub_kriterias' => 'nullable|array',
'sub_kriterias.*' => 'integer',
]);
$imgPath = null;
if ($request->hasFile('img')) {
$imgPath = $request->file('img')->store('uploads/pakaian', 'public');
DB::beginTransaction();
try {
// Upload image jika ada
$path = null;
if ($request->hasFile('img')) {
$path = $request->file('img')->store('pakaian', 'public');
}
// Simpan pakaian
$pakaian = Pakaian::create([
'nama_pakaian' => $request->nama_pakaian,
'harga' => $request->harga,
'img' => $path ? 'storage/' . $path : null,
'deskripsi' => $request->deskripsi,
]);
$inputSub = $request->input('sub_kriterias', []);
$subkriteriaIds = [];
foreach ($inputSub as $key => $value) {
if (is_array($value)) {
$subkriteriaIds = array_merge($subkriteriaIds, $value);
} else {
$subkriteriaIds[] = $value;
}
}
$pakaian->subKriterias()->sync($subkriteriaIds);
// Tambahkan penilaian default untuk semua subkriteria
$allSubkriterias = SubKriteria::all();
foreach ($allSubkriterias as $sub) {
\App\Models\PenilaianPakaian::firstOrCreate([
'pakaian_id' => $pakaian->id,
'sub_kriteria_id' => $sub->id,
], [
'nilai' => 3 // bisa disesuaikan nilai defaultnya
]);
}
DB::commit();
return redirect()->route('admin.pakaian.index', ['page' => $request->input('page')])
->with('success', 'Pakaian berhasil ditambahkan.');
} catch (\Exception $e) {
// Rollback semua jika ada error
DB::rollBack();
// Hapus file yang sudah di-upload jika perlu
if ($path && Storage::disk('public')->exists($path)) {
Storage::disk('public')->delete($path);
}
return redirect()->back()->with('error', 'Gagal menambahkan pakaian: ' . $e->getMessage());
}
$pakaian = Pakaian::create([
'nama_pakaian' => $request->nama_pakaian,
'harga' => $request->harga,
'img' => $imgPath ? 'storage/' . $imgPath : null,
]);
// Simpan relasi subkriteria (many-to-many)
$pakaian->subKriterias()->sync($request->subkriterias);
return redirect()->route('admin.pakaian.index')->with('success', 'Data pakaian berhasil ditambahkan.');
}
@ -76,55 +127,83 @@ class PakaianController extends Controller
/**
* Show the form for editing the specified resource.
*/
public function edit(string $id)
public function edit($id)
{
//
$pakaian = Pakaian::with('subKriterias')->findOrFail($id);
$kriterias = Kriteria::with('subKriteria')->get();
return view('admin.pages.pakaian.edit', compact('pakaian', 'kriterias'));
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, $id)
{
$request->validate([
'nama_pakaian' => 'required|string|max:255',
'harga' => 'required|numeric|min:0',
'gambar' => 'nullable|image|mimes:jpeg,png,jpg|max:2048',
'harga' => 'required|numeric',
'img' => 'nullable|image|max:2048',
'sub_kriterias' => 'array|nullable',
'deskripsi' => 'nullable|string|max:1000',
]);
$pakaian = Pakaian::findOrFail($id);
$pakaian->nama_pakaian = $request->nama_pakaian;
$pakaian->harga = $request->harga;
DB::beginTransaction();
// Jika upload gambar baru
if ($request->hasFile('gambar')) {
if ($pakaian->img && file_exists(public_path($pakaian->img))) {
unlink(public_path($pakaian->img));
try {
$pakaian = Pakaian::findOrFail($id);
$path = $pakaian->img;
if ($request->hasFile('img')) {
// Hapus gambar lama dari storage
if ($pakaian->img && Storage::disk('public')->exists(str_replace('storage/', '', $pakaian->img))) {
Storage::disk('public')->delete(str_replace('storage/', '', $pakaian->img));
}
// Simpan gambar baru
$storedPath = $request->file('img')->store('pakaian', 'public');
$path = 'storage/' . $storedPath;
}
$file = $request->file('gambar');
$path = 'uploads/pakaian/';
$filename = time() . '_' . $file->getClientOriginalName();
$file->move(public_path($path), $filename);
$pakaian->img = $path . $filename;
$pakaian->update([
'nama_pakaian' => $request->nama_pakaian,
'harga' => $request->harga,
'img' => $path,
'deskripsi' => $request->deskripsi,
]);
// Update relasi sub_kriterias
$inputSub = $request->input('sub_kriterias', []);
$subkriteriaIds = [];
foreach ($inputSub as $key => $value) {
if (is_array($value)) {
$subkriteriaIds = array_merge($subkriteriaIds, $value);
} else {
$subkriteriaIds[] = $value;
}
}
$pakaian->subKriterias()->sync($subkriteriaIds);
DB::commit();
return redirect()->route('admin.pakaian.index', ['page' => $request->input('page')])
->with('success', 'Pakaian berhasil diperbarui.');
} catch (\Exception $e) {
DB::rollBack();
return redirect()->back()->with('error', 'Gagal memperbarui pakaian: ' . $e->getMessage());
}
$pakaian->save();
return redirect()->back()->with('success', 'Data pakaian berhasil diperbarui!');
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id)
public function destroy(Request $request, string $id)
{
$pakaian = Pakaian::findOrFail($id);
// Hapus gambar dari storage jika ada
if ($pakaian->img && file_exists(public_path($pakaian->img))) {
unlink(public_path($pakaian->img));
if ($pakaian->img && Storage::disk('public')->exists(str_replace('storage/', '', $pakaian->img))) {
Storage::disk('public')->delete(str_replace('storage/', '', $pakaian->img));
}
// Hapus relasi subkriteria (pivot table)
@ -133,6 +212,8 @@ class PakaianController extends Controller
// Hapus data pakaian dari database
$pakaian->delete();
return redirect()->route('admin.pakaian.index')->with('success', 'Data pakaian berhasil dihapus.');
return redirect()->route('admin.pakaian.index', ['page' => $request->input('page')])
->with('success', 'Data pakaian berhasil dihapus.');
}
}

View File

@ -4,7 +4,9 @@ namespace App\Http\Controllers;
use App\Models\Pakaian;
use App\Models\Kriteria;
use App\Models\Subkriteria;
use Illuminate\Http\Request;
use App\Models\PenilaianPakaian;
class PenilaianController extends Controller
{
@ -13,117 +15,103 @@ class PenilaianController extends Controller
*/
public function index(Request $request)
{
$query = Pakaian::with('subKriterias.kriteria');
$perPage = $request->get('perPage', 10); // Ambil dari query, default ke 10
$query = PenilaianPakaian::with(['pakaian', 'subKriteria.kriteria']);
// Filter berdasarkan nama_pakaian jika ada pencarian
if ($request->has('search') && $request->search != '') {
$query->where('nama_pakaian', 'like', '%' . $request->search . '%');
}
// Ambil jumlah per halaman dari parameter 'perPage' atau default ke 10
$perPage = $request->get('perPage', 10);
// Ambil data pakaian dengan pagination
$pakaians = $query->paginate($perPage);
// Ambil semua data kriteria
$kriterias = Kriteria::all();
// Return ke view dengan data yang dibutuhkan
return view('admin.pages.penilaian.index', compact('pakaians', 'kriterias'));
$search = $request->get('search');
$query->where(function ($q) use ($search) {
// Cari di nama pakaian
$q->whereHas('pakaian', function ($q1) use ($search) {
$q1->where('nama_pakaian', 'like', "%$search%");
})
// Cari di nama sub kriteria
->orWhereHas('subKriteria', function ($q2) use ($search) {
$q2->where('nama_sub', 'like', "%$search%");
})
// Cari di nama kriteria
->orWhereHas('subKriteria.kriteria', function ($q3) use ($search) {
$q3->where('nama_kriteria', 'like', "%$search%");
});
});
}
$penilaians = $query->paginate($perPage)->appends($request->all());
return view('admin.pages.penilaian.index', compact('penilaians'));
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
//
$pakaians = Pakaian::all();
$subkriterias = SubKriteria::all();
return view('admin.pages.penilaian.form', compact('pakaians', 'subkriterias'));
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
//
}
$request->validate([
'pakaian_id' => 'required|exists:pakaians,id',
'sub_kriteria_id' => 'required|exists:sub_kriterias,id',
'nilai' => 'required|numeric|between:1,5',
]);
/**
* Display the specified resource.
*/
public function show(string $id)
{
//
}
// Cek apakah kombinasi sudah ada
$cek = PenilaianPakaian::where('pakaian_id', $request->pakaian_id)
->where('sub_kriteria_id', $request->sub_kriteria_id)
->first();
/**
* Show the form for editing the specified resource.
*/
public function edit(string $id)
{
// Ambil data pakaian dengan relasi subKriterias beserta kriteria-nya
$pakaian = Pakaian::with('subKriterias.kriteria')->findOrFail($id);
// Ambil semua kriteria, supaya bisa ditampilkan di form edit untuk memilih/mengubah subkriteria
$kriterias = Kriteria::with('subKriteria')->get();
// Kirim data ke view edit
return view('admin.pages.penilaian.edit', compact('pakaian', 'kriterias'));
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, $id)
{
$pakaian = Pakaian::findOrFail($id);
// Ambil list kriteria yang multiple select (jenis acara, lokasi, cuaca)
$multiSelectKriteria = Kriteria::whereIn('nama_kriteria', ['Jenis Acara', 'Lokasi', 'Cuaca'])->pluck('id')->toArray();
$rules = [];
$messages = [];
foreach ($request->input('nilai') as $kriteriaId => $value) {
if (in_array($kriteriaId, $multiSelectKriteria)) {
// Kriteria yang multiple select wajib berupa array dengan minimal 1 elemen
$rules["nilai.$kriteriaId"] = 'required|array|min:1';
$messages["nilai.$kriteriaId.required"] = 'Harap pilih minimal satu subkriteria untuk kriteria ' . Kriteria::find($kriteriaId)->nama_kriteria;
$messages["nilai.$kriteriaId.min"] = 'Harap pilih minimal satu subkriteria untuk kriteria ' . Kriteria::find($kriteriaId)->nama_kriteria;
} else {
// Kriteria yang single select wajib ada (string / integer)
$rules["nilai.$kriteriaId"] = 'required';
$messages["nilai.$kriteriaId.required"] = 'Harap pilih satu subkriteria untuk kriteria ' . Kriteria::find($kriteriaId)->nama_kriteria;
}
if ($cek) {
return redirect()->back()
->withErrors(['Data penilaian untuk kombinasi ini sudah ada.'])
->withInput();
}
$validated = $request->validate($rules, $messages);
PenilaianPakaian::create($request->all());
$page = $request->input('page', 1); // default page 1 jika tidak ada
return redirect()->route('admin.penilaian.index', ['page' => $page])
->with('success', 'Data penilaian berhasil ditambahkan.');
}
// Flatten semua subkriteria dari array nilai (baik single select maupun multi)
$subKriteriaIds = [];
public function edit(PenilaianPakaian $penilaian)
{
$pakaians = Pakaian::all();
$subkriterias = SubKriteria::all();
return view('admin.pages.penilaian.form', compact('penilaian', 'pakaians', 'subkriterias'));
}
foreach ($validated['nilai'] as $kriteriaId => $sub) {
if (is_array($sub)) {
$subKriteriaIds = array_merge($subKriteriaIds, $sub);
} else {
$subKriteriaIds[] = $sub;
}
public function update(Request $request, PenilaianPakaian $penilaian)
{
$request->validate([
'pakaian_id' => 'required|exists:pakaians,id',
'sub_kriteria_id' => 'required|exists:sub_kriterias,id',
'nilai' => 'required|numeric|between:1,5',
]);
// Cek jika ada duplikat kombinasi (tapi bukan dirinya sendiri)
$cek = PenilaianPakaian::where('pakaian_id', $request->pakaian_id)
->where('sub_kriteria_id', $request->sub_kriteria_id)
->where('id', '!=', $penilaian->id)
->first();
if ($cek) {
return redirect()->back()
->withErrors(['Kombinasi ini sudah digunakan pada data lain.'])
->withInput();
}
$subKriteriaIds = array_unique($subKriteriaIds);
// Sync relasi many-to-many
$pakaian->subKriterias()->sync($subKriteriaIds);
return redirect()->route('admin.penilaian.index')->with('success', 'Penilaian berhasil diperbarui.');
$penilaian->update($request->all());
$page = $request->input('page', 1);
return redirect()->route('admin.penilaian.index', ['page' => $page])
->with('success', 'Data penilaian berhasil diperbarui.');
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id)
public function destroy(PenilaianPakaian $penilaian)
{
//
}
$penilaian->delete();
$page = request()->input('page', 1);
return redirect()->route('admin.penilaian.index', ['page' => $page])
->with('success', 'Data berhasil dihapus.');
}
}

View File

@ -0,0 +1,64 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class RekomendasiController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
//
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*/
public function show(string $id)
{
//
}
/**
* Show the form for editing the specified resource.
*/
public function edit(string $id)
{
//
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $id)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id)
{
//
}
}

View File

@ -44,7 +44,6 @@ class SubKriteriaController extends Controller
$validated = $request->validate([
'kriteria_id' => 'required',
'nama_sub' => 'required|string|max:255',
'nilai' => 'required|numeric',
'min_harga' => 'nullable|numeric|min:0',
'max_harga' => 'nullable|numeric|min:0|gte:min_harga',
]);
@ -53,7 +52,6 @@ class SubKriteriaController extends Controller
SubKriteria::create([
'kriteria_id' => $validated['kriteria_id'],
'nama_sub' => $validated['nama_sub'],
'nilai' => $validated['nilai'],
'min_harga' => $validated['min_harga'] ?? null,
'max_harga' => $validated['max_harga'] ?? null,
]);
@ -86,7 +84,6 @@ class SubKriteriaController extends Controller
$request->validate([
'kriteria_id' => 'required',
'nama_sub' => 'required|string|max:255',
'nilai' => 'required|numeric',
'min_harga' => 'nullable|numeric',
'max_harga' => 'nullable|numeric',
]);
@ -95,7 +92,6 @@ class SubKriteriaController extends Controller
$subkriteria->update([
'kriteria_id' => $request->kriteria_id,
'nama_sub' => $request->nama_sub,
'nilai' => $request->nilai,
'min_harga' => $request->min_harga,
'max_harga' => $request->max_harga,
]);

View File

@ -0,0 +1,90 @@
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
class UserController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
$users = User::all(); // Mengambil semua data user
return view('admin.pages.user.index', compact('users'));
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*/
public function show($id)
{
$user = User::findOrFail($id); // Ambil data user, jika tidak ada akan 404
return view('admin.pages.user.show', compact('user'));
}
/**
* Show the form for editing the specified resource.
*/
public function edit($id)
{
$user = User::findOrFail($id); // Ambil data user
return view('admin.pages.user.edit', compact('user'));
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, $id)
{
$user = User::findOrFail($id); // Ambil user berdasarkan ID
// Validasi input dari form
$request->validate([
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email,' . $id,
'username' => 'required|string|unique:users,username,' . $id,
'password' => 'nullable|string|min:6|confirmed', // validasi password + konfirmasi
]);
// Ambil data yang akan diperbarui
$data = $request->only(['name', 'email', 'username']);
// Jika password diisi, enkripsi dan tambahkan ke data
if ($request->filled('password')) {
$data['password'] = Hash::make($request->password);
}
// Update data user di database
$user->update($data);
return redirect()->route('admin.user.show', $user->id)->with('success', 'User berhasil diperbarui');
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id)
{
//
}
}

View File

@ -2,8 +2,9 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class Kriteria extends Model
{
@ -13,8 +14,9 @@ class Kriteria extends Model
protected $fillable = ['nama_kriteria', 'bobot', 'jenis', 'kode_kriteria'];
public function subKriteria()
public function subKriteria(): HasMany
{
return $this->hasMany(SubKriteria::class);
return $this->hasMany(SubKriteria::class, );
}
}

View File

@ -12,10 +12,15 @@ class Pakaian extends Model
protected $table = 'pakaians';
protected $fillable = ['nama_pakaian', 'img', 'harga'];
protected $fillable = ['nama_pakaian', 'img', 'harga', 'deskripsi'];
public function subKriterias(): BelongsToMany
{
return $this->belongsToMany(SubKriteria::class, 'pakaian_sub_kriterias');
}
public function penilaian()
{
return $this->hasMany(PenilaianPakaian::class);
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace App\Models;
use App\Models\Subkriteria;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class PenilaianPakaian extends Model
{
use HasFactory;
protected $fillable = [
'pakaian_id',
'sub_kriteria_id',
'nilai',
];
public function pakaian()
{
return $this->belongsTo(Pakaian::class);
}
public function subkriteria()
{
return $this->belongsTo(Subkriteria::class, 'sub_kriteria_id');
}
}

View File

@ -13,7 +13,7 @@ class SubKriteria extends Model
protected $table = 'sub_kriterias';
protected $fillable = ['kriteria_id', 'nama_sub', 'nilai', 'min_harga', 'max_harga'];
protected $fillable = ['kriteria_id', 'nama_sub', 'min_harga', 'max_harga'];
public function kriteria(): BelongsTo
{
@ -22,6 +22,11 @@ class SubKriteria extends Model
public function pakaian(): BelongsToMany
{
return $this->belongsToMany(Pakaian::class, 'pakaian_sub_kriteria');
return $this->belongsToMany(Pakaian::class, 'pakaian_sub_kriteria',);
}
public function penilaians()
{
return $this->hasMany(PenilaianPakaian::class, 'sub_kriteria_id');
}
}

View File

@ -11,14 +11,13 @@ return new class extends Migration
*/
public function up(): void
{
Schema::create('pakaian_sub_kriterias', function (Blueprint $table) {
$table->id();
$table->foreignId('pakaian_id')->constrained()->onDelete('cascade');
$table->foreignId('sub_kriteria_id')->constrained()->onDelete('cascade');
$table->timestamps();
$table->unique(['pakaian_id', 'sub_kriteria_id']);
});
Schema::create('pakaian_sub_kriterias', function (Blueprint $table) {
$table->id();
$table->foreignId('pakaian_id')->constrained()->onDelete('cascade');
$table->foreignId('sub_kriteria_id')->constrained()->onDelete('cascade');
$table->timestamps();
$table->unique(['pakaian_id', 'sub_kriteria_id']);
});
}
/**

View File

@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('penilaian_pakaians', function (Blueprint $table) {
$table->id();
$table->foreignId('pakaian_id')->constrained('pakaians')->onDelete('cascade'); // FIX di sini
$table->foreignId('sub_kriteria_id')->constrained('sub_kriterias')->onDelete('cascade');
$table->integer('nilai'); // 1 kalau cocok, 0 kalau tidak
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('penilaian_pakaians');
}
};

View File

@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('pakaians', function (Blueprint $table) {
$table->text('deskripsi')->nullable()->after('img');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('pakaians', function (Blueprint $table) {
$table->dropColumn('deskripsi');
});
}
};

View File

@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('quiz_histories', function (Blueprint $table) {
$table->id();
$table->json('jenis_acara'); // multiple
$table->string('harga'); // single
$table->string('jenis_pakaian');// single
$table->json('warna'); // multiple
$table->json('lokasi'); // multiple
$table->json('hasil_rekomendasi'); // bisa menyimpan lebih dari 1 hasil
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('quiz_histories');
}
};

View File

@ -3,6 +3,7 @@
namespace Database\Seeders;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use App\Models\User;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;
@ -13,13 +14,18 @@ class DatabaseSeeder extends Seeder
*/
public function run(): void
{
// \App\Models\User::factory(10)->create();
\App\Models\User::create([
User::updateOrCreate(
['username' => 'ysn'], // Cek berdasarkan username
[
'name' => 'Admin User',
'username' => 'ysn',
'email' => 'yasindaputri16@gmail.com',
'password' => Hash::make('1234567890'),
]
);
// Panggil seeder PenilaianPakaianSeeder
$this->call([
PenilaianPakaianSeeder::class,
]);
}
}

File diff suppressed because it is too large Load Diff

1256
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

BIN
public/uploads/pakaian.rar Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

View File

@ -25,9 +25,10 @@
<style>
.sidebar {
position: relative;
position: relative;
}
}
.bg-gradient-green {
background-color: #43a047 !important;
/* hijau medium */
@ -45,7 +46,6 @@
padding-top: 8px !important;
padding-bottom: 8px !important;
}
</style>
</head>
@ -92,33 +92,35 @@
<!-- Nav Item - Data Sub Kriteria (Collapse) -->
<li class="nav-item">
<a class="nav-link d-flex justify-content-between align-items-center {{ request()->is('admin/kriteria/subkriteria/*') ? '' : 'collapsed' }}"
href="#" data-bs-toggle="collapse" data-bs-target="#collapseSubkriteria" aria-expanded="{{ request()->is('admin/kriteria/subkriteria/*') ? 'true' : 'false' }}"
aria-controls="collapseSubkriteria" style="font-size: 0.9rem; padding: 0.5rem 1rem;">
<div>
<i class="bi bi-boxes me-2"></i>
<span>Data Sub Kriteria</span>
</div>
<i class="bi bi-chevron-down small"></i>
</a>
<a class="nav-link d-flex justify-content-between align-items-center {{ request()->is('admin/kriteria/subkriteria/*') ? '' : 'collapsed' }}"
href="#" data-bs-toggle="collapse" data-bs-target="#collapseSubkriteria"
aria-expanded="{{ request()->is('admin/kriteria/subkriteria/*') ? 'true' : 'false' }}"
aria-controls="collapseSubkriteria" style="font-size: 0.9rem; padding: 0.5rem 1rem;">
<div>
<i class="bi bi-boxes me-2"></i>
<span>Data Sub Kriteria</span>
</div>
<i class="bi bi-chevron-down small"></i>
</a>
<div id="collapseSubkriteria" class="collapse {{ request()->is('admin/kriteria/subkriteria/*') ? 'show' : '' }}">
<div class="bg-white ps-2 py-1 rounded-2">
@php
use App\Models\Kriteria;
$kriterias = Kriteria::with('subKriteria')->get();
@endphp
<div id="collapseSubkriteria"
class="collapse {{ request()->is('admin/kriteria/subkriteria/*') ? 'show' : '' }}">
<div class="bg-white ps-2 py-1 rounded-2">
@php
use App\Models\Kriteria;
$kriterias = Kriteria::with('subKriteria')->get();
@endphp
@foreach ($kriterias as $kriteria)
<a href="{{ route('admin.kriteria.subkriteria.index', ['nama_kriteria' => $kriteria->nama_kriteria]) }}"
class="d-block nav-link {{ request()->is('admin/kriteria/subkriteria/' . $kriteria->nama_kriteria) ? 'fw-bold text-dark' : 'text-dark' }}"
style="font-size: 0.82rem; padding: 3px 6px; line-height: 1.2;">
<i class="bi bi-chevron-right small me-1"></i>{{ $kriteria->nama_kriteria }}
</a>
@endforeach
@foreach ($kriterias as $kriteria)
<a href="{{ route('admin.kriteria.subkriteria.index', ['nama_kriteria' => $kriteria->nama_kriteria]) }}"
class="d-block nav-link {{ request()->is('admin/kriteria/subkriteria/' . $kriteria->nama_kriteria) ? 'fw-bold text-dark' : 'text-dark' }}"
style="font-size: 0.82rem; padding: 3px 6px; line-height: 1.2;">
<i class="bi bi-chevron-right small me-1"></i>{{ $kriteria->nama_kriteria }}
</a>
@endforeach
</div>
</div>
</div>
</li>
</li>
<script>
document.addEventListener("DOMContentLoaded", function() {
@ -159,14 +161,6 @@
<span>Penilaian</span></a>
</li>
<!-- Nav Item - Hasil Akhir -->
<li class="nav-item {{ request()->is('admin/riwayat') ? 'active' : '' }}">
<a class="nav-link" href="#">
<i class="bi bi-hourglass-split"></i>
<span>Riwayat User</span>
</a>
</li>
<!-- Divider -->
<hr class="sidebar-divider">
@ -212,12 +206,13 @@
aria-labelledby="userDropdown">
<!-- Profile Link -->
<a class="dropdown-item" href="#">
<a class="dropdown-item" href="{{ route('admin.user.show', Auth::user()->id) }}">
<i class="fas fa-user fa-sm fa-fw mr-2 text-gray-400"></i>
Profile
</a>
<div class="dropdown-divider"></div>
<!-- Logout Link -->
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#logoutModal">
<i class="fas fa-sign-out-alt fa-sm fa-fw mr-2 text-gray-400"></i>

View File

@ -0,0 +1,42 @@
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<title>Lupa Username</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="flex justify-center items-center min-h-screen bg-white text-gray-800 font-sans">
<div class="bg-green-100 border border-green-200 p-6 rounded-xl shadow-md w-full max-w-md">
<h2 class="text-2xl font-bold mb-4">Lupa Username?</h2>
<p class="text-gray-600 mb-6">
Masukkan email yang terdaftar untuk mengetahui username Anda.
</p>
@if (session('status'))
<div class="bg-blue-100 text-blue-800 border border-blue-300 p-3 rounded mb-4">
{{ session('status') }}
</div>
@endif
<form method="POST" action="{{ route('forgot.username.send') }}">
@csrf
<div class="mb-4">
<label for="email" class="block text-sm mb-1">Email</label>
<input type="email" id="email" name="email" required class="w-full px-3 py-2 border rounded bg-white text-gray-900 focus:outline-none focus:ring-2 focus:ring-blue-400" />
@error('email')
<span class="text-red-600 text-sm">{{ $message }}</span>
@enderror
</div>
<button type="submit" class="w-full bg-green-700 hover:bg-green-800 text-white px-4 py-2 rounded font-semibold">
Kirim Username
</button>
</form>
<p class="text-center text-sm text-gray-700 mt-4">
<a href="{{ route('login') }}" class="text-black hover:underline font-medium">
Kembali ke halaman login
</a>
</p>
</div>
</body>
</html>

View File

@ -30,6 +30,9 @@
<a href="{{ route('forgot.password.form') }}" class="text-green-700 hover:underline font-medium">
Lupa Password?
</a>
<a href="{{ route('forgot.username.form') }}" class="text-green-700 hover:underline font-medium">
Lupa Username?
</a>
</div>
<button type="submit" class="w-full bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded font-semibold">
Login

View File

@ -3,57 +3,33 @@
@section('content')
<style>
#content-wrapper {
min-height: 100vh; /* Supaya kontennya minimal setinggi layar */
#content-wrapper {
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: space-between;
}
#content {
flex: 1; /* Supaya konten utama mengambil semua ruang kosong */
flex: 1;
}
.sticky-footer {
width: calc(100% - 225px); /* Sesuaikan 250px dengan lebar sidebar */
position: fixed;
bottom: 0;
left: 225px; /* Mulai dari sebelah kanan sidebar */
background-color: white;
padding: 10px 0;
text-align: center;
}
.card-link-text {
transition: text-decoration 0.2s ease;
width: calc(100% - 225px);
position: fixed;
bottom: 0;
left: 225px;
background-color: white;
padding: 10px 0;
text-align: center;
}
a:hover .card-link-text {
text-decoration: underline;
}
a.card-link {
text-decoration: none;
color: inherit; /* supaya warna teks tetap sama */
display: block; /* supaya link memenuhi seluruh card */
}
a.card-link:hover span {
text-decoration: underline;
cursor: pointer;
}
a.text-decoration-none:hover .underline-on-hover {
text-decoration: underline;
}
</style>
<h1 class="h3 text-gray-800">
<i class="bi bi-house-door-fill"></i> Dashboard
</h1>
<!-- Notification Pop-up -->
<!-- Notification -->
<div class="alert alert-success alert-dismissible fade show" role="alert" style="font-size: 14px; display: flex; align-items: center; justify-content: space-between; background-color: #d4edda; border: 1px solid #c3e6cb; padding: 10px; border-radius: 5px;">
<span><strong>Selamat datang ADMIN!</strong> Anda bisa mengoperasikan sistem dengan wewenang tertentu melalui pilihan menu di bawah.</span>
<button type="button" class="close" data-dismiss="alert" aria-label="Close" style="margin-left: 10px;">
@ -61,110 +37,69 @@
</button>
</div>
<!-- Content Row -->
<div class="row">
<!-- Data Kriteria -->
<div class="col-xl-4 col-md-6 mb-4">
<a href="#">
<div class="card border-left-primary shadow h-100 py-2">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<span class="h5 mb-0 font-weight-bold text-gray-800">
Data Kriteria: {{ $totalKriteria }}
</span>
<i class="bi bi-box text-gray-400" style="font-size: 1.5rem;"></i>
</div>
</div>
</div>
</a>
<div class="row mt-4">
<!-- Tentang Sistem -->
<div class="col-md-6 mb-4">
<div class="card shadow-sm h-100 p-4">
<h5 class="mb-3" style="color: #155724; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; font-weight: 600;">
Informasi Sistem Pendukung Keputusan Pemilihan Pakaian
</h5>
<p class="text-gray-700 mb-0">
Sistem ini menggunakan metode <strong>Simple Additive Weighting (SAW)</strong> untuk memberikan rekomendasi pakaian berdasarkan preferensi pengguna.
Setiap pakaian dinilai berdasarkan kecocokan terhadap subkriteria dari 5 kriteria utama, dengan bobot yang telah ditentukan.
Semakin tinggi skor akhir, semakin cocok pakaian tersebut untuk kebutuhan pengguna.
</p>
</div>
<!-- Data Sub Kriteria -->
<div class="col-xl-4 col-md-6 mb-4">
<a href="#">
<div class="card border-left-info shadow h-100 py-2">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<span class="h5 mb-0 font-weight-bold text-gray-800">
Data Sub Kriteria: {{ $totalSubKriteria }}
</span>
<i class="bi bi-boxes text-gray-400" style="font-size: 1.5rem;"></i>
</div>
</div>
</div>
</a>
</div>
<!-- Data Alternatif -->
<div class="col-xl-4 col-md-6 mb-4">
<a href="#" class="text-decoration-none">
<div class="card border-left-success shadow h-100 py-2">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<span class="h5 mb-0 font-weight-bold text-gray-800 underline-on-hover">
Data Alternatif: {{ $totalPakaian }}
</span>
<i class="bi bi-person-lines-fill text-gray-400" style="font-size: 1.5rem;"></i>
</div>
</div>
</div>
</a>
</div>
<!-- Card Area Chart -->
<div class="col-xl-12 mb-4">
<div class="card shadow h-100">
<div class="card-header d-flex align-items-center py-2">
<h6 class="m-0 font-weight-bold text-dark">Statistik Pengunjung</h6>
</div>
<div class="card-body">
<div class="chart-area">
<canvas id="myAreaChart"></canvas>
</div>
<hr>
</div>
</div>
</div>
{{-- <!-- Data Penilaian -->
<div class="col-xl-4 col-md-6 mb-4">
<a href="{{ route('admin.penilaian.index') }}" style="text-decoration: none;">
<div class="card border-left-secondary shadow h-100 py-2">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<span class="h5 mb-0 font-weight-bold text-gray-800 card-link-text">Penilaian Alternatif</span>
<i class="bi bi-list-ul text-gray-400" style="font-size: 1.5rem;"></i>
</div>
</div>
</div>
</a>
</div>
<!-- Data Perhitungan -->
<div class="col-xl-4 col-md-6 mb-4">
<div class="card border-left-warning shadow h-100 py-2">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<span class="h5 mb-0 font-weight-bold text-gray-800">Perhitungan</span>
<i class="bi bi-calculator-fill text-gray-400" style="font-size: 1.5rem;"></i>
</div>
</div>
</div>
</div>
<!-- Data Hasil Akhir -->
<div class="col-xl-4 col-md-6 mb-4">
<div class="card border-left-danger shadow h-100 py-2">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<span class="h5 mb-0 font-weight-bold text-gray-800">Hasil Akhir</span>
<i class="bi bi-graph-up text-gray-400" style="font-size: 1.5rem;"></i>
</div>
</div>
</div>
</div> --}}
</div>
<!-- Grafik -->
<div class="col-md-6 mb-4">
<div class="card shadow-sm h-100 p-4">
<h5 class="mb-3" style="color: #155724; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; font-weight: 600;">
Statistik Jumlah Data
</h5>
<canvas id="dashboardChart" height="170"></canvas>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
const ctx = document.getElementById('dashboardChart').getContext('2d');
const dashboardChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ['Kriteria', 'Sub Kriteria', 'Pakaian'],
datasets: [{
label: 'Jumlah Data',
data: [{{ $totalKriteria }}, {{ $totalSubKriteria }}, {{ $totalPakaian }}],
backgroundColor: [
'rgba(78, 115, 223, 0.7)',
'rgba(54, 185, 204, 0.7)',
'rgba(28, 200, 138, 0.7)'
],
borderColor: [
'rgba(78, 115, 223, 1)',
'rgba(54, 185, 204, 1)',
'rgba(28, 200, 138, 1)'
],
borderWidth: 1
}]
},
options: {
responsive: true,
plugins: {
legend: { display: false }
},
scales: {
y: {
beginAtZero: true,
ticks: {
precision: 0
}
}
}
}
});
</script>
@endsection

View File

@ -0,0 +1,109 @@
@extends('admin.layouts.base')
@section('title', 'Tambah Pakaian')
@section('content')
<div class="py-4">
<div class="card shadow-sm border-0 mx-auto">
<div class="card-header text-white d-flex align-items-center" style="background-color: #14532d;">
<h5 class="mb-0">Tambah Pakaian</h5>
</div>
<div class="card-body">
<form action="{{ route('admin.pakaian.store') }}" method="POST" enctype="multipart/form-data">
@csrf
<input type="hidden" name="page" value="{{ request()->input('page') }}">
<div class="mb-3">
<label for="nama_pakaian" class="form-label fw-semibold">Nama Pakaian</label>
<input type="text" name="nama_pakaian" id="nama_pakaian" class="form-control" required>
</div>
<div class="mb-3">
<label for="harga" class="form-label fw-semibold">Harga</label>
<div class="input-group">
<span class="input-group-text">Rp</span>
<input type="number" name="harga" id="harga" class="form-control" required>
</div>
</div>
<div class="mb-3">
<label for="img" class="form-label fw-semibold">Upload Gambar</label>
<input type="file" name="img" id="img" class="form-control" accept="image/*">
</div>
<div class="mb-3">
<label for="deskripsi" class="form-label fw-semibold">Deskripsi</label>
<textarea name="deskripsi" id="deskripsi" class="form-control" rows="4" placeholder="Masukkan deskripsi pakaian..."></textarea>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">Pilih Sub Kriteria</label>
<div class="border rounded px-3 py-2" style="max-height: 300px; overflow-y: auto;">
@foreach ($kriterias as $kriteria)
<div class="mb-3">
<h6 style="color: #14532d;">{{ $kriteria->nama_kriteria }}</h6>
@foreach ($kriteria->subKriteria as $sub)
@php
$isRadio = in_array($kriteria->nama_kriteria, ['Harga', 'Jenis Pakaian']);
$inputType = $isRadio ? 'radio' : 'checkbox';
$inputName = $isRadio ? 'sub_kriterias[' . $kriteria->id . ']' : 'sub_kriterias[]';
@endphp
<div class="form-check mb-2 ms-3">
<input
class="form-check-input"
type="{{ $inputType }}"
name="{{ $inputName }}"
value="{{ $sub->id }}"
id="sub_{{ $sub->id }}"
data-kriteria="{{ $kriteria->nama_kriteria }}"
>
<label class="form-check-label" for="sub_{{ $sub->id }}">
<strong>{{ $sub->nama_sub }}</strong>
@if ($kriteria->nama_kriteria === 'Harga')
<div class="text-muted small">
Min: Rp {{ number_format($sub->min_harga, 0, ',', '.') }},
Max: Rp {{ number_format($sub->max_harga, 0, ',', '.') }}
</div>
@endif
</label>
</div>
@endforeach
</div>
@endforeach
</div>
</div>
<div class="d-flex justify-content-between pt-3">
<a href="{{ route('admin.pakaian.index', ['page' => request('page')]) }}"
class="btn btn-outline-secondary">
<i class="bi bi-arrow-left"></i> Batal
</a>
<button type="submit" class="btn text-white" style="background-color: #14532d;">
Simpan
</button>
</div>
</form>
</div>
</div>
</div>
@endsection
@push('scripts')
<style>
.form-check-input[type="checkbox"],
.form-check-input[type="radio"] {
accent-color: #14532d;
}
.form-check-input:checked {
background-color: #14532d;
border-color: #14532d;
}
.form-check-input:focus {
box-shadow: 0 0 0 0.25rem rgba(20, 83, 45, 0.25);
border-color: #14532d;
}
</style>
@endpush

View File

@ -0,0 +1,116 @@
@extends('admin.layouts.base')
@section('title', 'Edit Pakaian')
@section('content')
<div class="py-4">
<div class="card shadow-sm border-0 mx-auto">
<div class="card-header text-white d-flex align-items-center" style="background-color: #14532d;">
<h5 class="mb-0">Edit Pakaian</h5>
</div>
<div class="card-body">
<form action="{{ route('admin.pakaian.update', $pakaian->id) }}" method="POST" enctype="multipart/form-data">
@csrf
@method('PUT')
<input type="hidden" name="page" value="{{ request()->input('page') }}">
<div class="mb-3">
<label class="form-label fw-semibold">Nama Pakaian</label>
<input type="text" name="nama_pakaian" class="form-control"
value="{{ old('nama_pakaian', $pakaian->nama_pakaian) }}" required>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">Harga</label>
<div class="input-group">
<span class="input-group-text">Rp</span>
<input type="number" name="harga" class="form-control"
value="{{ old('harga', $pakaian->harga) }}" required>
</div>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">Gambar Lama</label><br>
@if ($pakaian->img)
<img src="{{ asset($pakaian->img) }}" alt="Gambar Lama"
style="width: 100px; height: 100px; object-fit: cover;" class="border rounded">
@else
<p class="text-muted">Tidak ada gambar</p>
@endif
</div>
<div class="mb-3">
<label class="form-label fw-semibold">Upload Gambar Baru</label>
<input type="file" name="img" class="form-control" accept="image/*">
</div>
<div class="mb-3">
<label for="deskripsi" class="form-label fw-semibold">Deskripsi</label>
<textarea name="deskripsi" id="deskripsi" class="form-control" rows="4" placeholder="Masukkan deskripsi pakaian...">{{ old('deskripsi', $pakaian->deskripsi) }}</textarea>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">Pilih Sub Kriteria</label>
<div class="border rounded px-3 py-2" style="max-height: 300px; overflow-y: auto;">
@foreach ($kriterias as $kriteria)
<div class="mb-3">
<h6 style="color: #14532d;">{{ $kriteria->nama_kriteria }}</h6>
@foreach ($kriteria->subKriteria as $sub)
<div class="form-check mb-2 ms-3">
<input
class="form-check-input"
type="checkbox"
name="sub_kriterias[]"
value="{{ $sub->id }}"
id="sub_{{ $sub->id }}"
data-kriteria="{{ $kriteria->nama_kriteria }}"
onclick="handleSingleChoice(this)"
style="accent-color: #14532d;"
{{ in_array($sub->id, $pakaian->subKriterias->pluck('id')->toArray()) ? 'checked' : '' }}
>
<label class="form-check-label" for="sub_{{ $sub->id }}">
<strong>{{ $sub->nama_sub }}</strong>
@if ($kriteria->nama_kriteria === 'Harga')
<div class="text-muted small">
Min: Rp {{ number_format($sub->min_harga, 0, ',', '.') }},
Max: Rp {{ number_format($sub->max_harga, 0, ',', '.') }}
</div>
@endif
</label>
</div>
@endforeach
</div>
@endforeach
</div>
</div>
@push('scripts')
<script>
function handleSingleChoice(checkbox) {
const singleChoiceKriterias = ['Harga', 'Jenis Pakaian'];
const kriteria = checkbox.getAttribute('data-kriteria');
if (singleChoiceKriterias.includes(kriteria)) {
const checkboxes = document.querySelectorAll(`input[data-kriteria="${kriteria}"]`);
checkboxes.forEach(cb => {
if (cb !== checkbox) cb.checked = false;
});
}
}
</script>
@endpush
@stack('scripts')
<div class="d-flex justify-content-between pt-3">
<a href="{{ route('admin.pakaian.index', ['page' => request('page')]) }}" class="btn btn-outline-secondary">
<i class="bi bi-arrow-left"></i> Batal
</a>
<button type="submit" class="btn text-white" style="background-color: #14532d;">
Perbarui
</button>
</div>
</form>
</div>
</div>
</div>
@endsection

View File

@ -7,49 +7,50 @@
<style>
.search-input {
width: 200px;
}
width: 200px;
}
.btn-biru {
background-color: #007bff; /* biru Bootstrap */
color: white;
border: none;
padding: 6px 16px;
border-radius: 4px;
cursor: pointer;
}
.btn-biru {
background-color: #007bff;
/* biru Bootstrap */
color: white;
border: none;
padding: 6px 16px;
border-radius: 4px;
cursor: pointer;
}
.btn-biru:hover {
background-color: #0069d9;
}
.btn-biru:hover {
background-color: #0069d9;
}
.search-box {
display: flex;
gap: 8px;
align-items: center;
margin-bottom: 12px;
}
.search-box {
display: flex;
gap: 8px;
align-items: center;
margin-bottom: 12px;
}
.search-box input[type="text"] {
padding: 6px;
border: 1px solid #ccc;
border-radius: 4px;
}
.search-box input[type="text"] {
padding: 6px;
border: 1px solid #ccc;
border-radius: 4px;
}
.modern-select {
padding: 6px 12px;
border-radius: 8px;
border: 1px solid #ccc;
font-size: 14px;
background-color: #fff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
transition: border 0.2s ease-in-out;
}
.modern-select {
padding: 6px 12px;
border-radius: 8px;
border: 1px solid #ccc;
font-size: 14px;
background-color: #fff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
transition: border 0.2s ease-in-out;
}
.modern-select:focus {
border-color: #0d6efd;
outline: none;
}
.modern-select:focus {
border-color: #0d6efd;
outline: none;
}
</style>
@if (session('success'))
<script>
@ -73,10 +74,10 @@
<h6 class="m-0 font-weight-bold" style="color: #064E3B;">
<i class="bi bi-table"></i> Daftar Data Pakaian
</h6>
<button type="button" class="btn" style="background-color: #064E3B; color: white;" data-bs-toggle="modal"
data-bs-target="#modalTambah">
<a href="{{ route('admin.pakaian.create') }}" class="btn" style="background-color: #064E3B; color: white;">
<i></i> Tambah Data
</button>
</a>
</div>
<div class="card-body">
@ -99,352 +100,249 @@
<div class="d-flex align-items-center" style="gap: 10px;">
<input type="text" name="search" value="{{ request('search') }}"
class="form-control form-control-sm" placeholder="Cari nama pakaian...">
<button type="submit" class="btn btn-success btn-sm" style="background-color: #14532d; border-color: #14532d;">
<button type="submit" class="btn btn-success btn-sm"
style="background-color: #14532d; border-color: #14532d;">
Cari
</button>
</div>
</form>
</div>
<div class="table-responsive">
<table class="table table-bordered border-secondary table-striped align-middle text-center">
<thead class="table-light">
<tr>
<th scope="col">No</th>
<th scope="col">Gambar</th>
<th scope="col">Nama Pakaian</th>
<th scope="col">Harga</th>
<th scope="col">Aksi</th>
</tr>
</thead>
<tbody>
@foreach ($alternatif as $index => $item)
<tr>
<td>{{ $loop->iteration }}</td>
<td>
@if ($item->img)
<img src="{{ asset($item->img) }}" alt="Gambar" class="img-thumbnail" style="width: 100px; height: 100px;">
@else
<span class="text-muted">Tidak ada gambar</span>
@endif
</td>
<td>{{ $item->nama_pakaian }}</td>
<td>Rp{{ number_format($item->harga, 0, ',', '.') }}</td>
<td>
<button type="button" class="btn btn-info btn-sm" data-bs-toggle="modal" data-bs-target="#infoModal{{ $item->id }}">
<i class="bi bi-info-circle"></i>
</button>
<a href="{{ route('admin.pakaian.edit', $item->id) }}" class="btn btn-warning btn-sm">
<i class="bi bi-pencil-square"></i>
</a>
<button type="button" class="btn btn-danger btn-sm btn-delete" data-id="{{ $item->id }}" data-nama="{{ $item->nama_pakaian }}">
<i class="bi bi-trash"></i>
</button>
<div class="table-responsive">
<table class="table table-bordered border-secondary table-striped align-middle text-center">
<thead class="table-light">
<tr>
<th scope="col">No</th>
<th scope="col">Gambar</th>
<th scope="col">Nama Pakaian</th>
<th scope="col">Harga</th>
<th scope="col">Deskripsi</th>
<th scope="col">Aksi</th>
</tr>
</thead>
<tbody>
@foreach ($alternatif as $index => $item)
<tr>
<td>{{ $loop->iteration }}</td>
<td>
@if ($item->img)
<img src="{{ asset($item->img) }}" alt="Gambar"
style="width: 100px; height: 100px;">
@else
<span class="text-muted">Tidak ada gambar</span>
@endif
</td>
<td>{{ $item->nama_pakaian }}</td>
<td>Rp{{ number_format($item->harga, 0, ',', '.') }}</td>
<td>{{ $item->deskripsi ?? '-' }}</td>
<td>
<!-- Tombol Info -->
<button type="button" class="btn btn-info btn-sm" data-bs-toggle="modal" data-bs-target="#infoModal{{ $item->id }}">
<i class="bi bi-info-circle"></i>
</button>
<!-- Form Hapus (disembunyikan) -->
<form id="delete-form-{{ $item->id }}" action="{{ route('admin.pakaian.destroy', $item->id) }}" method="POST" style="display: none;">
@csrf
@method('DELETE')
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<!-- Pagination -->
<div class="d-flex justify-content-end">
{{ $alternatif->appends(request()->query())->links('vendor.pagination.bootstrap-5') }}
</div>
<a href="{{ route('admin.pakaian.edit', $item->id) }}" class="btn btn-warning btn-sm">
<i class="bi bi-pencil-square"></i>
</a>
<!-- Modal Info -->
@foreach ($alternatif as $item)
<div class="modal fade" id="infoModal{{ $item->id }}" tabindex="-1"
aria-labelledby="infoModalLabel{{ $item->id }}" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="infoModalLabel{{ $item->id }}">
Detail Subkriteria - {{ $item->nama_pakaian }}
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"
aria-label="Close"></button>
</div>
<div class="modal-body">
<table class="table table-bordered">
<thead>
<tr>
<th>Kriteria</th>
<th>Subkriteria</th>
<th>Nilai</th>
<th>Range Harga</th>
</tr>
</thead>
<tbody>
@foreach ($item->subKriterias as $sub)
<tr>
<td>{{ $sub->kriteria->nama_kriteria ?? '-' }}</td>
<td>{{ $sub->nama_sub }}</td>
<td>{{ $sub->nilai }}</td>
<td>
@if ($sub->kriteria->nama_kriteria === 'Harga')
Rp{{ number_format($sub->min_harga, 0, ',', '.') }}
-
Rp{{ number_format($sub->max_harga, 0, ',', '.') }}
@else
-
@endif
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary"
data-bs-dismiss="modal">Tutup</button>
</div>
</div>
</div>
</div>
@endforeach
<button type="button" class="btn btn-danger btn-sm btn-delete"
data-id="{{ $item->id }}" data-nama="{{ $item->nama_pakaian }}">
<i class="bi bi-trash"></i>
</button>
<!-- Pagination -->
<div class="d-flex justify-content-end">
{{ $alternatif->appends(request()->query())->links('vendor.pagination.bootstrap-5') }}
</div>
<!-- Modal Tambah Data Pakaian -->
<div class="modal fade" id="modalTambah" tabindex="-1" aria-labelledby="modalTambahLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered"> <!-- Centered vertically -->
<div class="modal-content rounded-3 shadow-sm border-0">
<!-- Header -->
<div class="modal-header border-bottom-0">
<h5 class="modal-title fw-semibold" id="modalTambahLabel">
<i class="bi bi-plus-circle me-1"></i> Tambah Pakaian
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Tutup"></button>
</div>
<!-- Body -->
<div class="modal-body pt-0">
<form action="{{ route('admin.pakaian.store') }}" method="POST" enctype="multipart/form-data">
@csrf
<div class="mb-3">
<label for="nama_pakaian" class="form-label">Nama Pakaian</label>
<input type="text" class="form-control" name="nama_pakaian" required>
</div>
<div class="mb-3">
<label for="harga" class="form-label">Harga</label>
<input type="number" class="form-control" name="harga" required>
</div>
<div class="mb-3">
<label for="img" class="form-label">Upload Gambar</label>
<input type="file" class="form-control" name="img" accept="image/*">
</div>
<!-- Footer Buttons -->
<div class="modal-footer border-top-0 d-flex justify-content-end gap-2 pt-0">
<button type="button" class="btn" style="background-color: #90ee90; color: black; border-radius: 5px; padding: 6px 20px;" data-bs-dismiss="modal">
<i></i> Batal
</button>
<button type="submit" class="btn" style="background-color: #064e3b; color: white; border-radius: 5px; padding: 6px 20px;">
<i></i> Simpan
</button>
</div>
</form>
</div>
</div>
<!-- Form Hapus (disembunyikan) -->
<form id="delete-form-{{ $item->id }}"
action="{{ route('admin.pakaian.destroy', $item->id) }}" method="POST"
style="display: none;">
@csrf
@method('DELETE')
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
@foreach ($alternatif as $item)
<!-- Modal Edit -->
<div class="modal fade" id="modalEdit{{ $item->id }}" tabindex="-1"
aria-labelledby="modalEdit{{ $item->id }}" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modalEdit{{ $item->id }}">Edit Data Pakaian</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form method="POST" action="{{ route('admin.pakaian.update', $item->id) }}"
enctype="multipart/form-data">
@csrf
@method('PUT')
<!-- Modal Info -->
@foreach ($alternatif as $item)
<div class="modal fade" id="infoModal{{ $item->id }}" tabindex="-1"
aria-labelledby="infoModalLabel{{ $item->id }}" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="infoModalLabel{{ $item->id }}">
Detail Subkriteria - {{ $item->nama_pakaian }}
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<!-- Nama Pakaian -->
<div class="mb-3">
<label for="edit_nama_pakaian{{ $item->id }}" class="form-label">Nama Pakaian</label>
<input type="text" class="form-control" id="edit_nama_pakaian{{ $item->id }}"
name="nama_pakaian" value="{{ $item->nama_pakaian }}" required>
</div>
<!-- Harga -->
<div class="mb-3">
<label for="edit_harga{{ $item->id }}" class="form-label">Harga</label>
<input type="number" id="edit_harga{{ $item->id }}" name="harga"
class="form-control" value="{{ $item->harga }}" required>
</div>
<!-- Upload Gambar Baru -->
<div class="mb-3">
<label for="edit_gambar{{ $item->id }}" class="form-label">Gambar Baru</label>
<input type="file" class="form-control" name="gambar"
id="edit_gambar{{ $item->id }}" accept="image/*">
</div>
<!-- Preview Gambar Lama -->
<div class="mb-3">
<label class="form-label">Gambar Lama:</label><br>
<img src="{{ asset($item->img) }}" alt="Gambar Lama"
style="width: 100px; height: 100px; object-fit: cover;" class="border rounded">
</div>
<table class="table table-bordered">
<thead>
<tr>
<th>Kriteria</th>
<th>Subkriteria</th>
<th>Range Harga</th>
</tr>
</thead>
<tbody>
@foreach ($item->subKriterias as $sub)
<tr>
<td>{{ $sub->kriteria->nama_kriteria ?? '-' }}</td>
<td>{{ $sub->nama_sub }}</td>
<td>
@if ($sub->kriteria->nama_kriteria === 'Harga')
Rp{{ number_format($sub->min_harga, 0, ',', '.') }}
-
Rp{{ number_format($sub->max_harga, 0, ',', '.') }}
@else
-
@endif
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn" style="background-color: #90ee90; color: black;"
data-bs-dismiss="modal">Batal</button>
<button type="submit" class="btn"
style="background-color: #064E3B; color: white;">Simpan</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Tutup</button>
</div>
</form>
</div>
</div>
</div>
@endforeach
<!-- Pagination -->
<div class="d-flex justify-content-end">
{{ $alternatif->appends(request()->query())->links('vendor.pagination.bootstrap-5') }}
</div>
@endforeach
<style>
.label-spacing {
margin-right: 0.3rem;
/* Jarak antara label dan select */
}
<style>
.label-spacing {
margin-right: 0.3rem;
/* Jarak antara label dan select */
}
.search-input {
width: 200px;
/* Lebar input search */
}
.search-input {
width: 200px;
/* Lebar input search */
}
.justify-between {
justify-content: space-between;
}
.justify-between {
justify-content: space-between;
}
.pagination {
display: flex;
justify-content: flex-end;
/* Geser ke pojok kanan */
align-items: center;
padding: 10px;
}
.pagination {
display: flex;
justify-content: flex-end;
/* Geser ke pojok kanan */
align-items: center;
padding: 10px;
}
.pagination .page-item .page-link {
font-size: 14px;
padding: 6px 12px;
border-radius: 5px;
border: none;
color: white;
background-color: #064E3B;
/* Warna biru */
margin: 0 2px;
transition: 0.3s ease-in-out;
}
.pagination .page-item .page-link {
font-size: 14px;
padding: 6px 12px;
border-radius: 5px;
border: none;
color: white;
background-color: #064E3B;
/* Warna biru */
margin: 0 2px;
transition: 0.3s ease-in-out;
}
.pagination .page-item.active .page-link {
background-color: #053B2D;
/* Biru lebih gelap */
font-weight: bold;
}
.pagination .page-item.active .page-link {
background-color: #053B2D;
/* Biru lebih gelap */
font-weight: bold;
}
.pagination .page-item .page-link:hover {
background-color: #046C4E;
}
.pagination .page-item .page-link:hover {
background-color: #046C4E;
}
.pagination .page-item.disabled .page-link {
background-color: #e9ecef;
color: #6c757d;
cursor: not-allowed;
}
.pagination .page-item.disabled .page-link {
background-color: #e9ecef;
color: #6c757d;
cursor: not-allowed;
}
.entries-form {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 1rem;
margin-bottom: 1rem;
}
.entries-form {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 1rem;
margin-bottom: 1rem;
}
.entries-left,
.entries-right {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 14px;
}
.entries-left,
.entries-right {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 14px;
}
.entries-left label,
.entries-right label {
margin: 0;
line-height: 1;
}
.entries-left label,
.entries-right label {
margin: 0;
line-height: 1;
}
.entries-left select,
.entries-right input[type="text"] {
padding: 4px 8px;
height: 32px;
font-size: 14px;
border: 1px solid #ccc;
border-radius: 4px;
}
.entries-left select,
.entries-right input[type="text"] {
padding: 4px 8px;
height: 32px;
font-size: 14px;
border: 1px solid #ccc;
border-radius: 4px;
}
.entries-right button {
height: 32px;
padding: 0 12px;
font-size: 14px;
background-color: #007bff;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
}
.entries-right button {
height: 32px;
padding: 0 12px;
font-size: 14px;
background-color: #007bff;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
}
.entries-right button:hover {
background-color: #0056b3;
}
</style>
.entries-right button:hover {
background-color: #0056b3;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
const deleteButtons = document.querySelectorAll(".btn-delete");
<script>
document.addEventListener("DOMContentLoaded", function () {
const deleteButtons = document.querySelectorAll(".btn-delete");
deleteButtons.forEach(button => {
button.addEventListener("click", function() {
const id = this.getAttribute("data-id");
const nama = this.getAttribute("data-nama");
deleteButtons.forEach(button => {
button.addEventListener("click", function () {
const id = this.getAttribute("data-id");
const nama = this.getAttribute("data-nama");
Swal.fire({
title: 'Hapus Data?',
text: `Data pakaian "${nama}" akan dihapus!`,
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#d33',
cancelButtonColor: '#3085d6',
confirmButtonText: 'Ya, hapus!',
cancelButtonText: 'Batal'
}).then((result) => {
if (result.isConfirmed) {
document.getElementById(`delete-form-${id}`).submit();
}
Swal.fire({
title: 'Hapus Data?',
text: `Data pakaian "${nama}" akan dihapus!`,
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#d33',
cancelButtonColor: '#3085d6',
confirmButtonText: 'Ya, hapus!',
cancelButtonText: 'Batal'
}).then((result) => {
if (result.isConfirmed) {
document.getElementById(`delete-form-${id}`).submit();
}
});
});
});
});
});
});
</script>
</script>
@endsection
@endsection

View File

@ -1,104 +0,0 @@
@extends('admin.layouts.base')
@section('title', 'Tambah Data Penilaian')
@section('content')
<h1 class="h3 mb-4 text-grey-800">
<i class="bi bi-database"></i> Data Penilaian
</h1>
<div class="card shadow mb-4">
<div class="card-header bg-white d-flex justify-content-between align-items-center">
<span class="text-primary fw-bold">+ Tambah Data Penilaian</span>
<a href="{{ route('admin.penilaian.index') }}" class="btn btn-secondary">
<i class="bi bi-arrow-left"></i> Kembali
</a>
</div>
<div class="card-body">
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form action="{{ route('admin.penilaian.store') }}" method="POST">
@csrf
<div class="row">
<!-- Pilih Alternatif -->
<div class="col-md-6 mb-3">
<label for="alternatif_id" class="form-label">Nama Alternatif</label>
<select class="form-control" id="alternatif_id" name="alternatif_id" required>
<option value="" selected disabled>--Pilih Alternatif--</option>
@foreach ($alternatif as $alt)
<option value="{{ $alt->id }}">{{ $alt->nama_alternatif }}</option>
@endforeach
</select>
</div>
<!-- Pilih Jenis Pakaian -->
<div class="col-md-6 mb-3">
<label for="subkriteria_id" class="form-label">Jenis Pakaian</label> <!-- Perubahan Nama -->
<select class="form-control" id="subkriteria_id" name="subkriteria_id" required>
<option value="" selected disabled>--Pilih Jenis Pakaian--</option> <!-- Perubahan Nama -->
@foreach ($subkriteria->where('kriteria_id', 3) as $sub)
<option value="{{ $sub->id }}">{{ $sub->nama_subkriteria }}</option>
@endforeach
</select>
</div>
<!-- Pilih Kriteria -->
<div class="col-md-6 mb-3">
<label for="kriteria_id" class="form-label">Nama Kriteria</label>
<select class="form-control" id="kriteria_id" name="kriteria_id" required>
<option value="" selected disabled>--Pilih Kriteria--</option>
@foreach ($kriteria->where('id', 3) as $kri)
<option value="{{ $kri->id }}">{{ $kri->nama_kriteria }}</option>
@endforeach
</select>
</div>
<!-- Input Nilai C1 - C6 -->
<div class="col-md-6 mb-3">
<div class="row">
<div class="col-4 mb-2">
<label for="nilai_c1" class="form-label">C1</label>
<input type="number" step="0.01" class="form-control" id="nilai_c1" name="nilai[C1]" required>
</div>
<div class="col-4 mb-2">
<label for="nilai_c2" class="form-label">C2</label>
<input type="number" step="0.01" class="form-control" id="nilai_c2" name="nilai[C2]" required>
</div>
<div class="col-4 mb-2">
<label for="nilai_c3" class="form-label">C3</label>
<input type="number" step="0.01" class="form-control" id="nilai_c3" name="nilai[C3]" required>
</div>
<div class="col-4 mb-2">
<label for="nilai_c4" class="form-label">C4</label>
<input type="number" step="0.01" class="form-control" id="nilai_c4" name="nilai[C4]" required>
</div>
<div class="col-4 mb-2">
<label for="nilai_c5" class="form-label">C5</label>
<input type="number" step="0.01" class="form-control" id="nilai_c5" name="nilai[C5]" required>
</div>
<div class="col-4 mb-2">
<label for="nilai_c6" class="form-label">C6</label>
<input type="number" step="0.01" class="form-control" id="nilai_c6" name="nilai[C6]" required>
</div>
</div>
</div>
</div>
<button type="submit" class="btn btn-success me-3">
<i class="bi bi-save"></i> Simpan
</button>
<button type="reset" class="btn btn-info">
<i class="bi bi-arrow-clockwise"></i> Reset
</button>
</form>
</div>
</div>
@endsection

View File

@ -76,43 +76,48 @@
</div>
<div class="row">
@foreach ($kriterias as $kriteria)
@foreach ($kriterias as $kriteria)
<div class="col-md-6 mb-3">
<label class="form-label fw-semibold">{{ $kriteria->nama_kriteria }}</label>
@if(in_array($kriteria->nama_kriteria, ['Jenis Acara', 'Lokasi', 'Cuaca']))
{{-- Checkbox group untuk multiple select --}}
@if(in_array($kriteria->id, $multiSelectKriteriaIds))
{{-- Multiple select: checkbox group --}}
<div class="checkbox-group d-flex flex-wrap gap-2">
@foreach ($kriteria->subKriteria as $subkriteria)
<div class="form-check">
<input type="checkbox"
<input
type="checkbox"
name="nilai[{{ $kriteria->id }}][]"
value="{{ $subkriteria->id }}"
id="sub_{{ $kriteria->id }}_{{ $subkriteria->id }}"
class="form-check-input"
{{ (isset($nilai[$kriteria->id]) && in_array($subkriteria->id, (array) $nilai[$kriteria->id])) ? 'checked' : '' }}>
<label for="sub_{{ $kriteria->id }}_{{ $subkriteria->id }}" class="form-check-label cursor-pointer">
{{ (isset($nilai[$kriteria->id]) && in_array($subkriteria->id, (array) $nilai[$kriteria->id])) ? 'checked' : '' }}
>
<label class="form-check-label" for="sub_{{ $kriteria->id }}_{{ $subkriteria->id }}">
{{ $subkriteria->nama_sub }}
</label>
</div>
@endforeach
</div>
<small class="form-text text-muted">Pilih satu atau lebih</small>
@else
{{-- Dropdown biasa untuk single select --}}
<select class="form-control" name="nilai[{{ $kriteria->id }}]" required>
<option value="">-- Pilih --</option>
@foreach ($kriteria->subKriteria as $subkriteria)
<option value="{{ $subkriteria->id }}"
{{ isset($nilai[$kriteria->id]) && $nilai[$kriteria->id] == $subkriteria->id ? 'selected' : '' }}>
{{ $subkriteria->nama_sub }}
</option>
@endforeach
</select>
@endif
</div>
@endforeach
</div>
<small class="form-text text-muted">Pilih satu atau lebih</small>
@else
{{-- Single select: dropdown --}}
<select class="form-control" name="nilai[{{ $kriteria->id }}]" required>
<option value="">-- Pilih --</option>
@foreach ($kriteria->subKriteria as $subkriteria)
<option
value="{{ $subkriteria->id }}"
{{ isset($nilai[$kriteria->id]) && $nilai[$kriteria->id] == $subkriteria->id ? 'selected' : '' }}
>
{{ $subkriteria->nama_sub }}
</option>
@endforeach
</select>
@endif
</div>
@endforeach
</div>
<button type="submit" class="btn" style="background-color: #064E3B; color: white;">
Simpan
</button>

View File

@ -0,0 +1,99 @@
@extends('admin.layouts.base')
@section('title', isset($penilaian) ? 'Edit Data Penilaian' : 'Tambah Data Penilaian')
@section('content')
<h1 class="h3 mb-4 text-grey-800">
<i class="bi bi-database"></i> Data Penilaian
</h1>
<div class="card shadow mb-4">
<div class="card-header bg-white d-flex justify-content-between align-items-center">
<span class="fw-bold" style="color: #14532d;">
{{ isset($penilaian) ? 'Edit Data Penilaian' : '+ Tambah Data Penilaian' }}
</span>
<a href="{{ route('admin.penilaian.index', ['page' => request('page')]) }}" class="btn btn-secondary">
<i class="bi bi-arrow-left"></i> Kembali
</a>
</div>
<div class="card-body">
@if ($errors->any())
<div class="alert alert-danger">
<ul class="mb-0">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form
action="{{ isset($penilaian) ? route('admin.penilaian.update', $penilaian->id) : route('admin.penilaian.store') }}"
method="POST">
@csrf
@if (isset($penilaian))
@method('PUT')
@endif
<div class="row">
<!-- Pilih Pakaian -->
<div class="col-md-6 mb-3">
<label for="pakaian_id" class="form-label">Nama Pakaian</label>
<select class="form-control" id="pakaian_id" name="pakaian_id" required>
<option value="" disabled {{ old('pakaian_id', $penilaian->pakaian_id ?? '') == '' ? 'selected' : '' }}>-- Pilih Pakaian --</option>
@foreach ($pakaians as $pakaian)
<option value="{{ $pakaian->id }}"
{{ old('pakaian_id', $penilaian->pakaian_id ?? '') == $pakaian->id ? 'selected' : '' }}>
{{ $pakaian->nama_pakaian }}
</option>
@endforeach
</select>
</div>
<!-- Pilih Sub Kriteria -->
<div class="col-md-6 mb-3">
<label for="sub_kriteria_id" class="form-label">Sub Kriteria</label>
<select class="form-control" id="sub_kriteria_id" name="sub_kriteria_id" required>
<option value="" disabled {{ old('sub_kriteria_id', $penilaian->sub_kriteria_id ?? '') == '' ? 'selected' : '' }}>-- Pilih Sub Kriteria --</option>
@foreach ($subkriterias as $sub)
<option value="{{ $sub->id }}"
{{ old('sub_kriteria_id', $penilaian->sub_kriteria_id ?? '') == $sub->id ? 'selected' : '' }}>
{{ $sub->nama_sub }}
</option>
@endforeach
</select>
</div>
<!-- Nilai -->
<div class="col-md-6 mb-3">
<label for="nilai" class="form-label">Nilai</label>
<select class="form-control" name="nilai" id="nilai" required>
<option value="" disabled {{ old('nilai', $penilaian->nilai ?? '') === '' ? 'selected' : '' }}>-- Pilih Nilai --</option>
<option value="1" {{ old('nilai', $penilaian->nilai ?? '') == '1' ? 'selected' : '' }}>1 - Sangat Tidak Cocok</option>
<option value="2" {{ old('nilai', $penilaian->nilai ?? '') == '2' ? 'selected' : '' }}>2 - Tidak Cocok</option>
<option value="3" {{ old('nilai', $penilaian->nilai ?? '') == '3' ? 'selected' : '' }}>3 - Cukup Cocok</option>
<option value="4" {{ old('nilai', $penilaian->nilai ?? '') == '4' ? 'selected' : '' }}>4 - Cocok</option>
<option value="5" {{ old('nilai', $penilaian->nilai ?? '') == '5' ? 'selected' : '' }}>5 - Sangat Cocok</option>
</select>
</div>
<div class="col-md-12 d-flex justify-content-between mt-3">
<div>
{{-- Tambahkan input hidden untuk simpan halaman --}}
<input type="hidden" name="page" value="{{ request('page') }}">
<button type="submit" class="btn" style="background-color: #064E3B; color: white;">
{{ isset($penilaian) ? 'Update' : 'Simpan' }}
</button>
<button type="reset" class="btn" style="background-color: #90ee90; color: black;">
<i class="bi bi-arrow-clockwise me-1"></i> Reset
</button>
</div>
</div>
</form>
</div>
</div>
@endsection

View File

@ -1,197 +1,188 @@
@extends('admin.layouts.base')
@section('title', 'Penilaian Pakaian')
@section('title', 'Data Penilaian Pakaian')
@section('content')
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3 text-grey-800">
<i class="bi bi-box"></i> Penilaian Pakaian
</h1>
</div>
<style>
.btn-hijau {
background-color: #064E3B;
color: white;
border: none;
padding: 6px 16px;
border-radius: 4px;
cursor: pointer;
}
<style>
.pagination {
display: flex;
justify-content: flex-end;
align-items: center;
padding: 10px;
}
.btn-hijau:hover {
background-color: #053B2D;
}
.pagination .page-item .page-link {
font-size: 14px;
padding: 6px 12px;
border-radius: 5px;
border: none;
color: white;
background-color: #064E3B;
margin: 0 2px;
transition: 0.3s ease-in-out;
}
.modern-select {
padding: 6px 12px;
border-radius: 8px;
border: 1px solid #ccc;
font-size: 14px;
background-color: #fff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
transition: border 0.2s ease-in-out;
}
.pagination .page-item.active .page-link {
background-color: #053B2D;
font-weight: bold;
}
.modern-select:focus {
border-color: #0d6efd;
outline: none;
}
.pagination .page-item .page-link:hover {
background-color: #046C4E;
}
.pagination {
display: flex;
justify-content: flex-end;
align-items: center;
padding: 10px;
}
.pagination .page-item.disabled .page-link {
background-color: #e9ecef;
color: #6c757d;
cursor: not-allowed;
}
.pagination .page-item .page-link {
font-size: 14px;
padding: 6px 12px;
border-radius: 5px;
border: none;
color: white;
background-color: #064E3B;
margin: 0 2px;
transition: 0.3s ease-in-out;
}
.form-select-sm,
.form-control-sm {
width: auto;
}
.pagination .page-item.active .page-link {
background-color: #053B2D;
font-weight: bold;
}
.search-input {
width: 200px;
}
.pagination .page-item .page-link:hover {
background-color: #046C4E;
}
.btn-biru {
background-color: #007bff;
color: white;
border: none;
padding: 6px 16px;
border-radius: 4px;
cursor: pointer;
}
.pagination .page-item.disabled .page-link {
background-color: #e9ecef;
color: #6c757d;
cursor: not-allowed;
}
</style>
.btn-biru:hover {
background-color: #0069d9;
}
@if (session('success'))
<div class="alert alert-success">{{ session('success') }}</div>
@endif
.search-box {
display: flex;
gap: 8px;
align-items: center;
}
.modern-select {
padding: 6px 12px;
border-radius: 8px;
border: 1px solid #ccc;
font-size: 14px;
background-color: #fff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
transition: border 0.2s ease-in-out;
}
.modern-select:focus {
border-color: #0d6efd;
outline: none;
}
</style>
<div class="card shadow mb-4">
<div class="card-header py-3 d-flex justify-content-between align-items-center">
<h6 class="m-0 font-weight-bold" style="color: #064E3B;">
<i class="bi bi-table"></i> Daftar Penilaian Pakaian
</h6>
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3 text-grey-800">
<i class="bi bi-clipboard-data"></i> Data Penilaian Pakaian
</h1>
<a href="{{ route('admin.penilaian.create') }}" class="btn btn-hijau">
<i class="bi bi-plus-circle"></i> Tambah Data
</a>
</div>
<div class="card shadow mb-4">
<div class="card-body">
{{-- GABUNGKAN FORM --}}
<form method="GET" action="{{ route('admin.penilaian.index') }}" class="d-flex justify-content-between align-items-center flex-wrap gap-3 mb-3">
<div class="d-flex align-items-center gap-2 mb-2 mb-md-0">
<label for="entriesPerPage" class="mb-0 text-muted fw-semibold" style="margin-right: 12px;">Show</label>
<select name="entries" id="entriesPerPage" class="modern-select" onchange="this.form.submit()">
<option value="10" {{ request('entries') == 10 ? 'selected' : '' }}>10</option>
<option value="25" {{ request('entries') == 25 ? 'selected' : '' }}>25</option>
<option value="50" {{ request('entries') == 50 ? 'selected' : '' }}>50</option>
</select>
<span class="text-muted fw-semibold" style="margin-left: 12px;">entries</span>
</div>
<form method="GET" class="d-flex justify-content-start align-items-center mb-3">
<label for="perPage" class="me-3 mt-1">Tampilkan</label>
<div class="search-box">
<input type="text" name="search" value="{{ request('search') }}" placeholder="Cari nama alternatif..." class="form-control form-control-sm search-input">
<button type="submit" class="btn btn-sm" style="background-color: #14532d; color: white;">Cari</button>
</div>
<select name="perPage" id="perPage" class="modern-select mx-2" onchange="this.form.submit()">
@foreach([10, 50, 100, 500, 1000] as $size)
<option value="{{ $size }}" {{ request('perPage', 10) == $size ? 'selected' : '' }}>
{{ $size }}
</option>
@endforeach
</select>
<label class="ms-2 mt-1">entri</label>
</form>
<div class="table-responsive">
<table class="table table-bordered" width="100%" cellspacing="0">
<thead>
<tr>
<th class="text-center">No</th>
<th class="text-center">Nama Pakaian</th>
{{-- Header Kriteria --}}
@foreach ($kriterias as $kriteria)
<th class="text-center">{{ $kriteria->nama_kriteria }}</th>
@endforeach
<th class="text-center">Aksi</th>
</tr>
</thead>
<tbody>
@forelse ($pakaians as $item)
<tr>
<td class="text-center">{{ $loop->iteration }}</td>
<td class="text-center">{{ $item->nama_pakaian ?? '-' }}</td>
<form method="GET" class="d-flex justify-content-end mb-3">
{{-- Pertahankan nilai perPage --}}
<input type="hidden" name="perPage" value="{{ request('perPage', 10) }}">
{{-- Subkriteria --}}
@foreach ($kriterias as $kriteria)
@php
$subKriterias = $item->subKriterias->where('kriteria_id', $kriteria->id);
$namaSubs = $subKriterias->pluck('nama_sub')->toArray();
@endphp
<td class="text-center">
@if (count($namaSubs))
@if ($kriteria->nama_kriteria === 'Jenis Acara')
<div class="d-flex flex-wrap justify-content-center gap-2">
@foreach ($namaSubs as $nama)
<span class="rounded-pill px-3 py-1 bg-light border text-dark small shadow-sm">
{{ $nama }}
</span>
@endforeach
</div>
@else
{{ $namaSubs[0] ?? '-' }}
@endif
@else
<span class="text-muted">-</span>
@endif
</td>
@endforeach
<input type="text" name="search" value="{{ request('search') }}" placeholder="Cari pakaian..."
class="form-control form-control-sm" style="width: 200px; margin-right: 8px;">
<button type="submit" class="btn btn-success btn-sm" style="background-color: #14532d; border: none;">
Cari
</button>
</form>
<td class="text-center">
<a href="{{ route('admin.penilaian.edit', $item->id) }}" class="btn btn-warning btn-sm">
<i class="bi bi-pencil"></i>
</a>
</td>
</tr>
@empty
<tr>
<td colspan="{{ 3 + $kriterias->count() }}" class="text-center">Belum ada data penilaian.</td>
</tr>
@endforelse
</tbody>
</table>
</div>
<div class="table-responsive">
<table class="table table-bordered table-striped align-middle text-center">
<thead class="table-light">
<tr>
<th>No</th>
<th>Pakaian</th>
<th>Kriteria</th>
<th>Sub Kriteria</th>
<th>Nilai</th>
<th>Aksi</th>
</tr>
</thead>
<tbody>
@forelse ($penilaians as $index => $penilaian)
<tr>
<td>{{ $loop->iteration }}</td>
<td>{{ $penilaian->pakaian->nama_pakaian ?? '-' }}</td>
<td>{{ $penilaian->subKriteria->kriteria->nama_kriteria ?? '-' }}</td>
<td>{{ $penilaian->subKriteria->nama_sub ?? '-' }}</td>
<td>{{ $penilaian->nilai ?? '-' }}</td>
<td>
<a href="{{ route('admin.penilaian.edit', ['penilaian' => $penilaian->id, 'page' => request('page')]) }}"
class="btn btn-warning btn-sm">
<i class="bi bi-pencil-square"></i>
</a>
<form id="delete-form-{{ $penilaian->id }}" action="{{ route('admin.penilaian.destroy', $penilaian->id) }}" method="POST" style="display: inline;">
@csrf
@method('DELETE')
<button type="button" class="btn btn-danger btn-sm delete-button" data-id="{{ $penilaian->id }}">
<i class="bi bi-trash"></i>
</button>
</form>
</td>
</tr>
@empty
<tr>
<td colspan="6" class="text-muted">Tidak ada data penilaian tersedia.</td>
</tr>
@endforelse
</tbody>
</table>
</div>
<div class="mt-3">
{{-- BAWA PARAMETER PAGINATION --}}
{{ $pakaians->appends(['entries' => request('entries'), 'search' => request('search')])->links('pagination::bootstrap-4') }}
<div class="d-flex justify-content-end">
{{ $penilaians->appends(request()->query())->links('vendor.pagination.bootstrap-5') }}
</div>
</div>
</div>
</div>
<!-- SweetAlert CDN -->
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script>
document.addEventListener('DOMContentLoaded', function () {
const deleteButtons = document.querySelectorAll('.delete-button');
@if (session('success'))
<script>
Swal.fire({
title: 'Berhasil!',
text: '{{ session('success') }}',
icon: 'success',
timer: 3000,
showConfirmButton: false
});
</script>
@endif
deleteButtons.forEach(button => {
button.addEventListener('click', function () {
const id = this.getAttribute('data-id');
Swal.fire({
title: 'Yakin ingin menghapus data ini?',
text: "Data yang dihapus tidak bisa dikembalikan!",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#d33',
cancelButtonColor: '#3085d6',
confirmButtonText: 'Ya, hapus!',
cancelButtonText: 'Batal'
}).then((result) => {
if (result.isConfirmed) {
document.getElementById(`delete-form-${id}`).submit();
}
});
});
});
});
</script>
@endsection

View File

@ -1,138 +0,0 @@
@extends('admin.layouts.base')
@section('title', 'Riwayat Perhitungan')
@section('content')
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h3 text-grey-800">
<i class="bi bi-hourglass-split"></i> Riwayat Hasil Perhitungan
</h1>
</div>
<div class="card shadow mb-4">
<div class="card-header py-3 d-flex justify-content-between align-items-center">
<h6 class="m-0 font-weight-bold" style="color: #064E3B;">
<i class="bi bi-table"></i> Daftar Riwayat Hasil Perhitungan
</h6>
</div>
<div class="card-body">
<form method="GET" class="mb-3 d-flex align-items-center">
<label for="per_page" class="me-2 mb-0">Tampilkan</label>
<select name="per_page" id="per_page" class="form-select form-select-sm w-auto me-2" onchange="this.form.submit()">
@foreach([5, 10, 20, 30] as $value)
<option value="{{ $value }}" {{ request('per_page', 5) == $value ? 'selected' : '' }}>
{{ $value }}
</option>
@endforeach
</select>
<span class="mb-0">entri</span>
</form>
<div class="table-responsive">
<table class="table table-bordered" width="100%" cellspacing="0">
<thead>
<tr>
<th class="text-center">No</th>
<th class="text-center">Tanggal</th>
<th class="text-center">Aksi</th>
</tr>
</thead>
<tbody>
@foreach ($riwayat as $index => $item)
<tr>
<td class="text-center">{{ $riwayat->firstItem() + $index }}</td>
<td class="text-center">{{ $item->created_at->setTimezone('Asia/Jakarta')->format('d M Y H:i') }}</td>
<td class="text-center">
<button class="btn btn-sm btn-success" data-bs-toggle="modal" data-bs-target="#modalRiwayat{{ $item->id }}">
<i class="bi bi-folder2-open"></i>
</button>
<form id="delete-form-{{ $item->id }}" action="{{ route('admin.riwayat.destroy', $item->id) }}" method="POST" class="d-inline">
@csrf
@method('DELETE')
<button type="button" class="btn btn-sm btn-danger" onclick="confirmDelete({{ $item->id }})">
<i class="bi bi-trash"></i>
</button>
</form>
</td>
</tr>
<!-- Modal Detail -->
<div class="modal fade" id="modalRiwayat{{ $item->id }}" tabindex="-1" aria-labelledby="modalLabel{{ $item->id }}" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modalLabel{{ $item->id }}">Detail Riwayat</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<h6>Jawaban Kuisioner:</h6>
@php
$kuisioner = is_string($item->data_kuisioner) ? json_decode($item->data_kuisioner, true) : $item->data_kuisioner;
@endphp
<ul>
@if (is_array($kuisioner))
@foreach ($kuisioner as $key => $value)
<li><strong>{{ ucfirst($key) }}:</strong> {{ $value }}</li>
@endforeach
@else
<li>Data kuisioner tidak tersedia.</li>
@endif
</ul>
<h6 class="mt-3">Hasil Rekomendasi:</h6>
@php
$rekomendasi = is_string($item->hasil_rekomendasi) ? json_decode($item->hasil_rekomendasi, true) : $item->hasil_rekomendasi;
@endphp
<ol>
@if (is_array($rekomendasi))
@foreach ($rekomendasi as $produk)
<li>
{{ is_array($produk) ? ($produk['nama'] ?? implode(', ', $produk)) : $produk }}
</li>
@endforeach
@else
<li>Tidak ada rekomendasi.</li>
@endif
</ol>
</div>
</div>
</div>
</div>
@endforeach
</tbody>
</table>
<div class="mt-3">
{{ $riwayat->links('pagination::bootstrap-5') }}
</div>
</div>
</div>
</div>
@push('scripts')
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script>
function confirmDelete(id) {
Swal.fire({
title: 'Yakin ingin menghapus?',
text: "Data riwayat akan dihapus permanen!",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#d33',
cancelButtonColor: '#6c757d',
confirmButtonText: 'Ya, hapus!',
cancelButtonText: 'Batal'
}).then((result) => {
if (result.isConfirmed) {
document.getElementById('delete-form-' + id).submit();
}
});
}
</script>
@endpush
@endsection

View File

@ -31,7 +31,6 @@
<tr>
<th class="text-center">No</th>
<th class="text-center">Nama Subkriteria</th>
<th class="text-center">Nilai</th>
<th class="text-center">Min Harga</th>
<th class="text-center">Max Harga</th>
<th class="text-center">Aksi</th>
@ -42,7 +41,6 @@
<tr>
<td class="text-center">{{ $key + 1 }}</td>
<td class="text-center">{{ $sub->nama_sub }}</td>
<td class="text-center">{{ $sub->nilai }}</td>
<td class="text-center">{{ $sub->min_harga ?? '-' }}</td>
<td class="text-center">{{ $sub->max_harga ?? '-' }}</td>
<td class="text-center">
@ -104,11 +102,6 @@
<input type="text" class="form-control" id="nama_sub" name="nama_sub" required>
</div>
<div class="mb-3">
<label for="nilai" class="form-label">Nilai</label>
<input type="number" class="form-control" id="nilai" name="nilai" step="1" required>
</div>
<div id="harga-fields" style="display: none;">
<div class="mb-3">
<label for="min_harga" class="form-label">Min Harga</label>
@ -167,11 +160,6 @@
<input type="text" class="form-control" name="nama_sub" value="{{ $sub->nama_sub }}" required>
</div>
<div class="mb-3">
<label for="nilai" class="form-label">Nilai</label>
<input type="number" class="form-control" name="nilai" value="{{ $sub->nilai }}" required>
</div>
<div class="harga-fields" id="hargaFields{{ $sub->id }}" style="display: none;">
<div class="mb-3">
<label for="min_harga" class="form-label">Min Harga</label>

View File

@ -21,7 +21,7 @@
</div>
@endif
<form action="{{ route('user.update', $user->id) }}" method="POST">
<form action="{{ route('admin.user.update', $user->id) }}" method="POST">
@csrf
@method('PUT')
<div class="mb-3">
@ -47,7 +47,7 @@
<button type="submit" class="btn btn-success" style="background-color: #064e03; border-color: #064e03;">
Simpan
</button>
<a href="{{ route('user.show', $user->id) }}" class="btn btn-success" style="background-color: #a6f4a3; border-color: #a6f4a3; color: #064e03;">
<a href="{{ route('admin.user.show', $user->id) }}" class="btn btn-success" style="background-color: #a6f4a3; border-color: #a6f4a3; color: #064e03;">
Kembali
</a>
</form>

View File

@ -36,7 +36,7 @@
</table>
<div class="mt-4 text-end">
<a href="{{ route('user.edit', $user->id) }}" class="btn" style="background-color: #064e03; color: white;">
<a href="{{ route('admin.user.edit', $user->id) }}" class="btn" style="background-color: #064e03; color: white;">
<i class="bi bi-pencil-square"></i> Edit Profil
</a>
</div>

View File

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<title>Pengingat Username</title>
</head>
<body style="font-family: Arial, sans-serif; color: #333;">
<div style="max-width: 600px; margin: 0 auto; padding: 20px;">
<h2 style="color: #2f855a;">Halo {{ $user->name ?? 'Pengguna' }},</h2>
<p>Berikut adalah username yang terdaftar dengan email ini:</p>
<p><strong>Username Anda:</strong> {{ $user->username }}</p>
<br>
<p>Jika Anda tidak meminta informasi ini, abaikan email ini.</p>
<p>Terima kasih.</p>
<hr>
<p style="font-size: 12px; color: #888;">Email ini dikirim secara otomatis oleh sistem kami.</p>
</div>
</body>
</html>

View File

@ -1,3 +1,5 @@
@php use Illuminate\Support\Str; @endphp
<section class="py-3 bg-white" id="daftarpakaian">
<div class="container">
<div class="row justify-content-center text-center">
@ -9,803 +11,115 @@
</div>
</div>
<!-- Tab Navigasi -->
<div class="row justify-content-center mb-4">
<div class="col-auto">
<ul class="nav nav-pills gap-2 justify-content-center" id="pakaianTab" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="dress-tab" data-bs-toggle="tab" data-bs-target="#dress" type="button" role="tab">Dress</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="blouse-tab" data-bs-toggle="tab" data-bs-target="#blouse" type="button" role="tab">Blouse</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="cardigan-tab" data-bs-toggle="tab" data-bs-target="#cardigan" type="button" role="tab">Cardigan</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="rok-tab" data-bs-toggle="tab" data-bs-target="#rok" type="button" role="tab">Rok</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="celana-tab" data-bs-toggle="tab" data-bs-target="#celana" type="button" role="tab">Celana</button>
</li>
</ul>
</div>
@php
$kategoriList = ['Dress', 'Blouse', 'Cardigan', 'Rok', 'Celana'];
@endphp
{{-- Tombol filter --}}
<div class="d-flex justify-content-center mb-4 flex-wrap gap-2">
<button class="btn btn-outline-primary btn-sm filter-btn active" data-kategori="all">Semua</button>
@foreach ($kategoriList as $kategori)
<button class="btn btn-outline-secondary btn-sm filter-btn" data-kategori="{{ strtolower($kategori) }}">{{ $kategori }}</button>
@endforeach
</div>
<!-- Isi Tab -->
<div class="tab-content" id="pakaianTabContent">
<!-- Dress (active tab) -->
<div class="tab-pane fade show active" id="dress" role="tabpanel" aria-labelledby="dress-tab">
<div class="container">
<div class="row g-3 gy-4 justify-content-center">
{{-- Daftar pakaian --}}
<div class="row g-2" id="pakaian-list">
@foreach ($pakaians as $pakaian)
@php
$kategoriSub = $pakaian->subKriterias->firstWhere('kriteria_id', 3);
$kategori = $kategoriSub ? Str::lower($kategoriSub->nama_sub) : null;
@endphp
@if ($kategori)
<div class="col-6 col-sm-4 col-md-3 col-lg-2 pakaian-item kategori-{{ $kategori }}">
<div class="card h-100 border-0 shadow-sm"
data-nama="{{ $pakaian->nama_pakaian }}"
data-img="{{ $pakaian->img ? asset($pakaian->img) : '' }}"
data-harga="Rp{{ number_format($pakaian->harga, 0, ',', '.') }}"
data-deskripsi="{{ $pakaian->deskripsi }}"
onclick="showDetailModal(this)">
<!-- Card Dress 1 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card border-0 shadow-sm h-100 card-hover">
<div class="overflow-hidden rounded-top">
<img src="assets/img/annelisedress.jpg" class="card-img-top img-fluid hover-zoom" alt="Dress 1">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Annelise Dress</h6>
<p class="text-muted small mb-1">
Dress cantik dengan potongan elegan, cocok untuk acara semi-formal atau hangout santai.
</p>
<p class="fw-semibold text-primary mb-0">Rp. 185.000</p>
</div>
</div>
</div>
@if ($pakaian->img && file_exists(public_path($pakaian->img)))
<img src="{{ asset($pakaian->img) }}" class="card-img-top" alt="{{ $pakaian->nama_pakaian }}" style="height: 150px; object-fit: cover;">
@else
<div class="bg-light d-flex align-items-center justify-content-center" style="height:150px;">
<span class="text-muted small">Gambar tidak tersedia</span>
</div>
@endif
<!-- Card Dress 2 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card border-0 shadow-sm h-100 card-hover">
<div class="overflow-hidden rounded-top">
<img src="assets/img/daisysilkdress.jpg" class="card-img-top img-fluid hover-zoom" alt="Dress 2">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Daisy Silk Dress</h6>
<p class="text-muted small mb-1">Dress berbahan silk lembut, memberikan kesan mewah dan anggun saat dipakai.</p>
<p class="fw-semibold text-primary mb-0">Rp. 189.000</p>
</div>
</div>
</div>
<!-- Card Dress 3 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card border-0 shadow-sm h-100 card-hover">
<div class="overflow-hidden rounded-top">
<img src="assets/img/edeliadress.jpg" class="card-img-top img-fluid hover-zoom" alt="Dress 3">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Edelia Dress</h6>
<p class="text-muted small mb-1">Dress feminin dengan detail renda, cocok untuk tampilan anggun dan stylish.</p>
<p class="fw-semibold text-primary mb-0">Rp. 269.000</p>
</div>
</div>
</div>
<!-- Card Dress 4 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card border-0 shadow-sm h-100 card-hover">
<div class="overflow-hidden rounded-top">
<img src="assets/img/embroiderytunik.jpg" class="card-img-top img-fluid hover-zoom" alt="Dress 4">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Embroidery Tunik</h6>
<p class="text-muted small mb-1">Tunik dengan bordir cantik yang memberikan nuansa etnik dan elegan.</p>
<p class="fw-semibold text-primary mb-0">Rp. 249.000</p>
</div>
</div>
</div>
<!-- Card Dress 5 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card border-0 shadow-sm h-100 card-hover">
<div class="overflow-hidden rounded-top">
<img src="assets/img/shimmerraya.jpg" class="card-img-top img-fluid hover-zoom" alt="Dress 5">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Shimmer Raya Dress</h6>
<p class="text-muted small mb-1">Dress dengan efek shimmer elegan, ideal untuk momen spesial seperti lebaran atau pesta malam.</p>
<p class="fw-semibold text-primary mb-0">Rp. 189.000</p>
</div>
</div>
</div>
<!-- Card Dress 6 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card border-0 shadow-sm h-100 card-hover">
<div class="overflow-hidden rounded-top">
<img src="assets/img/elenadress.jpg" class="card-img-top img-fluid hover-zoom" alt="Dress 6">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Elena Dress</h6>
<p class="text-muted small mb-1">Gaya simpel nan chic, cocok untuk daily wear maupun acara santai.</p>
<p class="fw-semibold text-primary mb-0">Rp. 189.000</p>
</div>
</div>
</div>
<!-- Card Dress 7 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card border-0 shadow-sm h-100 card-hover">
<div class="overflow-hidden rounded-top">
<img src="assets/img/asterdress.jpg" class="card-img-top img-fluid hover-zoom" alt="Dress 7">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Aster Dress</h6>
<p class="text-muted small mb-1">Dress floral dengan desain flowy, memberikan kesan segar dan feminin.</p>
<p class="fw-semibold text-primary mb-0">Rp. 179.000</p>
</div>
</div>
</div>
<!-- Card Dress 8 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card border-0 shadow-sm h-100 card-hover">
<div class="overflow-hidden rounded-top">
<img src="assets/img/orchidflowy.jpg" class="card-img-top img-fluid hover-zoom" alt="Dress 8">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Orchid Flowy Dress</h6>
<p class="text-muted small mb-1">Dress longgar dengan potongan flowy, cocok untuk gaya kasual elegan.</p>
<p class="fw-semibold text-primary mb-0">Rp. 179.000</p>
</div>
</div>
</div>
<!-- Card Dress 9 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card border-0 shadow-sm h-100 card-hover">
<div class="overflow-hidden rounded-top">
<img src="assets/img/adelinedress.jpg" class="card-img-top img-fluid hover-zoom" alt="Dress 9">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Adeline Dress</h6>
<p class="text-muted small mb-1">Dress klasik dengan siluet ramping yang memberi kesan elegan dan dewasa.</p>
<p class="fw-semibold text-primary mb-0">Rp. 189.000</p>
</div>
</div>
</div>
<!-- Card Dress 10 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card border-0 shadow-sm h-100 card-hover">
<div class="overflow-hidden rounded-top">
<img src="assets/img/daphnedress.jpg" class="card-img-top img-fluid hover-zoom" alt="Dress 10">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Daphne Dress</h6>
<p class="text-muted small mb-1">Dress glamor dengan detail elegan, cocok untuk acara formal atau pesta malam.</p>
<p class="fw-semibold text-primary mb-0">Rp. 269.000</p>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Blouse -->
<div class="tab-pane fade" id="blouse" role="tabpanel" aria-labelledby="blouse-tab">
<div class="container">
<div class="row g-3 gy-4 justify-content-center">
<!-- Card Blouse 1 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/arianablouse.jpg" class="card-img-top img-fluid hover-zoom" alt="Blouse 1">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Ariana Blouse</h6>
<p class="small mb-1">Blouse elegan dengan sentuhan feminin dan detail ruffle yang anggun.</p>
<p class="fw-semibold text-primary mb-0">Rp. 159.000</p>
</div>
</div>
</div>
<!-- Card Blouse 2 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/charlotteblouse.jpg" class="card-img-top img-fluid hover-zoom" alt="Blouse 2">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Charlotte Blouse</h6>
<p class="small mb-1">Desain simple namun elegan dengan bahan adem dan nyaman dikenakan seharian.</p>
<p class="fw-semibold text-primary mb-0">Rp. 139.000</p>
</div>
</div>
</div>
<!-- Card Blouse 3 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/keirablouse.jpg" class="card-img-top img-fluid hover-zoom" alt="Blouse 3">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Keira Blouse</h6>
<p class="small mb-1">Blouse klasik dengan detail lipit dan bahan flowy yang elegan.</p>
<p class="fw-semibold text-primary mb-0">Rp. 125.000</p>
</div>
</div>
</div>
<!-- Card Blouse 4 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/aurelieblouse.jpg" class="card-img-top img-fluid hover-zoom" alt="Blouse 4">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Aurelie Blouse</h6>
<p class="small mb-1">Tampil chic dengan blouse berpotongan loose dan motif lembut yang manis.</p>
<p class="fw-semibold text-primary mb-0">Rp. 120.000</p>
</div>
</div>
</div>
<!-- Card Blouse 5 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/elynalace.jpg" class="card-img-top img-fluid hover-zoom" alt="Blouse 5">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Elyna Lace Blouse</h6>
<p class="small mb-1">Blouse dengan aksen renda klasik yang memberikan kesan feminin dan anggun.</p>
<p class="fw-semibold text-primary mb-0">Rp. 129.000</p>
</div>
</div>
</div>
<!-- Card Blouse 6 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/louisablouse.jpg" class="card-img-top img-fluid hover-zoom" alt="Blouse 6">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Louisa Blouse</h6>
<p class="small mb-1">Model simpel dengan warna solid yang cocok dipadukan dengan berbagai bawahan.</p>
<p class="fw-semibold text-primary mb-0">Rp. 109.000</p>
</div>
</div>
</div>
<!-- Card Blouse 7 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/azuraetnic.jpg" class="card-img-top img-fluid hover-zoom" alt="Blouse 7">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Azura Etnic Blouse</h6>
<p class="small mb-1">Sentuhan etnik yang unik dengan kombinasi motif dan warna menarik.</p>
<p class="fw-semibold text-primary mb-0">Rp. 125.000</p>
</div>
</div>
</div>
<!-- Card Blouse 8 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/freyaetnic.jpg" class="card-img-top img-fluid hover-zoom" alt="Blouse 8">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Freya Etnic Blouse</h6>
<p class="small mb-1">Blouse etnik modern dengan bahan ringan dan nyaman untuk sehari-hari.</p>
<p class="fw-semibold text-primary mb-0">Rp. 139.000</p>
</div>
</div>
</div>
<!-- Card Blouse 9 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/celiablouse.jpg" class="card-img-top img-fluid hover-zoom" alt="Blouse 9">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Celia Blouse</h6>
<p class="small mb-1">Blouse casual yang cocok dipakai ke kantor ataupun hangout santai.</p>
<p class="fw-semibold text-primary mb-0">Rp. 129.000</p>
</div>
</div>
</div>
<!-- Card Blouse 10 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/elaineblouse.jpg" class="card-img-top img-fluid hover-zoom" alt="Blouse 10">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Elaine Blouse</h6>
<p class="small mb-1">Tampil stylish dan tetap sopan dengan blouse berkerah lembut dan potongan flowy.</p>
<p class="fw-semibold text-primary mb-0">Rp. 128.000</p>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Cardigan -->
<div class="tab-pane fade" id="cardigan" role="tabpanel" aria-labelledby="cardigan-tab">
<div class="container">
<div class="row g-3 gy-4 justify-content-center">
<!-- Cardigan 1 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/brielleribbon.jpg" class="card-img-top img-fluid hover-zoom" alt="Cardigan 1">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Brielle Ribbon Cardigan</h6>
<p class="small mb-1">Cardigan manis dengan detail pita untuk tampilan girly yang chic.</p>
<p class="fw-semibold text-primary mb-0">Rp. 130.000</p>
</div>
</div>
</div>
<!-- Cardigan 2 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/rubycardigan.jpg" class="card-img-top img-fluid hover-zoom" alt="Cardigan 2">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Ruby Cardigan</h6>
<p class="small mb-1">Warna merah yang bold dengan desain simple dan elegan.</p>
<p class="fw-semibold text-primary mb-0">Rp. 139.000</p>
</div>
</div>
</div>
<!-- Cardigan 3 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/roseknit.jpg" class="card-img-top img-fluid hover-zoom" alt="Cardigan 3">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Rose Knit Cardigan</h6>
<p class="small mb-1">Cardigan rajut lembut yang cocok untuk suasana santai dan hangat.</p>
<p class="fw-semibold text-primary mb-0">Rp. 120.000</p>
</div>
</div>
</div>
<!-- Cardigan 4 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/camelliacardigan.jpg" class="card-img-top img-fluid hover-zoom" alt="Cardigan 4">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Camellia Cardigan</h6>
<p class="small mb-1">Gaya feminin dengan potongan loose dan aksen floral cantik.</p>
<p class="fw-semibold text-primary mb-0">Rp. 169.000</p>
</div>
</div>
</div>
<!-- Cardigan 5 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/cholecardigan.jpg" class="card-img-top img-fluid hover-zoom" alt="Cardigan 5">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Chole Cardigan</h6>
<p class="small mb-1">Tampil stylish dan cozy dengan desain minimalis nan modis.</p>
<p class="fw-semibold text-primary mb-0">Rp. 189.000</p>
</div>
</div>
</div>
<!-- Cardigan 6 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/jadestripes.jpg" class="card-img-top img-fluid hover-zoom" alt="Cardigan 6">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Jade Stripes Cardigan</h6>
<p class="small mb-1">Cardigan bergaris klasik dengan kesan kasual yang kekinian.</p>
<p class="fw-semibold text-primary mb-0">Rp. 139.000</p>
</div>
</div>
</div>
<!-- Cardigan 7 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/giselleknit.jpg" class="card-img-top img-fluid hover-zoom" alt="Cardigan 7">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Giselle Knit Top</h6>
<p class="small mb-1">Blouse rajut modis yang cocok untuk layer outfit harian.</p>
<p class="fw-semibold text-primary mb-0">Rp. 149.000</p>
</div>
</div>
</div>
<!-- Cardigan 8 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/stripesfur.jpg" class="card-img-top img-fluid hover-zoom" alt="Cardigan 8">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Stripes Fur Cardigan</h6>
<p class="small mb-1">Cardigan berbulu halus dengan motif garis untuk tampilan cozy.</p>
<p class="fw-semibold text-primary mb-0">Rp. 149.000</p>
</div>
</div>
</div>
<!-- Cardigan 9 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/polostripes.jpg" class="card-img-top img-fluid hover-zoom" alt="Cardigan 9">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Polo Stripes Knit</h6>
<p class="small mb-1">Cardigan dengan kerah polo dan motif stripes yang sporty casual.</p>
<p class="fw-semibold text-primary mb-0">Rp. 169.000</p>
</div>
</div>
</div>
<!-- Cardigan 10 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/ribbonfur.jpg" class="card-img-top img-fluid hover-zoom" alt="Cardigan 10">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Ribbon Fur Cardigan</h6>
<p class="small mb-1">Sentuhan bulu halus dan aksen pita menjadikan cardigan ini elegan dan unik.</p>
<p class="fw-semibold text-primary mb-0">Rp. 169.000</p>
</div>
<p class="card-title mb-1 fw-semibold small" style="font-size: 0.85rem;">
{{ Str::limit($pakaian->nama_pakaian, 35) }}
</p>
<p class="fw-bold text-danger mb-0" style="font-size: 0.9rem;">
Rp{{ number_format($pakaian->harga, 0, ',', '.') }}
</p>
@if ($pakaian->deskripsi)
<p class="text-muted mb-0" style="font-size: 0.75rem;">
{{ Str::limit($pakaian->deskripsi, 50) }}
</p>
@endif
</div>
</div>
</div>
</div>
</div>
<!-- Rok -->
<div class="tab-pane fade" id="rok" role="tabpanel" aria-labelledby="rok-tab">
<div class="container">
<div class="row g-3 gy-4 justify-content-center">
<!-- Rok 1 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/knitskirt.jpg" class="card-img-top img-fluid hover-zoom" alt="Knit Skirt">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Knit Skirt</h6>
<p class="small mb-1">Rok rajut lembut dan nyaman untuk gaya kasual harian.</p>
<p class="fw-semibold text-primary mb-0">Rp. 149.000</p>
</div>
</div>
</div>
<!-- Rok 2 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/kireiflare.jpg" class="card-img-top img-fluid hover-zoom" alt="Kirei Flare Skirt">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Kirei Flare Skirt</h6>
<p class="small mb-1">Rok flare dengan potongan anggun dan flowy, cocok untuk hangout.</p>
<p class="fw-semibold text-primary mb-0">Rp. 169.000</p>
</div>
</div>
</div>
<!-- Rok 3 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/mermaidjeans.jpg" class="card-img-top img-fluid hover-zoom" alt="Mermaid Jeans Skirt">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Mermaid Jeans Skirt</h6>
<p class="small mb-1">Rok denim model duyung yang feminin dan trendi.</p>
<p class="fw-semibold text-primary mb-0">Rp. 169.000</p>
</div>
</div>
</div>
<!-- Rok 4 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/vionamermaid.jpg" class="card-img-top img-fluid hover-zoom" alt="Viona Mermaid Skirt">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Viona Mermaid Skirt</h6>
<p class="small mb-1">Rok potongan duyung dengan bahan ringan dan jatuh.</p>
<p class="fw-semibold text-primary mb-0">Rp. 139.000</p>
</div>
</div>
</div>
<!-- Rok 5 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/floralskirt.jpg" class="card-img-top img-fluid hover-zoom" alt="Floral Skirt">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Floral Skirt</h6>
<p class="small mb-1">Motif bunga manis untuk tampilan feminin dan segar.</p>
<p class="fw-semibold text-primary mb-0">Rp. 109.000</p>
</div>
</div>
</div>
<!-- Rok 6 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/fleurskirt.jpg" class="card-img-top img-fluid hover-zoom" alt="Fleur Embroidery Skirt">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Fleur Embroidery Skirt</h6>
<p class="small mb-1">Detail bordir bunga elegan dan classy.</p>
<p class="fw-semibold text-primary mb-0">Rp. 139.000</p>
</div>
</div>
</div>
<!-- Rok 7 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/belleskirt.jpg" class="card-img-top img-fluid hover-zoom" alt="Belle Skirt">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Belle Skirt</h6>
<p class="small mb-1">Desain simpel dan manis, mudah dipadu-padankan.</p>
<p class="fw-semibold text-primary mb-0">Rp. 105.000</p>
</div>
</div>
</div>
<!-- Rok 8 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/mermaidskirt.jpg" class="card-img-top img-fluid hover-zoom" alt="Mermaid Skirt">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Mermaid Skirt</h6>
<p class="small mb-1">Potongan mermaid yang mempercantik siluet tubuh.</p>
<p class="fw-semibold text-primary mb-0">Rp. 120.000</p>
</div>
</div>
</div>
<!-- Rok 9 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/silkruffle.jpg" class="card-img-top img-fluid hover-zoom" alt="Silk Ruffle Skirt">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Silk Ruffle Skirt</h6>
<p class="small mb-1">Rok sutra dengan detail ruffle yang lembut dan elegan.</p>
<p class="fw-semibold text-primary mb-0">Rp. 120.000</p>
</div>
</div>
</div>
<!-- Rok 10 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/arabellaruffle.jpg" class="card-img-top img-fluid hover-zoom" alt="Arabella Ruffle Skirt">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Arabella Ruffle Skirt</h6>
<p class="small mb-1">Rok detail ruffle manis dengan potongan feminin.</p>
<p class="fw-semibold text-primary mb-0">Rp. 116.000</p>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Celana -->
<div class="tab-pane fade" id="celana" role="tabpanel" aria-labelledby="celana-tab">
<div class="container">
<div class="row g-3 gy-4 justify-content-center">
<!-- Celana 1 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/cutbrayjeans.jpg" class="card-img-top img-fluid hover-zoom" alt="Cutbray Jeans Pants">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Cutbray Jeans Pants</h6>
<p class="small mb-1">Celana jeans model cutbray yang unik dan stylish.</p>
<p class="fw-semibold text-primary mb-0">Rp. 159.000</p>
</div>
</div>
</div>
<!-- Celana 2 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/anneflare.jpg" class="card-img-top img-fluid hover-zoom" alt="Anne Flare Jeans">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Anne Flare Jeans</h6>
<p class="small mb-1">Jeans flare yang mempertegas siluet kaki, cocok untuk OOTD.</p>
<p class="fw-semibold text-primary mb-0">Rp. 169.000</p>
</div>
</div>
</div>
<!-- Celana 3 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/cutbraypants.jpg" class="card-img-top img-fluid hover-zoom" alt="Cutbray Pants">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Cutbray Pants</h6>
<p class="small mb-1">Potongan klasik cutbray untuk tampilan retro modern.</p>
<p class="fw-semibold text-primary mb-0">Rp. 109.000</p>
</div>
</div>
</div>
<!-- Celana 4 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/laurahighwaist.jpg" class="card-img-top img-fluid hover-zoom" alt="Laura Highwaist Pants">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Laura Highwaist Pants</h6>
<p class="small mb-1">Model highwaist elegan yang cocok untuk kerja maupun santai.</p>
<p class="fw-semibold text-primary mb-0">Rp. 149.000</p>
</div>
</div>
</div>
<!-- Celana 5 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/flowypants.jpg" class="card-img-top img-fluid hover-zoom" alt="Flowy Pants">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Flowy Pants</h6>
<p class="small mb-1">Celana longgar dengan bahan ringan dan jatuh.</p>
<p class="fw-semibold text-primary mb-0">Rp. 109.000</p>
</div>
</div>
</div>
<!-- Celana 6 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/casualpants.jpg" class="card-img-top img-fluid hover-zoom" alt="Casual Pants">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Casual Pants</h6>
<p class="small mb-1">Gaya kasual yang fleksibel untuk sehari-hari.</p>
<p class="fw-semibold text-primary mb-0">Rp. 109.000</p>
</div>
</div>
</div>
<!-- Celana 7 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/celinepants.jpg" class="card-img-top img-fluid hover-zoom" alt="Celine Pants">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Celine Pants</h6>
<p class="small mb-1">Celana dengan potongan rapi dan bahan adem.</p>
<p class="fw-semibold text-primary mb-0">Rp. 149.000</p>
</div>
</div>
</div>
<!-- Celana 8 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/pleatedpants.jpg" class="card-img-top img-fluid hover-zoom" alt="Pleated Pants">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Pleated Pants</h6>
<p class="small mb-1">Detail pleats manis yang memberi kesan chic.</p>
<p class="fw-semibold text-primary mb-0">Rp. 99.000</p>
</div>
</div>
</div>
<!-- Celana 9 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/irispants.jpg" class="card-img-top img-fluid hover-zoom" alt="Iris Pants">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Iris Pants</h6>
<p class="small mb-1">Tampilan santai namun tetap fashionable.</p>
<p class="fw-semibold text-primary mb-0">Rp. 120.000</p>
</div>
</div>
</div>
<!-- Celana 10 -->
<div class="col-6 col-sm-4 col-md-2">
<div class="card card-hover border-0 shadow-sm h-100">
<div class="overflow-hidden rounded-top">
<img src="assets/img/scubapants.jpg" class="card-img-top img-fluid hover-zoom" alt="Scuba Pants">
</div>
<div class="card-body p-2">
<h6 class="card-title mb-1">Scuba Pants</h6>
<p class="small mb-1">Celana scuba elastis dan nyaman untuk aktivitas harian.</p>
<p class="fw-semibold text-primary mb-0">Rp. 99.000</p>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Tambahkan tab-pane lainnya seperti rok, celana, dll dengan class "fade" tanpa "show active" -->
@endif
@endforeach
</div>
</div>
</section>
<style>
.nav-pills .nav-link.active {
background-color: #4caf50 !important; /* Bootstrap 'success' green */
color: #fff !important;
}
{{-- Modal Detail --}}
<div class="modal fade" id="detailModal" tabindex="-1" aria-labelledby="detailModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title fw-bold" id="detailModalLabel">Detail Pakaian</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Tutup"></button>
</div>
<div class="modal-body">
<div class="row g-3">
<div class="col-md-5">
<img id="modal-img" src="" class="img-fluid rounded shadow" alt="Gambar Pakaian">
</div>
<div class="col-md-7">
<h5 id="modal-nama" class="fw-semibold mb-2"></h5>
<p id="modal-harga" class="text-danger fw-bold fs-5 mb-2"></p>
<p id="modal-deskripsi" class="text-muted"></p>
</div>
</div>
</div>
</div>
</div>
</div>
.nav-pills .nav-link {
color: #000; /* Warna teks normal */
}
{{-- Script filter kategori --}}
<script>
document.querySelectorAll('.filter-btn').forEach(button => {
button.addEventListener('click', () => {
const kategori = button.getAttribute('data-kategori');
document.querySelectorAll('.filter-btn').forEach(btn => btn.classList.remove('active'));
button.classList.add('active');
document.querySelectorAll('.pakaian-item').forEach(item => item.style.display = 'none');
if (kategori === 'all') {
document.querySelectorAll('.pakaian-item').forEach(item => item.style.display = 'block');
} else {
document.querySelectorAll(`.kategori-${kategori}`).forEach(item => item.style.display = 'block');
}
});
});
.card-hover {
transition: transform 0.3s ease, box-shadow 0.3s ease;
border-radius: 1rem;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
}
.card-hover:hover {
transform: translateY(-5px) scale(1.02);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
}
.hover-zoom {
transition: transform 0.4s ease;
}
.card-hover:hover .hover-zoom {
transform: scale(1.1);
}
</style>
function showDetailModal(card) {
const nama = card.getAttribute('data-nama');
const img = card.getAttribute('data-img');
const harga = card.getAttribute('data-harga');
const deskripsi = card.getAttribute('data-deskripsi') || 'Tidak ada deskripsi.';
document.getElementById('modal-nama').textContent = nama;
document.getElementById('modal-img').src = img || '';
document.getElementById('modal-harga').textContent = harga;
document.getElementById('modal-deskripsi').textContent = deskripsi;
const modal = new bootstrap.Modal(document.getElementById('detailModal'));
modal.show();
}
</script>

View File

@ -0,0 +1,447 @@
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hasil Rekomendasi Pakaian</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #1a4d3a 0%, #0d2818 100%);
min-height: 100vh;
padding: 20px 0;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
.header {
text-align: center;
margin-bottom: 40px;
color: white;
}
.header h1 {
font-size: 2.5rem;
font-weight: 700;
margin-bottom: 10px;
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
}
.header p {
font-size: 1.1rem;
opacity: 0.9;
}
.back-button {
display: inline-flex;
align-items: center;
gap: 8px;
background: rgba(255,255,255,0.2);
color: white;
text-decoration: none;
padding: 12px 24px;
border-radius: 25px;
margin-bottom: 30px;
transition: all 0.3s ease;
backdrop-filter: blur(10px);
border: 1px solid rgba(255,255,255,0.3);
}
.back-button:hover {
background: rgba(255,255,255,0.3);
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(0,0,0,0.2);
}
.results-summary {
background: rgba(255,255,255,0.95);
border-radius: 15px;
padding: 20px;
margin-bottom: 30px;
backdrop-filter: blur(10px);
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
}
.summary-text {
color: #4a5568;
font-size: 1.1rem;
text-align: center;
}
.summary-text i {
color: #2d5a3d;
margin-right: 8px;
}
.alert {
background: linear-gradient(135deg, #2d5a3d 0%, #1a4d3a 100%);
color: white;
padding: 30px;
border-radius: 15px;
text-align: center;
font-size: 1.2rem;
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
margin: 40px 0;
}
.alert i {
font-size: 3rem;
margin-bottom: 15px;
display: block;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
gap: 25px;
margin-top: 30px;
}
.card {
background: white;
border-radius: 20px;
overflow: hidden;
box-shadow: 0 15px 35px rgba(0,0,0,0.1);
transition: all 0.3s ease;
position: relative;
}
.card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(90deg, #2d5a3d, #1a4d3a);
}
.card:hover {
transform: translateY(-10px);
box-shadow: 0 25px 50px rgba(0,0,0,0.2);
}
.card-rank {
position: absolute;
top: 15px;
left: 15px;
background: linear-gradient(135deg, #2d5a3d, #1a4d3a);
color: white;
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 1.1rem;
z-index: 2;
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
}
.card-img {
width: 100%;
height: 250px;
object-fit: cover;
transition: transform 0.3s ease;
}
.card:hover .card-img {
transform: scale(1.05);
}
.card-body {
padding: 25px;
}
.card-title {
font-size: 1.4rem;
font-weight: 700;
color: #2d3748;
margin-bottom: 15px;
line-height: 1.3;
}
.card-info {
display: flex;
flex-direction: column;
gap: 12px;
margin-bottom: 20px;
}
.info-item {
display: flex;
align-items: center;
gap: 10px;
color: #4a5568;
font-size: 0.95rem;
}
.info-item i {
width: 20px;
color: #2d5a3d;
}
.price {
font-size: 1.3rem;
font-weight: 700;
color: #2d5a3d;
}
.score-container {
background: linear-gradient(135deg, #2d5a3d 0%, #1a4d3a 100%);
color: white;
padding: 15px;
border-radius: 12px;
text-align: center;
margin-bottom: 20px;
}
.score-label {
font-size: 0.9rem;
opacity: 0.9;
margin-bottom: 5px;
}
.score-value {
font-size: 1.8rem;
font-weight: 700;
}
.score-stars {
margin-top: 8px;
}
.star {
color: #ffd700;
font-size: 1.2rem;
margin: 0 2px;
}
.star.empty {
color: rgba(255,255,255,0.3);
}
.clothing-type {
background: #e8f5e8;
color: #2d5a3d;
padding: 6px 12px;
border-radius: 20px;
font-size: 0.85rem;
font-weight: 600;
display: inline-block;
margin-bottom: 10px;
}
.recommendation-badge {
position: absolute;
top: 15px;
right: 15px;
background: #2d5a3d;
color: white;
padding: 6px 12px;
border-radius: 15px;
font-size: 0.8rem;
font-weight: 600;
z-index: 2;
}
.top-choice {
background: linear-gradient(135deg, #2d5a3d 0%, #0d2818 100%);
}
@media (max-width: 768px) {
.grid {
grid-template-columns: 1fr;
gap: 20px;
}
.header h1 {
font-size: 2rem;
}
.card-rank {
width: 35px;
height: 35px;
font-size: 1rem;
}
}
.fade-in {
animation: fadeInUp 0.6s ease forwards;
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
</style>
</head>
<body>
<div class="container">
<a href="{{ url()->previous() }}" class="back-button">
<i class="fas fa-arrow-left"></i>
Kembali ke Pencarian
</a>
<div class="header">
<h1>Top 3 Rekomendasi Pakaian</h1>
<p>Temukan 3 pakaian terbaik yang sesuai dengan preferensi Anda</p>
</div>
@if (isset($message) || (isset($recommendations) && $recommendations->isEmpty()) || (isset($rekomendasi) && $rekomendasi->isEmpty()))
<div class="alert">
<i class="fas fa-search"></i>
<div>
{{ $message ?? 'Tidak ada pakaian yang cocok dengan preferensi Anda.' }}
</div>
<p style="margin-top: 15px; font-size: 1rem; opacity: 0.9;">
Coba ubah kriteria pencarian atau pilih opsi yang lebih fleksibel.
</p>
</div>
@else
@php
// Support both variable names for backward compatibility
$results = $recommendations ?? $rekomendasi ?? collect([]);
// Limit to top 3 recommendations
$top3Results = $results->take(3);
@endphp
<div class="results-summary">
<div class="summary-text">
<i class="fas fa-check-circle"></i>
Menampilkan <strong>3 pakaian terbaik</strong> dari {{ $results->count() }} hasil yang ditemukan
</div>
</div>
<div class="grid">
@foreach ($top3Results as $index => $item)
@php
$rank = $index + 1;
$clothing = $item['pakaian'];
$score = $item['score'];
$clothingType = $item['jenis_pakaian'] ?? 'Lainnya';
// Calculate star rating based on score (0-1 scale to 0-5 stars)
$maxScore = $results->max('score');
$normalizedScore = $maxScore > 0 ? ($score / $maxScore) * 5 : 0;
$fullStars = floor($normalizedScore);
$hasHalfStar = ($normalizedScore - $fullStars) >= 0.5;
@endphp
<div class="card fade-in" style="animation-delay: {{ $index * 0.1 }}s">
<div class="card-rank">{{ $rank }}</div>
@if ($rank == 1)
<div class="recommendation-badge top-choice">
<i class="fas fa-crown"></i> Pilihan Terbaik
</div>
@else
<div class="recommendation-badge">
<i class="fas fa-star"></i> Top {{ $rank }}
</div>
@endif
@if ($clothing->img && file_exists(public_path('storage/' . $clothing->img)))
<img src="{{ asset('storage/' . $clothing->img) }}"
class="card-img"
alt="Gambar {{ $clothing->nama_pakaian ?? $clothing->nama }}"
onerror="this.src='{{ asset('images/no-image.jpg') }}'">
@else
<div class="card-img" style="background: linear-gradient(135deg, #f0f0f0, #e0e0e0); display: flex; align-items: center; justify-content: center; color: #999;">
<i class="fas fa-tshirt" style="font-size: 3rem;"></i>
</div>
@endif
<div class="card-body">
<div class="clothing-type">{{ $clothingType }}</div>
<div class="card-title">{{ $clothing->nama_pakaian ?? $clothing->nama }}</div>
<div class="card-info">
<div class="info-item">
<i class="fas fa-tag"></i>
<span class="price">Rp {{ number_format($clothing->harga ?? 0, 0, ',', '.') }}</span>
</div>
@if (isset($clothing->merek))
<div class="info-item">
<i class="fas fa-copyright"></i>
<span>{{ $clothing->merek }}</span>
</div>
@endif
@if (isset($clothing->ukuran))
<div class="info-item">
<i class="fas fa-ruler"></i>
<span>Ukuran: {{ $clothing->ukuran }}</span>
</div>
@endif
</div>
<div class="score-container">
<div class="score-label">Skor Kecocokan</div>
<div class="score-value">{{ number_format($score, 3) }}</div>
<div class="score-stars">
@for ($i = 1; $i <= 5; $i++)
@if ($i <= $fullStars)
<i class="fas fa-star star"></i>
@elseif ($i == $fullStars + 1 && $hasHalfStar)
<i class="fas fa-star-half-alt star"></i>
@else
<i class="far fa-star star empty"></i>
@endif
@endfor
</div>
</div>
</div>
</div>
@endforeach
</div>
@endif
</div>
<script>
// Add smooth animations and interactions
document.addEventListener('DOMContentLoaded', function() {
// Animate cards on scroll
const observerOptions = {
threshold: 0.1,
rootMargin: '0px 0px -50px 0px'
};
const observer = new IntersectionObserver(function(entries) {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.style.opacity = '1';
entry.target.style.transform = 'translateY(0)';
}
});
}, observerOptions);
// Observe all cards
document.querySelectorAll('.card').forEach(card => {
observer.observe(card);
});
});
</script>
</body>
</html>

View File

@ -154,6 +154,10 @@
<div class="col-md-7 col-lg-6 col-xxl-5 py-6 text-sm-start text-center">
<h1 class="mt-6 mb-sm-4 fw-semi-bold lh-sm fs-4 fs-lg-5 fs-xl-6">Hello! <br class="d-block d-lg-block" />Selamat Datang</h1>
<p class="mb-4 fs-1">Terima kasih telah mengunjungi situs kami! Kami siap membantu anda mencari pakaian yang sesuai dengan gaya dan kebutuhan anda!</p>
<a href="#pilihpakaian" class="btn btn-primary px-4 py-2">
Cari Pakaian
</a>
</div>
</div>
</div>

View File

@ -1,147 +1,67 @@
<section class="py-5" id="pilihpakaian">
<div class="bg-holder d-none d-sm-block" style="background-image:url(assets/img/illustrations/bg.png);background-position:top left;background-size:225px 755px;margin-top:-17.5rem;"></div>
<div class="container my-5">
<form action="{{ route('proses.rekomendasi') }}" method="POST">
<form method="POST" action="{{ route('proses.rekomendasi') }}">
@csrf
<div class="row justify-content-center">
<div class="col-lg-8">
<div class="text-center mb-4">
<h5 class="fw-bold fs-3 fs-lg-5 lh-sm">Pilih Pakaian Anda</h5>
<p class="text-muted">Untuk mendapatkan rekomendasi pakaian yang paling sesuai dengan gaya dan kebutuhan Anda, silakan isi beberapa pertanyaan berikut.</p>
<p class="text-muted">Untuk mendapatkan rekomendasi pakaian yang sesuai dengan preferensi Anda.</p>
</div>
<div class="card shadow-lg border-0 rounded-4">
<div class="card-body p-5 bg-light">
<!-- Progress Bar -->
<div class="progress mb-4">
<div class="progress-bar bg-primary" role="progressbar" style="width: 20%;" id="progressBar"></div>
</div>
<!-- STEP 1 -->
<div class="step active" id="step-1">
<h5 class="fw-bold mb-3">Pilih jenis acara yang akan kamu hadiri...</h5>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="acara1" value="Formal" name="jenis_acara">
<label class="form-check-label" for="acara1">Formal</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="acara2" value="NonFormal" name="jenis_acara">
<label class="form-check-label" for="acara2">Non Formal</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="acara3" value="Casual" name="jenis_acara">
<label class="form-check-label" for="acara3">Casual</label>
</div>
<button type="button" class="btn btn-primary" onclick="nextStep()">Selanjutnya</button>
</div>
@php
$steps = [
'Jenis Pakaian' => $subKriteria['Jenis Pakaian'] ?? [],
'Harga' => $subKriteria['Harga'] ?? [],
'Jenis Acara' => $subKriteria['Jenis Acara'] ?? [],
'Warna Pakaian' => $subKriteria['Warna Pakaian'] ?? [],
'Lokasi Acara' => $subKriteria['Lokasi Acara'] ?? [],
];
<!-- STEP 2 -->
<div class="step" id="step-2">
<h5 class="fw-bold mb-3">Tentukan rentang harga pakaian...</h5>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="harga1" value="80000-100000" name="harga">
<label class="form-check-label" for="harga1">Rp80.000 - 100.000</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="harga2" value="101000-150000" name="harga">
<label class="form-check-label" for="harga2">Rp101.000 - 150.000</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="harga3" value="151000-200000" name="harga">
<label class="form-check-label" for="harga3">Rp151.000 - 200.000</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="harga4" value="201000-300000" name="harga">
<label class="form-check-label" for="harga4">Rp201.000 - 300.000</label>
</div>
<button type="button" class="btn btn-secondary me-2" onclick="prevStep()">Kembali</button>
<button type="button" class="btn btn-primary" onclick="nextStep()">Selanjutnya</button>
</div>
$multiAnswerKriteria = ['Jenis Acara', 'Warna Pakaian', 'Lokasi Acara'];
$stepIndex = 1;
@endphp
<!-- STEP 3 -->
<div class="step" id="step-3">
<h5 class="fw-bold mb-3">Pilih jenis pakaian...</h5>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="pakaian1" value="Dress" name="jenis_pakaian">
<label class="form-check-label" for="pakaian1">Dress</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="pakaian2" value="Blouse" name="jenis_pakaian">
<label class="form-check-label" for="pakaian2">Blouse</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="pakaian3" value="Cardigan" name="jenis_pakaian">
<label class="form-check-label" for="pakaian3">Cardigan</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="pakaian4" value="Rok" name="jenis_pakaian">
<label class="form-check-label" for="pakaian4">Rok</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="pakaian5" value="Celana" name="jenis_pakaian">
<label class="form-check-label" for="pakaian5">Celana</label>
</div>
<button type="button" class="btn btn-secondary me-2" onclick="prevStep()">Kembali</button>
<button type="button" class="btn btn-primary" onclick="nextStep()">Selanjutnya</button>
</div>
@foreach ($steps as $label => $subs)
<div class="step {{ $stepIndex === 1 ? 'active' : '' }}" id="step-{{ $stepIndex }}">
<h5 class="fw-bold mb-3">Pilih {{ strtolower($label) }}:</h5>
<!-- STEP 4 -->
<div class="step" id="step-4">
<h5 class="fw-bold mb-3">Pilih warna pakaian...</h5>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="warna1" value="Dingin" name="warna">
<label class="form-check-label" for="warna1">Warna Dingin</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="warna2" value="Panas" name="warna">
<label class="form-check-label" for="warna2">Warna Panas</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="warna3" value="Netral" name="warna">
<label class="form-check-label" for="warna3">Warna Netral</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="warna4" value="Lembut" name="warna">
<label class="form-check-label" for="warna4">Warna Lembut</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="warna5" value="Pastel" name="warna">
<label class="form-check-label" for="warna5">Warna Pastel</label>
</div>
<button type="button" class="btn btn-secondary me-2" onclick="prevStep()">Kembali</button>
<button type="button" class="btn btn-primary" onclick="nextStep()">Selanjutnya</button>
</div>
@foreach ($subs as $sub)
<div class="form-check mb-2">
@php
$isMultiple = in_array($label, $multiAnswerKriteria);
$inputType = $isMultiple ? 'checkbox' : 'radio';
$nameAttr = $isMultiple ? "sub_kriteria[{$sub->kriteria_id}][]" : "sub_kriteria[{$sub->kriteria_id}]";
@endphp
<input class="form-check-input" type="{{ $inputType }}" id="sub_{{ $sub->id }}"
name="{{ $nameAttr }}" value="{{ $sub->id }}">
<label class="form-check-label" for="sub_{{ $sub->id }}">
{{ $sub->nama_sub }}
</label>
</div>
@endforeach
<!-- STEP 5 -->
<div class="step" id="step-5">
<h5 class="fw-bold mb-3">Pilih kondisi cuaca...</h5>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="cuaca1" value="Cerah" name="cuaca">
<label class="form-check-label" for="cuaca1">Cerah</label>
<div class="mt-4">
@if ($stepIndex > 1)
<button type="button" class="btn btn-secondary me-2" onclick="prevStep()">Kembali</button>
@endif
@if ($stepIndex < count($steps))
<button type="button" class="btn btn-primary" onclick="nextStep()">Selanjutnya</button>
@else
<button type="submit" class="btn btn-success">Lihat Rekomendasi</button>
@endif
</div>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="cuaca2" value="Berawan" name="cuaca">
<label class="form-check-label" for="cuaca2">Berawan</label>
</div>
<button type="button" class="btn btn-secondary me-2" onclick="prevStep()">Kembali</button>
<button type="button" class="btn btn-primary" onclick="nextStep()">Selanjutnya</button>
</div>
<!-- STEP 6 -->
<div class="step" id="step-6">
<h5 class="fw-bold mb-3">Pilih lokasi acara...</h5>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="lokasi1" value="Indoor" name="lokasi">
<label class="form-check-label" for="lokasi1">Indoor</label>
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="radio" id="lokasi2" value="Outdoor" name="lokasi">
<label class="form-check-label" for="lokasi2">Outdoor</label>
</div>
<button type="button" class="btn btn-secondary me-2" onclick="prevStep()">Kembali</button>
<button type="submit" class="btn btn-success">Hasil Rekomendasi</button>
</div>
@php $stepIndex++; @endphp
@endforeach
</div>
</div>
@ -150,9 +70,10 @@
</form>
</div>
<!-- Script Multi-Step -->
<script>
let currentStep = 1;
const totalSteps = 6;
const totalSteps = {{ count($steps) }};
function showStep(step) {
for (let i = 1; i <= totalSteps; i++) {
@ -163,11 +84,11 @@
}
function nextStep() {
const radios = document.querySelectorAll(`#step-${currentStep} input[type="radio"]`);
const isAnswered = Array.from(radios).some(radio => radio.checked);
const currentInputs = document.querySelectorAll(`#step-${currentStep} input`);
const isAnswered = Array.from(currentInputs).some(input => input.checked);
if (!isAnswered) {
alert("Silakan isi pertanyaan ini terlebih dahulu.");
alert("Silakan pilih minimal satu opsi terlebih dahulu.");
return;
}
@ -191,6 +112,4 @@
showStep(currentStep);
</script>
<div id="hasil-rekomendasi" style="margin-top: 20px;"></div>
</section>

View File

@ -1,54 +0,0 @@
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Rekomendasi {{ $jenis }}</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container py-4">
<h1 class="mb-4">Rekomendasi {{ $jenis }}</h1>
@if(isset($skorAkhir) && count($skorAkhir) > 0)
<div class="row">
@foreach($skorAkhir as $index => $item)
<div class="col-md-4 mb-4">
<div class="card">
<div class="card-body">
<h5 class="card-title">
#{{ $index + 1 }} - {{ $item['alternatif']->nama_alternatif ?? 'Produk ' . ($index + 1) }}
</h5>
<p class="card-text">
<strong>Skor: </strong>{{ number_format($item['skor_akhir'] * 100, 1) }}%
</p>
@if(isset($item['alternatif']->harga))
<p class="card-text">
<strong>Harga: </strong>Rp {{ number_format($item['alternatif']->harga, 0, ',', '.') }}
</p>
@endif
@if(isset($item['alternatif']->deskripsi))
<p class="card-text">{{ $item['alternatif']->deskripsi }}</p>
@endif
</div>
</div>
</div>
@endforeach
</div>
@else
<div class="alert alert-info">
<p>Tidak ada rekomendasi {{ strtolower($jenis) }} yang tersedia.</p>
</div>
@endif
<div class="mt-4">
<a href="/" class="btn btn-secondary">Kembali ke Beranda</a>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/js/bootstrap.bundle.min.js"></script>
</body>
</html>

View File

@ -2,7 +2,9 @@
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;
use App\Http\Controllers\PakaianController;
use App\Http\Controllers\RiwayatController;
use App\Http\Controllers\KriteriaController;
use App\Http\Controllers\PenilaianController;
use App\Http\Controllers\Admin\AuthController;
@ -11,6 +13,8 @@ use App\Http\Controllers\Admin\DashboardController;
use App\Http\Controllers\SubKriteriaShowController;
use App\Http\Controllers\Landingpage\HomeController;
use App\Http\Controllers\Admin\ResetPasswordController;
use App\Http\Controllers\Admin\ForgotPasswordController;
use App\Http\Controllers\Admin\ForgotUsernameController;
/*
|--------------------------------------------------------------------------
@ -25,32 +29,28 @@ use App\Http\Controllers\Admin\ResetPasswordController;
Route::get('/', [HomeController::class, 'index'])->name('home');
Route::post('/proses-rekomendasi', [HomeController::class, 'simpankuisionerdanrekomendasi'])->name('proses.rekomendasi');
Route::post('/proses-rekomendasi', [HomeController::class, 'prosesRekomendasi'])->name('proses.rekomendasi');
// // Jika user sudah login, arahkan ke dashboard
// Route::get('/dashboard', function () {
// if (!Auth::check()) {
// return redirect()->route('login');
// }
// return view('admin.pages.dashboard.index');
// })->name('dashboard');
// Login & Register Routes
Route::get('/login', [AuthController::class, 'showLogin'])->name('login');
Route::post('/login', [AuthController::class, 'login']);
// Menampilkan form lupa password
Route::get('/forgot-password', [\App\Http\Controllers\Admin\ForgotPasswordController::class, 'showForm'])->name('forgot.password.form');
// === Forgot Username (tanpa prefix 'admin') ===
Route::get('/forgot-username', [ForgotUsernameController::class, 'showForm'])
->name('forgot.username.form');
Route::post('/forgot-username', [ForgotUsernameController::class, 'sendUsername'])
->name('forgot.username.send');
// Mengirim email reset link
Route::post('/forgot-password', [\App\Http\Controllers\Admin\ForgotPasswordController::class, 'sendResetLink'])->name('forgot.password.send');
// Menampilkan form reset password (dari email)
Route::get('/reset-password/{token}', [ResetPasswordController::class, 'showResetForm'])->name('password.reset');
// Menyimpan password baru
Route::post('/reset-password', [ResetPasswordController::class, 'reset'])->name('password.update');
// === Forgot Password (tanpa prefix 'admin') ===
Route::get('/forgot-password', [ForgotPasswordController::class, 'showForm'])
->name('forgot.password.form');
Route::post('/forgot-password', [ForgotPasswordController::class, 'sendResetLink'])
->name('forgot.password.send');
Route::get('/reset-password/{token}', [ResetPasswordController::class, 'showResetForm'])
->name('password.reset');
Route::post('/reset-password', [ResetPasswordController::class, 'reset'])
->name('password.update');
// Logout
Route::post('/logout', function () {
@ -64,9 +64,10 @@ Route::prefix('admin')->middleware(['auth'])->as('admin.')->group(function () {
Route::resource('kriteria', KriteriaController::class);
Route::resource('subkriteria', SubkriteriaController::class);
Route::get('kriteria/subkriteria/{nama_kriteria}', [SubKriteriaShowController::class, 'indexShow'])->name('kriteria.subkriteria.index');
Route::resource('pakaian', PakaianController::class);
Route::resource('penilaian', PenilaianController::class);
Route::resource('user', UserController::class);
});
// // Kriteria